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()

使用 Axes.set_title() 加上標題的 2×2 子圖網格:Sine、Cosine、Sine double frequency 與 Cosine double frequency,各標題置中於其曲線上方。

由於 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()

並排的兩個子圖,標題以 Axes.title.set_text() 設定:正弦曲線上方的 Sine 與餘弦曲線上方的 Cosine。

例如,建立名為 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() 與 plt.gca().set_title() 在迴圈中建立的相同 2×2 正弦與餘弦曲線網格,每個子圖上方各有一個標題。

若要處理網格,請先選取各個子圖,再設定標題。例如,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()

帶有長標題 Sine wave measured at the first sensor 與 Cosine wave measured at the second sensor 的兩個子圖,在加寬圖形並套用 tight_layout() 後完整可見且彼此分開。

在尺寸 (9, 3.5) 下,兩個標題都完整落在圖形之內,彼此留有間隔,沒有任何文字被切掉。標題遺漏則是靜默失敗:本文的迴圈透過 zip() 將座標軸與標題配對,而 zip() 會在較短的序列處停止,且不拋出任何錯誤。若只為 2×2 網格的四個子圖提供三個標題,第四個座標軸的標題就會是空的(用 ax.get_title() 讀回會得到空字串),而且沒有任何警告。當某個子圖看起來沒有標題時,先清點標題與座標軸的數量,再檢查標題設定呼叫本身。