Matplotlib 默認的刻度標志和格式被設計成能滿足許多通用場景的需求,但是不會是所有圖表的最佳選擇。本節會介紹一些調整刻度位置和格式的例子來說明自定義刻度的使用。
在介紹例子之前,我們應該加深對 Matplotlib 圖表的對象層次的理解。Matplotlib 的設計目標是展示在圖表中的所有內容都會表達成為 Python 的對象:例如,回憶前面我們介紹過figure
指的是用來展示圖表所有內容的方框。每個 Matplotlib 對象也被設計為其子對象的一個容器:例如figure
對象中可以包含一個或多個axes
對象,每個axes
對象都依次包含着其他用來展示圖表的內容對象。
刻度也不例外。每個axes
對象都有着屬性xaxis
和yaxis
,表示 x 和 y 軸,其中包含着所有的屬性用來指代軸的線、刻度和標簽。
主要的和次要的刻度
在每個坐標軸上,都有主要的刻度和次要的刻度概念。正如名字指代的,主要刻度通常是大的和更多用到的,而次要刻度通常是小的。默認 Matplotlib 很少使用次要刻度,但是在對數圖表中我們可能會看到它們:
在 Matplotlib 2.0 之后,當 axis 的跨度過大時,默認次要刻度將會不再展示,因此,下面的代碼經過了修改,加上了 xlim 和 ylim 參數。
import matplotlib.pyplot as plt plt.style.use('classic') import numpy as np
ax = plt.axes(xscale='log', yscale='log', xlim=[10e-5, 10e5], ylim=[10e-5, 10e5]) ax.grid(); plt.show()
我們看到每個主要刻度顯示了一個大的標志和標簽,而每個次要刻度顯示了一個小的刻度標志沒有標簽。
這些刻度屬性,位置和標簽,都可以使用每個軸的formatter
和locator
對象進行個性化設置。下面我們來查看一下 x 軸的相應對象:
print(ax.xaxis.get_major_locator())
print(ax.xaxis.get_minor_locator())
<matplotlib.ticker.LogLocator object at 0x000001E8074AF108>
<matplotlib.ticker.LogLocator object at 0x000001E8074AD908>
print(ax.xaxis.get_major_formatter())
print(ax.xaxis.get_minor_formatter())
<matplotlib.ticker.LogFormatterSciNotation object at 0x000001E8074AEB88>
<matplotlib.ticker.LogFormatterSciNotation object at 0x000001E8074ADB48>
我們看到主要和次要刻度的位置都是使用LogLocator
來設置的(對於對數圖表來說那是理所當然的)。然而次要刻度的標簽的格式是NullFormatter
:這表示次要刻度不會顯示標簽。
譯者注:新版 Matplotlib 已經修改,可以看到 Formatter 都統一成為了 LogFormatterSciNotation,再根據圖表實際情況選擇是否展示標簽。
下面我們就可以開始介紹一些設置這些 locator 和 formatter 的例子了。
隱藏刻度和標簽
也許最常見的刻度/標簽格式設置的操作是隱藏刻度或標簽。這可以通過使用plt.NullLocator()
和plt.NullFormatter()
來設置,如下例:
ax = plt.axes() ax.plot(np.random.rand(50)) ax.yaxis.set_major_locator(plt.NullLocator()) ax.xaxis.set_major_formatter(plt.NullFormatter())
注意上圖中我們去除了 x 軸的標簽(但是保留了刻度或網格線),y 軸的刻度和標簽都被去除了。圖表中沒有刻度和標簽在很多情況下很有用,例如,當你希望展示一個圖像的網格。比方說,考慮下面的圖表,包含着不同的頭像,一個很常見的有監督機器學習問題:
fig, ax = plt.subplots(5, 5, figsize=(5, 5)) fig.subplots_adjust(hspace=0, wspace=0) # 從scikit-learn載入頭像數據集 from sklearn.datasets import fetch_olivetti_faces faces = fetch_olivetti_faces().images for i in range(5): for j in range(5): ax[i, j].xaxis.set_major_locator(plt.NullLocator()) ax[i, j].yaxis.set_major_locator(plt.NullLocator()) ax[i, j].imshow(faces[10 * i + j], cmap="bone")
downloading Olivetti faces from
https://ndownloader.figshare.com/files/5976027
to C:\Users\gdc\scikit_learn_data
注意上圖中每張圖像都有它自己的 axes,我們將每一個 axes 的 locator 都設置為 null 因為這些刻度值(像素值)在這里並沒有任何實際意義。
減少或增加刻度的數量
默認設置的一個常見問題是當子圖表較小時,刻度標簽可能會粘在一起。我們可以從下面例子看到:
fig, ax = plt.subplots(4, 4, sharex=True, sharey=True)
特別是 x 軸,標簽的數字就快重疊在一起了,這讓這些標簽難以認清。我們可以通過plt.MaxNLocator()
來修正這點,用它可以設置最大展示刻度的數量。Matplotlib 會自己計算按照這個最大數量計算的刻度位置:
# 對x和y軸設置刻度最大數量 for axi in ax.flat: axi.xaxis.set_major_locator(plt.MaxNLocator(3)) axi.yaxis.set_major_locator(plt.MaxNLocator(3)) fig
上圖就清晰多了。如果你希望對於刻度位置進行更加精細的控制,你可以使用plt.MultipleLocator
,我們會接下來討論這個對象。
復雜的刻度格式
Matplotlib 的默認刻度格式只能在很多常見情況下工作良好,但是在特殊情況下你會希望能夠更多的進行個性化。考慮下面的正弦和余弦圖表:
# 繪制正弦和余弦圖表 fig, ax = plt.subplots() x = np.linspace(0, 3 * np.pi, 1000) ax.plot(x, np.sin(x), lw=3, label='Sine') ax.plot(x, np.cos(x), lw=3, label='Cosine') # 設置網格、圖例和軸極限 ax.grid(True) ax.legend(frameon=False) ax.axis('equal') ax.set_xlim(0, 3 * np.pi);
這里有幾個我們希望進行的改變。首先,如果刻度的間距和網格線是 的倍數會顯得更加自然。我們可以通過MultipleLocator
來設置它,這個對象用來設置刻度的配置。為了更直觀,我們設置主要刻度為pai/2 位置,設置次要刻度為pai/4 位置:
但是上圖看起來有點傻:我們可以看出刻度確實是 pai 的倍數,但是使用了小數的展示讓它們看起來很奇怪。要修正這些標簽,我們需要修改刻度的 formatter。在這種情況中,沒有內建的 formatter 可以給我們使用,因此我們使用plt.FuncFormatter
,這個對象能夠接受一個用戶自定義的函數來提供對於刻度標簽的精細控制:
def format_func(value, tick_number): # N是pi/2的倍數 N = int(np.round(2 * value / np.pi)) if N == 0: return "0" # 0點 elif N == 1: return r"$\frac{\pi}{2}$" # pi/2 elif N == 2: return r"$\pi$" # pi elif N % 2 > 0: return r"$\frac{{%d}\pi}{2}$" %N # n*pi/2 n是奇數 else: return r"${0}\pi$".format(N // 2) # n*pi n是整數 ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func)) fig
上圖看起來好多了。注意到我們使用到了 Matplotlib 的 LaTeX 支持,使用美元符號將 LaTeX 字符串括起來。這是用來展示數學符號和公式的簡便方法:在這個例子中"$\pi$"
被渲染成希臘字母 。
plt.FuncFomatter()
提供了對於圖表刻度最高級的自定義和精細控制,並且當你需要創建需要印刷或出版的圖表時非常方便。
Formatter 和 Locator 總結
我們已經介紹了一些 formatter 和 locator。在最后我們通過將內建的 locator 和 formatter 參數列出來對本節做一個總結。要獲得更多相關內容,請參閱文檔或 Matplotlib 的在線文檔。下表中列出的對象在plt
命名空間中都是有效的:
Locator 對象 | 描述 |
---|---|
NullLocator |
無刻度 |
FixedLocator |
固定刻度位置 |
IndexLocator |
序號圖表刻度 (例如 x = range(len(y))) |
LinearLocator |
從最小到最大值的均勻分割刻度 |
LogLocator |
從最小到最大值的對數分割刻度 |
MultipleLocator |
某個基數的倍數刻度 |
MaxNLocator |
刻度數量最大值 |
AutoLocator |
默認的刻度數量最大值 |
AutoMinorLocator |
默認的次要刻度 |
Formatter 對象 | 描述 |
---|---|
NullFormatter |
無標簽 |
IndexFormatter |
從一個列表獲得標簽 |
FixedFormatter |
從固定的字符串設置標簽 |
FuncFormatter |
使用自定義函數設置標簽 |
FormatStrFormatter |
使用一個格式化字符串設置標簽 |
ScalarFormatter |
默認的標量標簽 |
LogFormatter |
默認的對數標簽 |