HOWTO · Matplotlib

如何在 Matplotlib 中繪製水平線與垂直線

本教程介紹如何使用 axhline 和 axvline、hlines 和 vlines 以及 axhspan 和 axvspan 著色函數在 Matplotlib 中繪製水平線與垂直線。

本頁內容

要在 Matplotlib 中繪製水平和垂直參考線,當線段應跨越座標軸的一定比例時,選擇 axhline 和 axvline;當線段的端點應固定為資料值時,選擇 hlines 和 vlines。當目標是突顯一整條區域而不是單個值時,axhspan 和 axvspan 會為兩個位置之間的區域著色。每個範例都會將圖形儲存到暫存 PNG 檔案,並列印它所建立物件的座標,因此你可以確切確認 Matplotlib 將線條或區域放置在哪裡。

使用 axhline 和 axvline 在 Matplotlib 中繪製水平線與垂直線

使用 axhline 繪製水平線

axhline(y=...) 在資料座標的 y 處放置一條水平線。它的 xmin 和 xmax 參數將左端和右端設定為座標軸寬度的比例,通常從 0 到 1;它們不是 x 資料值。例如,xmin=0.1 和 xmax=0.9 會在兩端各留出等於座標軸寬度 10% 的邊距。

import tempfile
from pathlib import Path

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
line = ax.axhline(y=2, xmin=0.1, xmax=0.9, color="tab:red")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
print("x extent (axes fraction):", line.get_xdata())
print("y position (data):", line.get_ydata())
with tempfile.TemporaryDirectory() as directory:
    fig.savefig(Path(directory) / "plot.png")
plt.close(fig)

輸出:

x extent (axes fraction): [0.1, 0.9]
y position (data): [2, 2]

列印的值證實了這種劃分:位置是資料值 2,而範圍則以座標軸比例 0.1 和 0.9 儲存。

Matplotlib 圖表,其中一條位於 y = 2 的紅色水平線跨越座標軸寬度的 10% 到 90%

線條保持在資料值 y=2 處。如果你變更 x 的範圍,它的兩端仍然跨越座標軸寬度的 10% 到 90%,因此線段會隨顯示範圍而調整。

使用 axvline 繪製垂直線

axvline(x=...) 在資料座標的 x 處放置一條垂直線。它的 ymin 和 ymax 參數將底端和頂端設定為座標軸高度的比例,通常從 0 到 1。例如,ymin=0.1 和 ymax=0.9 會在兩端各留出等於座標軸高度 10% 的邊距。

import tempfile
from pathlib import Path

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
line = ax.axvline(x=2, ymin=0.1, ymax=0.9, color="tab:green")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
print("x position (data):", line.get_xdata())
print("y extent (axes fraction):", line.get_ydata())
with tempfile.TemporaryDirectory() as directory:
    fig.savefig(Path(directory) / "plot.png")
plt.close(fig)

輸出:

x position (data): [2, 2]
y extent (axes fraction): [0.1, 0.9]

這裡儲存的值正好相反:位置是資料值 2,範圍是座標軸比例對。

Matplotlib 圖表,其中一條位於 x = 2 的綠色垂直線跨越座標軸高度的 10% 到 90%

線條保持在資料值 x=2 處。如果你變更 y 的範圍,它的兩端仍然跨越座標軸高度的 10% 到 90%。因此,每個 ax*line 函數都將資料座標中的位置與按座標軸比例測量的範圍結合在一起。

使用 hlines 和 vlines 在 Matplotlib 中繪製水平線與垂直線

當線條的位置和兩個端點都應使用資料座標時,使用 hlines 和 vlines。對於 hlines,y 給出高度,xmin 和 xmax 給出端點的 x 值。對於 vlines,x 給出位置,ymin 和 ymax 給出端點的 y 值。變更繪圖範圍會改變哪些部分可見,而線條在資料座標中的位置和端點保持不變。這兩個函數都傳回一個 LineCollection,並接受常用的樣式參數,因此本範例還設定了虛線和點線樣式,並透過 label 參數新增了圖例。

import tempfile
from pathlib import Path

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
horizontal = ax.hlines(y=2, xmin=1, xmax=3, color="tab:red", linestyles="--",
                       linewidth=2, label="horizontal segment")
vertical = ax.vlines(x=2, ymin=1, ymax=3, color="tab:green", linestyles=":",
                     linewidth=2, label="vertical segment")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
ax.legend(loc="upper left")
print("horizontal segment endpoints:", horizontal.get_segments()[0].tolist())
print("vertical segment endpoints:", vertical.get_segments()[0].tolist())
with tempfile.TemporaryDirectory() as directory:
    fig.savefig(Path(directory) / "plot.png")
