注意
前往結尾以下載完整的範例程式碼。
繪圖的生命週期#
本教學旨在展示使用 Matplotlib 進行單一視覺化的開始、中間和結束。我們將從一些原始資料開始,並以儲存客製化視覺化的圖形結束。在此過程中,我們嘗試強調一些使用 Matplotlib 的整潔功能和最佳實踐。
注意
本教學改編自 Chris Moffitt 的這篇出色的部落格文章。由 Chris Holdgraf 轉化為本教學。
關於顯式與隱式介面的說明#
Matplotlib 有兩個介面。關於顯式和隱式介面之間權衡的說明,請參閱Matplotlib 應用程式介面 (API)。
在顯式物件導向 (OO) 介面中,我們直接使用 axes.Axes
的實例,在 figure.Figure
的實例中建立視覺化。在受 MATLAB 啟發和建模的隱式介面中,我們使用一個封裝在 pyplot
模組中的全域基於狀態的介面,來繪製到「當前 Axes」。有關 pyplot 介面的更深入介紹,請參閱pyplot 教學。
大多數術語都很直觀,但要記住的主要事情是
我們直接從 Axes 呼叫繪圖的方法,這讓我們在客製化繪圖方面擁有更大的彈性和能力。
注意
一般而言,繪圖時請使用顯式介面,而不是隱式 pyplot 介面。
我們的資料#
我們將使用本教學所改編的文章中的資料。它包含許多公司的銷售資訊。
import matplotlib.pyplot as plt
import numpy as np
data = {'Barton LLC': 109438.50,
'Frami, Hills and Schmidt': 103569.59,
'Fritsch, Russel and Anderson': 112214.71,
'Jerde-Hilpert': 112591.43,
'Keeling LLC': 100934.30,
'Koepp Ltd': 103660.54,
'Kulas Inc': 137351.96,
'Trantow-Barrows': 123381.38,
'White-Trantow': 135841.99,
'Will LLC': 104437.60}
group_data = list(data.values())
group_names = list(data.keys())
group_mean = np.mean(group_data)
開始#
此資料自然地以長條圖形式視覺化,每個群組一個長條。要使用物件導向方法執行此操作,我們首先產生 figure.Figure
和 axes.Axes
的實例。Figure 就像畫布,而 Axes 是該畫布的一部分,我們將在其中進行特定的視覺化。
注意
圖形可以有多個 Axes。有關如何執行此操作的資訊,請參閱緊密佈局教學。
fig, ax = plt.subplots()

現在我們有了 Axes 實例,就可以在其上繪圖了。
fig, ax = plt.subplots()
ax.barh(group_names, group_data)

控制樣式#
Matplotlib 中有許多樣式可供選擇,以便您可以根據自己的需求調整視覺化效果。要查看樣式列表,我們可以使用 style
。
print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'petroff10', 'seaborn-v0_8', 'seaborn-v0_8-bright', 'seaborn-v0_8-colorblind', 'seaborn-v0_8-dark', 'seaborn-v0_8-dark-palette', 'seaborn-v0_8-darkgrid', 'seaborn-v0_8-deep', 'seaborn-v0_8-muted', 'seaborn-v0_8-notebook', 'seaborn-v0_8-paper', 'seaborn-v0_8-pastel', 'seaborn-v0_8-poster', 'seaborn-v0_8-talk', 'seaborn-v0_8-ticks', 'seaborn-v0_8-white', 'seaborn-v0_8-whitegrid', 'tableau-colorblind10']
您可以使用以下方式啟用樣式
plt.style.use('fivethirtyeight')
現在讓我們重新製作上面的繪圖,看看它的樣子
fig, ax = plt.subplots()
ax.barh(group_names, group_data)

樣式控制許多內容,例如顏色、線寬、背景等。
自訂繪圖#
現在我們有了一個具有我們想要的一般外觀的繪圖,因此讓我們進行微調,使其可以列印。首先,讓我們旋轉 x 軸上的標籤,以便它們更清楚地顯示出來。我們可以使用 axes.Axes.get_xticklabels()
方法來存取這些標籤
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()

如果我們想要一次設定多個項目的屬性,則使用 pyplot.setp()
函式會很有用。這將採用一個(或多個)Matplotlib 物件的清單,並嘗試設定每個物件的某些樣式元素。
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')

