天天看點

matplotlib API 可視化入門 (附執行個體)

從一個小例子開始

繪制一條直線(折線圖)

import matplotlib.pyplot as plt
import numpy as np
data=np.arange(10)
plt.plot(data)
plt.show()
           
matplotlib API 可視化入門 (附執行個體)

Figure和Subplot

matplotlib的圖像都位于Figure對象中。你可以用plt.figure建立一個新的Figure:

plt.figure有一些選項,特别是figsize,它用于確定當圖檔儲存到磁盤時具有一定的大小和縱橫比。

不能通過空 Figure 繪圖。必須用 add_subplot 建立一個或多個 subplot 才行:

ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)
           
matplotlib API 可視化入門 (附執行個體)

圖9-2 帶有三個subplot的Figure

提示:使用Jupyter notebook有一點不同,即每個小窗重新執行後,圖形會被重置。是以,對于複雜的圖形,你必須将所有的繪圖指令存在一個小窗裡。

如果這時執行一條繪圖指令 plt.plot(),matplotlib就會在最後一個用過的subplot(如果沒有則建立一個)上進行繪制,隐藏建立figure和subplot的過程。是以,如果我們執行下列指令,你就會得到如圖9-3所示的結果:

ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)
plt.plot(np.random.randn(50).cumsum(), 'k--')
           
matplotlib API 可視化入門 (附執行個體)

圖9-3 繪制一次之後的圖像

上面那些由 fig.add_subplot 所傳回的對象是 AxesSubplot 對象,直接調用它們的執行個體方法就可以在其空着的格子裡面畫圖了,如圖9-4所示:

# 直方圖
# randn(2,3)表示2行3列的标準正态分布(期望為0,方差為1,也稱高斯分布)
# alpha 是透明度
ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)
# 散點圖
# arange(3,7,2) 表示從3開始,再到下一個相差2的數,一直到6(前包後不包)
# 傳回array([3,5])
ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30))
           
matplotlib API 可視化入門 (附執行個體)

圖9-4 繼續繪制兩次之後的圖像

建立包含subplot網格的figure是一個非常常見的任務,matplotlib有一個更為友善的方法plt.subplots,它可以建立一個新的Figure,并傳回一個含有已建立的subplot對象的NumPy數組:

fig, axes = plt.subplots(2,3)
axes
           

array([[<matplotlib.axes._subplots.AxesSubplot object at 0x000001CCD6617048>,

<matplotlib.axes._subplots.AxesSubplot object at 0x000001CCD66434A8>],

[<matplotlib.axes._subplots.AxesSubplot object at 0x000001CCD6669A90>,

<matplotlib.axes._subplots.AxesSubplot object at 0x000001CCD6699160>]],

dtype=object)

這是非常實用的,因為可以輕松地對axes數組進行索引,就好像是一個二維數組一樣,例如axes[0,1]。

你還可以通過sharex和sharey指定subplot應該具有相同的X軸或Y軸。在比較相同範圍的資料時,這也是非常實用的,否則,matplotlib會自動縮放各圖表的界限。

# sharex=True: 4個subplot共享x軸
fig, axes = plt.subplots(2,2, sharex=True)
           
matplotlib API 可視化入門 (附執行個體)

有關該方法的更多資訊,請參見表9-1。

matplotlib API 可視化入門 (附執行個體)

調整subplot周圍的間距

利用Figure的subplots_adjust方法可以輕而易舉地修改間距,此外,它也是個頂級函數:

fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
for i in range(2):    
    for j in range(2):
        axes[i, j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5)
# wspace和hspace用于控制寬度和高度的百分比
plt.subplots_adjust(wspace=0, hspace=0)
           
matplotlib API 可視化入門 (附執行個體)

圖9-5 各subplot之間沒有間距

不難看出,其中的軸标簽重疊了。matplotlib不會檢查标簽是否重疊,是以對于這種情況,你隻能自己設定刻度位置和刻度标簽。後面幾節将會詳細介紹該内容。

顔色、标記和線型

matplotlib的plot函數接受一組X和Y坐标,還可以接受一個表示顔色和線型的字元串縮寫。例如,要根據x和y繪制綠色虛線,你可以執行如下代碼:

這種在一個字元串中指定顔色和線型的方式非常友善。在實際中,如果你是用代碼繪圖,你可能不想通過處理字元串來獲得想要的格式。通過下面這種更為明确的方式也能得到同樣的效果:

