HOWTO · Matplotlib

如何在 Matplotlib 中繪製對數軸

我們可以使用 set_yscale(),semilogy()和 loglog()函式在 Matplotlib 中繪製對數軸。

本頁內容

使用 set_xscale() 或 set_yscale(),即可分別設定其中一個座標軸的刻度。若要讓兩個座標軸都使用對數刻度,請使用 loglog()。semilogx() 和 semilogy() 輔助函式則分別將對數刻度套用至 x 軸和 y 軸。 對數軸以 10 的冪次間隔排列刻度,因此跨越數個數量級的資料仍清晰可讀,不會擠在線性軸最低的刻度區間裡。
以下所有程式碼範例皆已成功執行。

使用 set_xscale() 或 set_yscale() 函式

呼叫 set_xscale("log") 可將 x 軸設為對數刻度,呼叫 set_yscale("log") 可將 y 軸設為對數刻度;若兩者都呼叫,兩個座標軸就都會使用對數刻度。 由於這兩個呼叫彼此獨立,您可以只轉換其中一個座標軸,讓另一個保持線性。

若只想讓 x 軸使用對數刻度,請照常繪製資料,然後對座標軸呼叫 set_xscale("log"):

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]

fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_xscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

印出的結果證實只有 x 軸改變:x-axis: log, y-axis: linear。1、10、100、1000 的刻度等距排列,儘管數值本身每次都增加為 10 倍。

使用 set_xscale 建立的折線圖,x 軸為對數刻度、y 軸為線性刻度

若只想讓 y 軸使用對數刻度,請改為呼叫 set_yscale("log"),並讓 x 軸保持不變:

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]

fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

這次印出的結果是 x-axis: linear, y-axis: log,等距的刻度出現在 y 軸上。

使用 set_yscale 建立的折線圖,x 軸為線性刻度、y 軸為對數刻度

pyplot 的狀態機介面透過頂層函式 plt.xscale() 與 plt.yscale() 提供相同的變更,這兩個函式作用於目前的座標軸。同一個圖表的 yscale() 版本如下:

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]

plt.plot(x, y, marker="o")
plt.yscale("log")
plt.xlabel("x")
plt.ylabel("y")
ax = plt.gca()
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close()

結果是相同的對數 y 軸;在保留明確 ax 參照的程式中,座標軸物件的方法通常更清楚,因為目標座標軸在呼叫中被直接指名,而不是由目前的圖形隱含決定。

使用 pyplot 的 yscale 函式建立的折線圖,y 軸為對數刻度

以下完整範例使用正數資料繪圖,並將兩個座標軸都設為對數刻度。

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]

fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

此時印出的結果是 x-axis: log, y-axis: log,相同的比例在兩個座標軸上都佔據相同的距離。

使用 set_xscale 與 set_yscale 建立的折線圖,兩個座標軸皆為對數刻度

標準的 log 刻度適用於正值。如果資料包含正負值,請對相關座標軸使用 symlog,例如 ax.set_yscale("symlog");它可以顯示零的兩側的值。 最後一節會以經過驗證的範例重新討論這個情況。

使用 semilogx() 或 semilogy() 函式

若要讓 x 軸使用對數刻度、y 軸維持線性刻度,請使用 semilogx()。若要讓 y 軸使用對數刻度、x 軸維持線性刻度,則使用 semilogy()。這兩個輔助函式都接受 x 與 y 資料作為引數,因此可在繪圖呼叫中明確指定所需的刻度。如果兩個座標軸都要使用對數刻度,可以使用 loglog(),或在同一組座標軸上結合 semilogx() 和 semilogy()。

下面的 semilogx() 呼叫會一步完成資料繪製與對數 x 軸的設定:

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]

fig, ax = plt.subplots()
ax.semilogx(x, y, marker="o", label="logarithmic x")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

這個輔助函式會傳回繪製的線條,之後座標軸報告 x-axis: log, y-axis: linear,與第一節中明確呼叫 set_xscale("log") 的結果完全相同。

使用 semilogx 建立的折線圖,x 軸為對數刻度、y 軸為線性刻度

在同一組座標軸上結合這兩個輔助函式,兩個座標軸都會使用對數刻度。請注意,刻度屬於座標軸,而不是單一條繪製的線條:一旦 semilogy() 設定了 y 軸,該刻度就會套用到座標軸中的所有資料系列,包括先前由 semilogx() 繪製的那一條。

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
y2 = [3, 8, 30, 120]

fig, ax = plt.subplots()
ax.semilogx(x, y, marker="o", label="first series")
ax.semilogy(x, y2, marker="s", label="second series")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

兩個資料系列最終都繪製在對數 x 軸與 y 軸上,印出的結果證實了最終狀態:x-axis: log, y-axis: log。

結合 semilogx 與 semilogy 建立的兩條折線系列,共用對數 x 軸與 y 軸

使用 loglog() 函式

若兩個座標軸都需要對數刻度,請使用 loglog()。它會繪製提供的 x 與 y 資料,並將兩個座標軸設為標準對數刻度。以下是使用正數值的完整範例:

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]

fig, ax = plt.subplots()
ax.loglog(x, y, marker="o")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

渲染結果與第一節中 set_xscale("log") 加上 set_yscale("log") 的組合一致;loglog() 只是把刻度選擇併入繪圖呼叫本身。

使用 loglog 建立的折線圖,兩個座標軸皆為對數刻度

非正值與無效的刻度名稱

有兩件事經常讓對數軸的使用者感到意外,在除錯一個看起來不對的圖表之前,兩者都值得先了解。第一,刻度名稱會立即被驗證:像 ax.set_yscale("logg") 這樣的拼寫錯誤會引發 ValueError: 'logg' is not a valid value for scale. Did you mean one of: 'log', 'logit', 'symlog'?(訊息在 Matplotlib 3.11 上逐字擷取)。錯誤訊息會列出可接受的值,因此拼寫錯誤會立刻失敗,而不是悄悄產生一個線性軸。

第二,對數刻度無法表示零或負值,而且這種情況不會引發錯誤。Matplotlib 會悄悄丟棄非正值的資料點:它們會被從繪圖中遮蔽,經過這些點的線段會消失,座標軸範圍只涵蓋正值。下面的範例在對數 y 軸上繪製 y = [2, 0, -5, 80]:

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 0, -5, 80]

fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

呼叫會正常完成並報告 y-axis: log,但只有 y = 2 與 y = 80 的資料點能顯示;在經過驗證的執行中,得到的 y 軸範圍約為 1.66 到 96.2,只涵蓋正值資料。如果把某個座標軸切換為 log 之後,資料系列似乎少了點,請先檢查資料中是否有零和負值,再懷疑繪圖程式碼。

當資料確實包含帶正負號的值時,symlog(對稱對數)刻度是合適的替代方案:它在遠離零的範圍使用對數刻度,在零附近的小範圍使用線性刻度,因此每個資料點都能保留顯示。

import matplotlib.pyplot as plt

x = [1, 10, 100, 1000]
y = [2, 0, -5, 80]

fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("symlog")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)

四個資料點(包括 0 和 -5)都會繪製在 symlog 的 y 軸上。只要數值的正負號本身帶有資訊,就使用這種刻度;對於本質上為正值的資料,例如計數、大小和物理測量值,則保持使用單純的 log 刻度。