看起來這剪切掉了底部的某些標籤。我們可以告訴 Matplotlib 自動為我們建立的圖形中的元素騰出空間。為此,我們設定 rcParams 的 autolayout
值。有關使用 rcParams 控制繪圖的樣式、佈局和其他功能的更多資訊,請參閱使用樣式表和 rcParams 自訂 Matplotlib。
plt.rcParams.update({'figure.autolayout': True})
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')

接下來,我們將標籤新增到繪圖。要使用 OO 介面執行此操作,我們可以使用 Artist.set()
方法來設定此 Axes 物件的屬性。
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')

我們也可以使用 pyplot.subplots()
函式調整此繪圖的大小。我們可以使用 figsize 關鍵字引數來執行此操作。
注意
雖然 NumPy 中的索引形式為 (列、欄),但 figsize 關鍵字引數的形式為 (寬度、高度)。這遵循視覺化的慣例,不幸的是,這些慣例與線性代數的慣例不同。
fig, ax = plt.subplots(figsize=(8, 4))
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')

對於標籤,我們可以使用函式的形式指定自訂格式設定準則。下面我們定義一個函式,該函式將整數作為輸入,並將字串作為輸出傳回。當與 Axis.set_major_formatter
或 Axis.set_minor_formatter
一起使用時,它們將自動建立並使用 ticker.FuncFormatter
類別。
對於此函式,x
引數是原始刻度標籤,而 pos
是刻度位置。我們在此只會使用 x
,但兩個引數都是必要的。
def currency(x, pos):
"""The two arguments are the value and tick position"""
if x >= 1e6:
s = f'${x*1e-6:1.1f}M'
else:
s = f'${x*1e-3:1.0f}K'
return s
然後,我們可以將此函式套用至繪圖上的標籤。要執行此操作,我們可以使用 Axes 的 xaxis
屬性。這可讓您在繪圖上的特定軸上執行動作。
fig, ax = plt.subplots(figsize=(6, 8))
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')
ax.xaxis.set_major_formatter(currency)

合併多個視覺化#
可以在 axes.Axes
的同一個實例上繪製多個繪圖元素。要執行此操作,我們只需在該 Axes 物件上呼叫另一個繪圖方法即可。
fig, ax = plt.subplots(figsize=(8, 8))
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
# Add a vertical line, here we set the style in the function call
ax.axvline(group_mean, ls='--', color='r')
# Annotate new companies
for group in [3, 5, 8]:
ax.text(145000, group, "New Company", fontsize=10,
verticalalignment="center")
# Now we move our title up since it's getting a little cramped
ax.title.set(y=1.05)
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')
ax.xaxis.set_major_formatter(currency)
ax.set_xticks([0, 25e3, 50e3, 75e3, 100e3, 125e3])
fig.subplots_adjust(right=.1)
plt.show()

儲存繪圖#
現在我們對繪圖的結果感到滿意,我們想要將其儲存到磁碟。在 Matplotlib 中,我們可以儲存為許多檔案格式。要查看可用選項的清單,請使用
print(fig.canvas.get_supported_filetypes())
{'eps': 'Encapsulated Postscript', 'jpg': 'Joint Photographic Experts Group', 'jpeg': 'Joint Photographic Experts Group', 'pdf': 'Portable Document Format', 'pgf': 'PGF code for LaTeX', 'png': 'Portable Network Graphics', 'ps': 'Postscript', 'raw': 'Raw RGBA bitmap', 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', 'svgz': 'Scalable Vector Graphics', 'tif': 'Tagged Image File Format', 'tiff': 'Tagged Image File Format', 'webp': 'WebP Image Format'}
然後,我們可以使用 figure.Figure.savefig()
以將圖形儲存到磁碟。請注意,下面我們顯示了幾個有用的旗標
transparent=True
使儲存的圖形背景透明(如果格式支援)。dpi=80
控制輸出解析度(每平方英寸點數)。bbox_inches="tight"
將圖形的邊界擬合到我們的繪圖。
# Uncomment this line to save the figure.
# fig.savefig('sales.png', transparent=False, dpi=80, bbox_inches="tight")
腳本的總執行時間:(0 分 4.147 秒)