常用的顔色可以使用顔色縮寫,你也可以指定顔色碼(例如,’#CECECE’)。你可以通過檢視plot的文檔字元串檢視所有線型的合集(在IPython和Jupyter中使用plot?)。

線圖可以使用标記強調資料點。因為matplotlib可以建立連續線圖,在點之間進行插值,是以有時可能不太容易看出真實資料點的位置。标記也可以放到格式字元串中,但标記類型和線型必須放在顔色後面(見圖9-6):

from numpy.random import randn
# y表示黃色,o表示資料點為實心圓點,-- 表示虛線。
plt.plot(randn(30).cumsum(), 'yo--')
           
matplotlib API 可視化入門 (附執行個體)

圖9-6 帶有标記的線型圖示例

線上型圖中,非實際資料點預設是按線性方式插值的。可以通過drawstyle選項修改(見圖9-7):

data = np.random.randn(30).cumsum()
# 非資料點預設為線性插值方式繪制
plt.plot(data, 'k--', label='Default')
# 非資料點使用 drawstyle='steps-post'方式繪制
plt.plot(data, 'k-', drawstyle='steps-post', label='steps-post')
plt.legend(loc='best')
           
matplotlib API 可視化入門 (附執行個體)

圖9-7 不同drawstyle選項的線型圖

刻度、标簽和圖例

對于大多數的圖表裝飾項,其主要實作方式有二:

  • 使用過程型的pyplot接口(例如,matplotlib.pyplot)
  • 以及更為面向對象的原生matplotlib API。

pyplot接口的設計目的就是互動式使用,含有諸如xlim、xticks和xticklabels之類的方法。它們分别控制圖表的範圍、刻度位置、刻度标簽等。其使用方式有以下兩種:

  • 調用時不帶參數,則傳回目前的參數值(例如,plt.xlim() 傳回目前的X軸繪圖範圍)。
  • 調用時帶參數,則設定參數值(例如,plt.xlim([0,10]) 會将X軸的範圍設定為0到10)。

所有這些方法都是對目前或最近建立的AxesSubplot起作用的。它們各自對應subplot對象上的兩個方法,以xlim為例,就是ax.get_xlim和ax.set_xlim。我更喜歡使用subplot的執行個體方法(因為我喜歡明确的事情,而且在處理多個subplot時這樣也更清楚一些)。當然你完全可以選擇自己覺得友善的那個。

設定标題、軸标簽、刻度以及刻度标簽

為了說明自定義軸,我将建立一個簡單的圖像并繪制一段随機漫步(如圖9-8所示):

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(np.random.randn(1000).cumsum())
           
matplotlib API 可視化入門 (附執行個體)

圖9-8 用于示範xticks的簡單線型圖(帶有标簽)

要改變x軸刻度,最簡單的辦法是使用 set_xticks 和 set_xticklabels。前者告訴matplotlib要将刻度放在資料範圍中的哪些位置,預設情況下,這些位置也就是刻度标簽。但我們可以通過set_xticklabels将任何其他的值用作标簽:

ticks = ax.set_xticks([0, 250, 500, 750, 1000])
labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'],
							rotation=30, fontsize='small')
# rotation選項設定x刻度标簽傾斜30度
           
matplotlib API 可視化入門 (附執行個體)

最後,再用 set_xlabel 為X軸設定一個名稱,并用 set_title 設定一個标題(見圖9-9的結果):

ax.set_title('My first matplotlib plot')
ax.set_xlabel('Stages')
           
matplotlib API 可視化入門 (附執行個體)

圖9-9 用于示範xticks的簡單線型圖

Y軸的修改方式與此類似,隻需将上述代碼中的x替換為y即可。

軸的類有集合方法,可以批量設定繪圖選項。前面的例子,也可以寫為:

props = {'title': 'My first matplotlib plot', 'xlabel': 'Stages'}
ax.set(**props)
           

添加圖例

圖例(legend)是另一種用于辨別圖表元素的重要工具。添加圖例的方式有多種。最簡單的是在添加subplot的時候傳入label參數:

from numpy.random import randn
fig = plt.figure(); ax = fig.add_subplot(1, 1, 1)
ax.plot(randn(1000).cumsum(), 'k', label='one')
ax.plot(randn(1000).cumsum(), 'k--', label='two')
ax.plot(randn(1000).cumsum(), 'k.', label='three')
ax.legend(loc='best')
           

在此之後,你可以調用ax.legend()或plt.legend()來自動建立圖例(結果見圖9-10):

matplotlib API 可視化入門 (附執行個體)

圖9-10 帶有三條線以及圖例的簡單線型圖

legend方法有幾個其它的loc位置參數選項。

loc告訴matplotlib要将圖例放在哪。如果你不是吹毛求疵的話,"best"是不錯的選擇,因為它會選擇最不礙事的位置。要從圖例中去除一個或多個元素,不傳入label或傳入label='nolegend’即可。

注解以及在Subplot上繪圖

