本文示例代碼、數據已上傳至我的
Github
倉庫https://github.com/CNFeffery/DataScienceStudyNotes
1 簡介
在進行數據可視化時我們常常需要在可視化作品上進行一些文字標注,譬如對散點圖我們可以將每個散點對應的屬性信息標注在每個散點旁邊,但隨着散點量的增多,或圖像上的某個區域聚集了較多的散點時,疊加上的文字標注會擠在一起相互疊置,出現如圖1所示的情況:

出現這種情況非常影響數據可視化作品的呈現效果,而我們下面要介紹的adjustText
是一個輔助matplotlib
所繪制的圖像自動調整文字位置以緩解遮擋現象的庫,其靈感來源於R
中非常著名的輔助ggplot2
解決文字遮擋問題的ggrepel
:

它通過算法迭代,在一輪輪的迭代過程中逐漸消除文字遮擋現象:

下面我們就來學習如何使用adjustText
解決matplotlib
圖像文字遮擋問題。
2 使用adjustText解決文字遮擋問題
2.1 從一個簡單的例子出發
使用pip install adjustText
或conda install -c conda-forge adjusttext
來安裝adjustText
。安裝成功之后,首先生成隨機示例數據以方便之后的演示:
import matplotlib.pyplot as plt
from adjustText import adjust_text
import numpy as np
#解決中文顯示問題
plt.rcParams['font.sans-serif'] = ['SimHei']
seed = np.random.RandomState(42) # 固定隨機數水平
x, y = seed.uniform(0, 1, [2, 100]) # 產生固定的均勻分布隨機數
texts = [f'文字{i}' for i in range(x.__len__())]
接着我們先不使用adjustText
調整圖像,直接繪制出原始的散點+文字標簽:
fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y, c='SeaGreen', s=10) # 繪制散點
# 繪制所有點對應的文字標簽
for x_, y_, text in zip(x, y, texts):
plt.text(x_, y_, text, fontsize=12)
# 美觀起見隱藏頂部與右側邊框線
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
fig.savefig('圖4.png', dpi=300, bbox_inches='tight', pad_inches=0) # 保存圖像

可以看到,在通常的情況下,散點聚集的區域內文字標簽非常容易重疊在一起,接下來我們使用adjustText
的基礎功能來消除文字重疊現象:

這時可以看到與圖4相比,圖5中的所有文字都沒有出現彼此重疊現象,adjustText
幫助我們自動微調了文字的擺放位置,並且距離原始散點偏移較大的文字還貼心的加上了連接線,至此,我們就初探了adjustText
的強大功能,接下來我們來學習adjustText
的更多功能。
2.2 adjust_text的用法
adjustText
中的核心功能都通過調用函數adjust_text
來實現,其核心參數如下:
texts:List型,每個元素都是表示單個文字標簽對應的
matplotlib.text.Text
對象ax:繪制文字標簽的目標axe對象,默認為最近一次的axe對象
lim:int型,控制迭代調整文本標簽位置的次數,默認為500次
precision:float型,用於決定迭代停止的精度,默認為0.01,即所有標簽相互遮擋部分的長和寬占所有標簽自身長寬之和的比例,
addjust_text
會在精度達到precision和迭代次數超過lim這兩個條件中至少有一個滿足時停止迭代only_move:字典型,用於指定文本標簽與不同對象發生遮擋時的位移策略,鍵有
'points'
、'text'
和'objects'
,對應的值可選'xy'
、'x'
、'y'
,分別代表豎直和水平方向均調整、只調整水平方向以及只調整豎直方向arrowprops:字典型,用於設置偏移后的文字標簽與原始位置之間的連線樣式,下文會作具體演示
save_steps:bool型,用於決定是否保存記錄迭代過程中各輪的幀圖像,默認為False
save_prefix:str型,當save_steps設置為True時,用於指定中間幀保存的路徑,默認為'',即當前工作路徑
下面我們來演示一下這些參數的使用效果,首先我們來看看only_move
參數的效果,在圖6的基礎上,我們設置only_move={'text': 'x'}
,即當文字出現遮擋時,只在水平方向上進行偏移,這里將save_steps設置為True以直觀地查看偏移過程:
fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y, c='SeaGreen', s=10) # 繪制散點
# 使用adjustText修正文字重疊現象
new_texts = [plt.text(x_, y_, text, fontsize=12) for x_, y_, text in zip(x, y, texts)]
adjust_text(new_texts,
only_move={'text': 'x'},
arrowprops=dict(arrowstyle='-', color='grey'),
save_steps=True)
# 美觀起見隱藏頂部與右側邊框線
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

可以看到在整個迭代微調的過程中,每個標簽只在水平方向發生位移,你可以根據自己作圖的實際需要靈活調整這里的平移策略。接下來我們來看看arrowprops
對可視化結果的影響,在之前的例子里我們設置了arrowprops={arrowstyle='-', color='grey'}
,其中arrowstyle
用於設定連線的線型,color
不用多說,接下來我們添加參數lw
用於控制線的寬度,並對線型與顏色進行修改:
fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y, c='SeaGreen', s=10) # 繪制散點
# 使用adjustText修正文字重疊現象
new_texts = [plt.text(x_, y_, text, fontsize=12) for x_, y_, text in zip(x, y, texts)]
adjust_text(new_texts,
arrowprops=dict(arrowstyle='->',
color='red',
lw=1))
# 美觀起見隱藏頂部與右側邊框線
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
fig.savefig('圖7.png', dpi=300, bbox_inches='tight', pad_inches=0) # 保存圖像
這時連線隨着我們自定義的設置改變到相應的樣式:

有關adjustText
的更多參數設置信息和示例可以去官方文檔(https://adjusttext.readthedocs.io/en/latest/ )查看。
以上就是本文的全部內容,如有疑問歡迎在評論區與我們討論。