plt.close(fig)

輸出:

horizontal segment endpoints: [[1.0, 2.0], [3.0, 2.0]]
vertical segment endpoints: [[2.0, 1.0], [2.0, 3.0]]

列印的端點是純粹的資料座標:水平線段從 (1, 2) 到 (3, 2),垂直線段從 (2, 1) 到 (2, 3)。

Matplotlib 圖表,其中一條位於 y = 2、從 x = 1 到 x = 3 的紅色虛線水平線段和一條位於 x = 2、從 y = 1 到 y = 3 的綠色點線垂直線段,由圖例標識

由於所有四個端點都使用資料座標,縮放或變更範圍會改變每個線段的可見部分,而不是調整其端點以符合座標軸的比例。

使用 axhspan 和 axvspan 在 Matplotlib 中為區域著色

當單條線不夠時,可以改為對兩個值之間的區域著色。axhspan(ymin, ymax) 在座標軸的整個寬度上填滿兩個 y 資料值之間的水平區域,axvspan(xmin, xmax) 在整個高度上填滿兩個 x 資料值之間的垂直區域。使用它們可以在資料背後標記可接受的範圍、目標區域或關注的時間段。這兩個函數都傳回一個 Rectangle 補片。

import tempfile
from pathlib import Path

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
band_y = ax.axhspan(ymin=1.5, ymax=2.5, color="tab:orange", alpha=0.3,
                    label="y between 1.5 and 2.5")
band_x = ax.axvspan(xmin=1.5, xmax=2.5, color="tab:blue", alpha=0.15,
                    label="x between 1.5 and 2.5")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
ax.legend(loc="upper left")
print("horizontal band y range:", band_y.get_y(), "to", band_y.get_y() + band_y.get_height())
print("vertical band x range:", band_x.get_x(), "to", band_x.get_x() + band_x.get_width())
with tempfile.TemporaryDirectory() as directory:
    fig.savefig(Path(directory) / "plot.png")
plt.close(fig)

輸出:

horizontal band y range: 1.5 to 2.5
vertical band x range: 1.5 to 2.5

Matplotlib 圖表,其中一條位於 y = 1.5 到 y = 2.5 之間的橙色水平區域和一條位於 x = 1.5 到 x = 2.5 之間的藍色垂直區域,由圖例標識

區域的邊界始終使用資料座標。與 axhline 一樣,span 函數也接受橫向方向的比例參數——axhspan 接受 xmin 和 xmax 作為座標軸比例以限制區域的寬度,axvspan 接受 ymin 和 ymax——但以這種方式繪製的區域仍然以資料值開始和結束。

為什麼 Matplotlib 中的水平線或垂直線可能不顯示

兩個檢查就能解釋幾乎所有線條缺失的報告。第一個是類型錯誤:axhline 和 axvline 的比例參數必須是數字。將它們作為字串傳遞——當值來自表單、CSV 檔案或設定項目時常見的失誤——會在繪製任何內容之前引發 ValueError:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
ax.axhline(y=2, xmin="0.1", xmax="0.9", color="tab:red")
plt.close(fig)

輸出:

ValueError: xmin must be a single scalar value, but got 0.1

先將值轉換為數字,例如使用 float(...),相同的呼叫就會成功——本文的第一個範例正是使用數字比例的那個呼叫。

第二個檢查是可見範圍。即使線條的位置位於目前座標軸範圍之外,它也會以資料座標建立,因此它存在於圖形中,但被裁剪到檢視之外:

import tempfile
from pathlib import Path

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
line = ax.axhline(y=20, color="tab:red")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
print("line y position:", line.get_ydata())
print("axes y limits:", tuple(float(v) for v in ax.get_ylim()))
with tempfile.TemporaryDirectory() as directory:
    fig.savefig(Path(directory) / "plot.png")
plt.close(fig)

輸出:

line y position: [20, 20]
axes y limits: (0.0, 4.0)

線條位於 y=20,而座標軸止於 4.0。擴展範圍以包含該位置——或者如果 20 是個錯誤則更正該值——線條就會出現。同樣的檢查適用於 hlines 和 vlines 的端點,以及落在範圍之外的 span 邊界。

在 Matplotlib 中繪製水平線與垂直線的結論

當位置是資料值但線條的範圍應遵循座標軸比例時,選擇 axhline 或 axvline。當位置和兩個端點都應保持為資料值時,選擇 hlines 或 vlines;當需要突顯兩個值之間的整條區域而不是單條線時,使用 axhspan 或 axvspan。這種座標選擇決定了在變更繪圖範圍後線條的可見程度——而將儲存的座標與座標軸範圍進行比較,可以解釋任何看似缺失的線條。