1. 程式人生 > >(資料科學學習手札87)利用adjustText解決matplotlib文字標籤遮擋問題

(資料科學學習手札87)利用adjustText解決matplotlib文字標籤遮擋問題

> 本文示例程式碼、資料已上傳至我的`Github`倉庫[https://github.com/CNFeffery/DataScienceStudyNotes](https://github.com/CNFeffery/DataScienceStudyNotes) # 1 簡介   在進行資料視覺化時我們常常需要在視覺化作品上進行一些**文字標註**,譬如對散點圖我們可以將每個散點對應的屬性資訊標註在每個散點旁邊,但隨著散點量的增多,或影象上的某個區域**聚集**了較多的散點時,疊加上的文字標註會擠在一起相互疊置,出現如圖1所示的情況:
圖1
  出現這種情況非常影響資料視覺化作品的呈現效果,而我們下面要介紹的`adjustText`是一個輔助`matplotlib`所繪製的影象自動調整文字位置以緩解遮擋現象的庫,其靈感來源於`R`中非常著名的輔助`ggplot2`解決文字遮擋問題的`ggrepel`:
圖2
  它通過演算法迭代,在一輪輪的迭代過程中逐漸消除文字遮擋現象:
圖3
  下面我們就來學習如何使用`adjustText`解決`matplotlib`影象文字遮擋問題。 # 2 使用adjustText解決文字遮擋問題 ## 2.1 從一個簡單的例子出發   使用`pip install adjustText`或`conda install -c conda-forge adjusttext `來安裝`adjustText`。安裝成功之後,首先生成隨機示例資料以方便之後的演示: ```Python 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`調整影象,直接繪製出原始的**散點**+**文字標籤**: ```Python 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) # 儲存影象 ```
圖4
  可以看到,在通常的情況下,散點聚集的區域內文字標籤非常容易重疊在一起,接下來我們使用`adjustText`的基礎功能來消除文字重疊現象:
圖5
  這時可以看到與圖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以直觀地檢視偏移過程: ```Python 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) ```
圖6
  可以看到在整個迭代微調的過程中,每個標籤只在水平方向發生位移,你可以根據自己作圖的實際需要靈活調整這裡的平移策略。接下來我們來看看`arrowprops`對視覺化結果的影響,在之前的例子裡我們設定了`arrowprops={arrowstyle='-', color='grey'}`,其中`arrowstyle`用於設定連線的線型,`color`不用多說,接下來我們新增引數`lw`用於控制線的寬度,並對線型與顏色進行修改: ```Python 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) # 儲存影象 ```   這時連線隨著我們自定義的設定改變到相應的樣式:
圖7
  有關`adjustText`的更多引數設定資訊和示例可以去官方文件(https://adjusttext.readthedocs.io/en/latest/ )檢視。   以上就是本文的全部內容,如有疑問歡迎在評論區與我們