HOWTO · Matplotlib
如何在 Matplotlib 中向子圖新增標題
我們可以使用 Axes.set_title()、Axes.title.set_text() 或 pyplot 的目前座標軸(plt.gca())為 Matplotlib 中的子圖新增標題。
本頁內容
若要為每個子圖設定個別標題,請對應的座標軸呼叫 Axes.set_title()。同時建立多個圖表時,這是最清楚的做法,因為每個標題都會與它所描述的座標軸保持關聯。子圖標題只屬於一個座標軸;若要用一個標題描述整張圖,請改用圖形層級的標題,例如 fig.suptitle()。
使用 Axes.set_title() 為子圖加上標題
設定 squeeze=False 時,plt.subplots() 會傳回一個圖形物件和一個座標軸陣列。下方範例繪製四組資料,將每個座標軸與描述性標籤配對,並在顯示圖形前調整版面。這可確保 axes 在 2×2 網格、單列(1×N)、單欄(N×1)或單一子圖(1×1)時都維持二維。若要使用不同的網格尺寸,請調整 plt.subplots() 的引數,並為每個座標軸提供一個標題。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
series = [np.sin(x), np.cos(x), np.sin(2 * x), np.cos(2 * x)]
titles = ["Sine", "Cosine", "Sine, double frequency", "Cosine, double frequency"]
fig, axes = plt.subplots(2, 2, figsize=(8, 5), squeeze=False)
for ax, y, title in zip(axes.flat, series, titles):
ax.plot(x, y)
ax.set_title(title)
fig.tight_layout()
plt.show()
由於 squeeze=False 即使在 1×1 網格中也會讓座標軸維持為二維陣列,因此 axes.flat 能以一致的方式遍歷四種網格形狀:2×2、1×N、N×1 和 1×1。zip() 會依序將每個座標軸和資料系列與一個標題配對,因此這些集合必須維持相同的順序與長度。
label 引數是顯示在座標軸上方的文字。你也可以傳入 fontsize 或 loc 等選項,控制標題的外觀與位置。標題較長時請盡量精簡;如果相鄰標題或標籤的空間不足,請在顯示前放大圖形或調整間距。tight_layout() 是實用的起點,不過裝飾元素較多時,可能還需要額外調整間距。
使用 Axes.title.set_text() 設定子圖標題
座標軸也會以文字物件的形式提供其標題。建立座標軸後,可以使用 Axes.title.set_text() 設定或更新該文字。如果程式已保留標題物件的參照,或之後需要更改標題文字,這種方式會很方便。初次設定圖表時,Axes.set_title() 通常更直接,也能清楚表達呼叫位置正在設定座標軸標題。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
fig, axes = plt.subplots(1, 2, figsize=(8, 3.5), squeeze=False)
axes[0, 0].plot(x, np.sin(x))
axes[0, 1].plot(x, np.cos(x))
axes[0, 0].title.set_text("Sine")
axes[0, 1].title.set_text("Cosine")
fig.tight_layout()
plt.show()
例如,建立名為 ax 的座標軸後,呼叫 ax.title.set_text("Updated title")。這會更新該座標軸的標題,不會替圖中的每個子圖設定標題。若有多個座標軸,請明確選取要更新的座標軸,或像第一個範例那樣,逐一配對座標軸與相應的字串。這兩種 API 都是設定座標軸標題;同一項操作選用其中一種即可,避免重複設定相同標題。
使用 pyplot 的目前座標軸設定子圖標題
使用 pyplot 的狀態式介面時,plt.gca() 會傳回目前的座標軸。你可以呼叫 plt.gca().set_title("Title") 設定標題;等效的文字物件寫法是 plt.gca().title.set_text("Title")。括號不可省略:gca() 是函式呼叫,用來取得目前的座標軸。這兩種寫法都只會影響當下的座標軸,因此適合一次繪製一個座標軸的情況。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
series = [np.sin(x), np.cos(x), np.sin(2 * x), np.cos(2 * x)]
titles = ["Sine", "Cosine", "Sine, double frequency", "Cosine, double frequency"]
plt.figure(figsize=(8, 5))
for position, (y, title) in enumerate(zip(series, titles), start=1):
plt.subplot(2, 2, position)
plt.plot(x, y)
plt.gca().set_title(title)
plt.tight_layout()
plt.show()
若要處理網格,請先選取各個子圖,再設定標題。例如,plt.subplot(2, 2, position) 會選取第 1 到第 4 個位置之一,接著 plt.gca().set_title(title) 就會將標題套用到所選的座標軸。如果你使用 fig, axes = plt.subplots(...) 建立網格,直接使用傳回的座標軸參照通常更容易理解,也較不受 pyplot 目前狀態影響。
請在呼叫 plt.show() 前完成圖形設定。尤其要在顯示前呼叫 plt.tight_layout(),讓版面配置能將子圖標題納入考量。
修正重疊或被裁切的標題與遺漏的標題
標題會在座標軸上方置中,因此較長的標題可能比座標軸本身還寬。以本節範例使用的兩個標題、在尺寸為 (8, 3.5) 的圖形上實測,未套用任何版面調整時,量得的兩個標題方框重疊了 15 像素,第一個標題的結尾會侵入下一個標題的開頭。呼叫 fig.tight_layout() 後兩者會分開(同樣量測下間隔為 39 像素),但 tight_layout() 只是重新分配子圖之間的空間,並不會縮小標題文字。在該圖形尺寸下,第二個標題會超出圖形右側邊界 11 像素,在繪製結果中被裁切。完整的修正方式是給標題留出空間:如本範例保留 tight_layout() 並加寬圖形,或縮短標題。在原尺寸下將標題的 fontsize 降為 11,也能讓兩個標題完整落在圖形之內(已實測)。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
fig, axes = plt.subplots(1, 2, figsize=(9, 3.5), squeeze=False)
axes[0, 0].plot(x, np.sin(x))
axes[0, 1].plot(x, np.cos(x))
axes[0, 0].set_title("Sine wave measured at the first sensor")
axes[0, 1].set_title("Cosine wave measured at the second sensor")
fig.tight_layout()
plt.show()
在尺寸 (9, 3.5) 下,兩個標題都完整落在圖形之內,彼此留有間隔,沒有任何文字被切掉。標題遺漏則是靜默失敗:本文的迴圈透過 zip() 將座標軸與標題配對,而 zip() 會在較短的序列處停止,且不拋出任何錯誤。若只為 2×2 網格的四個子圖提供三個標題,第四個座標軸的標題就會是空的(用 ax.get_title() 讀回會得到空字串),而且沒有任何警告。當某個子圖看起來沒有標題時,先清點標題與座標軸的數量,再檢查標題設定呼叫本身。