除标準的繪圖元素,你可能還希望繪制一些注解,可能是文本、箭頭或其他圖形等。注解和文字可以通過text、arrow和annotate函數進行添加。text可以将文本繪制在圖表的指定坐标(x,y),還可以加上一些自定義格式:

注解中可以既含有文本也含有箭頭。例如,我們根據最近的标準普爾500指數價格繪制一張曲線圖,并标出2008年到2009年金融危機期間的一些重要日期。你可以在Jupyter notebook的一個小窗中試驗這段代碼(圖9-11是結果):

from datetime import datetime
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# parse_dates 解析為日期格式
data = pd.read_csv('examples/spx.csv', index_col=0, parse_dates=True)
spx = data['SPX']
spx.plot(ax=ax, style='k-')
crisis_data = [
    (datetime(2007, 10, 11), 'Peak of bull market'),
    (datetime(2008, 3, 12), 'Bear Stearns Fails'),
    (datetime(2008, 9, 15), 'Lehman Bankruptcy')]

for date, label in crisis_data:
	# asof(date) 将date 作為索引,傳回這個索引對應的行值 
    ax.annotate(label, xy=(date, spx.asof(date) + 75),
                xytext=(date, spx.asof(date) + 225),
                arrowprops=dict(facecolor='black',headwidth=4,width=2,headlength=4),
                horizontalalignment='left', verticalalignment='top')
                # Zoom in on 2007-2010
                ax.set_xlim(['1/1/2007', '1/1/2011'])
                
ax.set_ylim([600, 1800])
ax.set_title('Important dates in the 2008-2009 financial crisis')
           
matplotlib API 可視化入門 (附執行個體)

圖9-11 2008-2009年金融危機期間的重要日期

這張圖中有幾個重要的點要強調:ax.annotate方法可以在指定的x和y坐标軸繪制标簽。我們使用set_xlim和set_ylim人工設定起始和結束邊界,而不使用matplotlib的預設方法。最後,用ax.set_title添加圖示标題。

更多有關注解的示例,請通路matplotlib的線上示例庫。

圖形的繪制要麻煩一些。matplotlib有一些表示常見圖形的對象。這些對象被稱為塊(patch)。其中有些(如Rectangle和Circle),可以在matplotlib.pyplot中找到,但完整集合位于matplotlib.patches。

要在圖表中添加一個圖形,你需要建立一個塊對象shp,然後通過ax.add_patch(shp)将其添加到subplot中(如圖9-12所示):

matplotlib API 可視化入門 (附執行個體)

圖9-12 由三個塊圖形組成的圖

将圖表儲存到檔案

利用plt.savefig可以将目前圖表儲存到檔案。該方法相當于Figure對象的執行個體方法savefig。例如,要将圖表儲存為SVG檔案,你隻需輸入:

檔案類型是通過檔案擴充名推斷出來的。是以,如果你使用的是.pdf,就會得到一個PDF檔案。我在釋出圖檔時最常用到兩個重要的選項是dpi(控制“每英寸點數”分辨率)和bbox_inches(可以剪除目前圖表周圍的空白部分)。要得到一張帶有最小白邊且分辨率為400DPI的PNG圖檔,你可以:

savefig并非一定要寫入磁盤,也可以寫入任何檔案型的對象,比如BytesIO:

from io import BytesIO
buffer = BytesIO()
plt.savefig(buffer)
plot_data = buffer.getvalue()
           

表9-2列出了savefig的其它選項。

matplotlib API 可視化入門 (附執行個體)

表9-2 Figure.savefig的選項

matplotlib配置

matplotlib自帶一些配色方案,以及為生成出版品質的圖檔而設定的預設配置資訊。幸運的是,幾乎所有預設行為都能通過一組全局參數進行自定義,它們可以管理圖像大小、subplot邊距、配色方案、字型大小、網格類型等。一種Python程式設計方式配置系統的方法是使用rc方法。例如,要将全局的圖像預設大小設定為10×10,你可以執行:

rc的第一個參數是希望自定義的對象,如’figure’、‘axes’、‘xtick’、‘ytick’、‘grid’、'legend’等。其後可以跟上一系列的關鍵字參數。一個簡單的辦法是将這些選項寫成一個字典:

font_options = {'family':'monospace','weight':'bold','size':'small'}
plt.rc('font', **font_options)
           

要了解全部的自定義選項,請查閱matplotlib的配置檔案matplotlibrc(位于matplotlib/mpl-data目錄中)。如果對該檔案進行了自定義,并将其放在你自己的.matplotlibrc目錄中,則每次使用matplotlib時就會加載該檔案。

下一節,我們會看到,seaborn包有若幹内置的繪圖主題或類型,它們使用了matplotlib的内部配置。

.

.

參考:《利用Python進行資料分析·第2版》