0. matplotlib入門

這篇筆記主要來自《利用python進行數(shù)據(jù)分析》的第八章第一節(jié),對matplotlib的基本使用介紹的特別清晰。關于matplotlib的基本概念(figure, subplot, axes)的介紹還可以看這里

  • Figure和Subplot
  • 顏色、標記和線型
  • 刻度、標簽和圖例
  • 注解
  • 保存到文件

pyplot模塊的API文檔,這里

1. Figure和Subplot

plt.figure()

matplotlib的圖像都位于Figure對象中,可以使用plt.figure()創(chuàng)建一個新的figure:

>>> fig = plt.figure()

在ipython中,執(zhí)行后會彈出一個空窗口:

一個Figure

該窗口的大小可以通過在plt.figure()中傳遞參數(shù)figsize=(width,height)來指定。

可以看到窗口的標題為“Figure 1”,要想設定Figure編號為3,則可執(zhí)行:

>>> fig = plt.figure(3)

可通過plt.gcf()來獲得最后一次創(chuàng)建的Figure對象的引用。

Figure.add_subplot()

現(xiàn)在雖然有了一個Figure對象fig,但是還不能在其上畫圖。必須使用add_subplot()在fig上創(chuàng)建一個或多個subplot才行:

# 等價于fig.add_subplot(221)
# 意思是將fig劃分為2x2,指定第一個為畫圖位置
# 這里的subplot從1開始編號
# 其實就是在fig中固定位置創(chuàng)建了一個Axes對象。
>>> ax1 = fig.add_subplot(2, 2, 1)

執(zhí)行后會得到:

Figure中有一個subplot(Axes對象)

若接著執(zhí)行:

# 執(zhí)行后fig中就有了三個Axes對象
>>> ax2 = fig.add_subplot(2, 2, 2)
>>> ax3 = fig.add_subplot(2, 2, 3)

得到:

Figure中有三個subplot(Axes對象)

fig.add_subplot(2, 2, 1)并不意味著對于該fig,固定劃分了2x2個subplot,這只是指出一個固定的位置來確定要創(chuàng)建的Axes對象。比如還可以接著執(zhí)行下面的代碼再創(chuàng)建個小的Axes對象:

>>> ax4 = fig.add_subplot(339)

結(jié)果為:

也可將其放到其他位置,放這里方便看

可以看到Figure.add_subplot()的功能是將Axes對象創(chuàng)建于規(guī)則的網(wǎng)格(grid)上的,如果想要在Figure中的任意位置創(chuàng)建任意大小的Axes對象可使用Figure.add_axes()

plot()

如果這時發(fā)出一條繪圖命令,matplotlib會在最后一個用過的Axes對象上(如果沒有則自動創(chuàng)建一個)進行繪制。

# 繪制黑色'k'虛線'--'
>>> plt.plot(np.random.randn(50).cumsum(), 'k--')

結(jié)果為:

可見是在最后一個創(chuàng)建的Axes對象上繪制的

如果想要在其他的axes中繪圖,則可以調(diào)用之前的Axes對象中的繪圖方法

# hist方法有三個返回值,不想顯示就將其賦給以變量
>>> _ = ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)
>>> ax2.scatter(np.arange(30), np.arange(30) + 3*np.random.randn(30))

結(jié)果如下:

plt.subplots()

有一條語句可以快速的建立Figure和一組subplots,也就是plt.subplots()。它可以創(chuàng)建一個新的Figure,并返回一個含有已創(chuàng)建的Axes對象的numpy數(shù)組:

# 創(chuàng)建一個Figure對象fig2,并在其上繪制2x3個subplots
# fig2為新創(chuàng)建的Figure對象
# axess為一2x3數(shù)組,其中元素為Axes對象。
>>> fig2, axess = plt.subplots(2,3)

執(zhí)行上述語句,會彈出一個新的Figure窗口:

與之前不同,這里直接畫出了2x3個subplot

之前使用plt.figure()創(chuàng)建Figure對象時,可以傳遞figsize參數(shù)來指定Figure對象的大小。在plt.subplots()中也可以傳遞該參數(shù),見文檔中對**fig_kw參數(shù)的描述。
但是如果在創(chuàng)建完Figure對象后想改變figure size該怎么辦呢?可調(diào)用Figure類的方法set_figheight()set_figweight()來分別設置Figure對象的長和寬。可見Figure類的文檔說明

可以看axess的內(nèi)容:

>>> axess
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x1178f9240>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117920438>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117947710>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x117b28438>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117b50748>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117b7a9e8>]], dtype=object)

可以通過指定參數(shù)sharex=True使各列Axes對象使用同一個x軸(這樣,調(diào)整某列的xlim將會影響對應的axes),而設置sharey=True使各行Axes對象使用同一個y軸(這樣,調(diào)整某行的ylim將會影響對應的axes)。

>>> plt.close(2)
>>> fig2, axess = plt.subplots(2,3, sharex=Ture, sharey=Ture)

結(jié)果為:

plt.subplots_adjust()

默認情況下(matplotlib有默認的配置文件),matplotlib會在subplot外圍留下一定的邊距,并在subplot之間留下一定的間距。利用plt.subplots_adjust()Figure.subplots_adjust()可以修改這些間距。兩個函數(shù)的參數(shù)都是一樣的(見文檔),但前者是在當前Figure中操作,而后者是在指定的Figure中操作的。

# 操作的是fig2
>>> plt.subplots_adjust(wspace=0, hspace=0)

結(jié)果為:

可以看到matplotlib中的畫圖是很自由的,并不會檢查坐標的重疊。

# 操作的是上面的Figure 1
>>> fig.subplots_adjust(wspace=0, hspace=0)

結(jié)果為:

當畫完圖之后,要記得使用plt.close()關掉對應的Figure,釋放內(nèi)存。有多種關閉方式,可看文檔。

# 關閉所有Figure。
>>> plt.close('all')

總結(jié)一下,Figure對象就相當于一個巨大的畫板,可以在畫板上放置多個畫紙,各個畫紙也就是Axes對象,畫圖就是畫在Axes對象上的。各個Axes對象都有自己的坐標軸,可以分別控制。文檔中對這幾個概念的描述在這里。其中有張圖可以很好的理解Figure與Axes的各部分。

下面都以plot畫線來介紹。

2. 顏色、標記和線型

上一節(jié)中調(diào)用plot()畫線時(plt.plot()axes.plot()),傳遞了一個參數(shù)'k--',指出畫的線為黑色虛線,這是對線的顏色和形式一種便捷的設置,這種簡便寫法中還可以加入一個標記的形式控制(也就是(x,y)點的形式)。

注意,plot()的字典參數(shù)**kwargs用于指定要畫的Line2D線對象的各種屬性。

控制格式為,注意順序不能變:
fmt = '[color][marker][line]'

如:

>>> fig, ax = plt.subplots(1,1)
# 相當于,這種顯示控制:
# ax.plot(np.random.randn(20), linestyle='-', color='r', marker='o')
>>> ax.plot(np.random.randn(20), 'ro-')

得到下圖:


fmt中的三項都是可選的,各項可配置的值可看這里的Notes部分。

但是要注意,fmt這種簡便設置方式與顯示參數(shù)的設置還是不同的。

# 只設置顏色和marker形式,則只畫點,不畫線
>>> ax.plot(np.random.randn(20), 'bo‘)
# 雖只設置顏色和marker形式,依然畫出了線
>>> ax.plot(np.random.randn(20), color='g', marker='o')

另外使用color參數(shù)設置顏色時,或fmt中只設置顏色時,可以使用更多的顏色設置方式,具體可看這里

在線型圖中,非實際的數(shù)據(jù)點默認是按照線性方式插值的。可以通過plot()的參數(shù)drawstyle來修改插值方式:

# 清除axes上的繪制
>>> ax.clear()
>>> ax.plot(np.random.randn(20), 'ko-', drawstyle='steps-post')

3. 刻度、標簽和圖例

這一節(jié)講解的就是對坐標軸的控制,包括軸標簽、軸刻度的標簽、軸刻度、軸刻度范圍、圖例。下面都是顯示指定要控制的Axes對象,使用Axes類中的方法。

先繪制一個簡單的圖像,并在其上舉例。

>>> fig, ax = plt.subplots(1,1)
>>> np.random.seed(985)
>>> ax.plot(np.random.randn(30), 'ro-')
# 設置標題
>>> ax.set_title('random plot')
# 設置xy軸標簽
>>> ax.set_xlabel('x')
>>> ax.set_ylabel('y')

對應的,可以通過Axes.get_title()Axes.get_xlabel()Axes.get_ylabel()來得到對應的值。

>>> ax.get_title()
'random plot'
>>> ax.get_xlabel()
'x'
>>> ax.get_ylabel()
'y'
  • 軸的范圍
    由于沒有指定要畫線的x值,所以默認為range(0,30),而看圖上的x軸坐標范圍,其在左右明顯要小于0并大于29,我們可以使用Axes.get_xlim()Axes.get_ylim()來分別得到x軸和y軸的坐標范圍。
>>> ax.get_xlim()
(-1.4500000000000002, 30.449999999999999)
>>> ax.get_ylim()
(-1.271508964835969, 2.6919009419421762)

可見畫圖時默認增加了些冗余,當然我們可以對其更改。

可以使用Axes.set_xlim()Axes.set_ylim()來分別設置軸的范圍:

>>> ax.set_xlim(-10, 40)

同樣也可以縮小:

>>> ax.set_xlim(10, 20)

兩次縮放了軸的范圍,與原始圖對比下可發(fā)現(xiàn),在縮放中,x坐標(只操作了x軸)刻度也在自動變化。這是因為我們沒有顯示設置x軸的坐標刻度值,所以matplotlib自動設置的。如果顯示設置了,那么會一直使用我們設置好的,不論如何縮放軸范圍。

# 接著上面執(zhí)行代碼。
>>> ax.get_xticks()
array([ 10.,  12.,  14.,  16.,  18.,  20.])
>>> ax.get_yticks()
array([-1.5, -1. , -0.5,  0. ,  0.5,  1. ,  1.5,  2. ,  2.5,  3. ])

可見也就是軸上的坐標值,同樣的可以使用Axes.set_xticks()Axes.set_yticks()來更改:

# 會返回一個列表,包含11個創(chuàng)建的XTick對象。
>>> ticks = ax.set_xticks(range(0,33,3))
可見自動按我們設置的x坐標來放大了x軸范圍

此時x軸的坐標刻度也就固定了,再放大x軸范圍也不會改變坐標刻度,而只是縮放了圖像。如:

# 設置為最初的x軸范圍
>>> ax.set_xlim(-1.4500000000000002, 30.449999999999999)
  • 軸刻度標簽的控制
    目前在x軸上有11個刻度,都是數(shù)字表示的,還可以使用Axes.set_xticklabels()將其他任何值用做標簽:
# 改為其他數(shù)值
>>> labels = ax.set_xticklabels(range(10,43,3))
# 改為字符串
>>> labels = ax.set_xticklabels([i for i in 'abcdefghijk'])
# 指定的字符串還可以為LateX數(shù)學表達式。
>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)])

此外,可以對函數(shù)Axes.set_xticklabels()的**kwargs傳入其他參數(shù)來控制Text對象的屬性。如字體角度rotation和字體大小fontsize(其他屬性可看文檔):

>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)], rotation = 30, fontsize='large')

此外,因為我們使用了Axes.set_xticks()設置了11個坐標刻度,所以在Axes.set_xticklabels()中需要傳遞長度11的列表指定這11刻度的label。如果列表長度小于11的話,如5,那么,只改變前5個刻度的label,后6個刻度的label為空,也就啥也沒有。如果列表中的元素多于11個,那么只用前11個。

>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,5)], rotation = 30, fontsize='large')
  • 圖例
    可以使用Axes.legend()在Axes中添加圖例,對繪制進行說明。

對于上面畫的紅線,現(xiàn)在加入一個圖例:

# 返回Legend對象
>>> l1 = ax.legend(['red'])

這種方法是不推薦的,因為當Axes中繪制了多條線后,需要在legend()中傳入對應著畫線順序的label,而該順序很容易搞混的。

常用的一種加入圖例方法是在畫圖是傳入label參數(shù),然后在使用legend():

>>> np.random.seed(211)
>>> ax.plot(np.random.randn(30), 'ko--', label='black')
>>> ax.legend()
這時只有一個圖例了,因為畫紅線時沒有傳入label

還用一種更為全面的控制方式,即指出需要圖例的那條線和其對應的字符串,清除掉這兩條線,重畫下:

>>> ax.clear()
>>> np.random.seed(233)
# 注意,plot()返回的是包含Line2D對象的列表,如果不加',‘,那么l1是列表。
>>> l1, = ax.plot(np.random.randn(30), 'ko-')
>>> np.random.seed(666)
>>> l2, = ax.plot(np.random.randn(30), 'ro--')
# 將Line2D對象放入第一個列表中,第二個列表中的字符串順序要一致。
>>> ax.legend([l1,l2], ['black', 'red'])

關于圖例的控制(位置、字體等),可看文檔Axes.legend()

4. 注解

  • 文本的繪制

在Axes對象中繪制文本可使用函數(shù)Axes.text()。該函數(shù)的使用很簡單,傳入坐標和文本,就會將文本繪制在對應的坐標上。可以向函數(shù)傳入Text屬性來控制文本的顯示。

>>> fig, ax = plt.subplots(1,1)
>>> x = np.linspace(-np.pi,np.pi,100, endpoint=True)
>>> y = np.sin(x)
>>> ax.plot(x,y, 'k-')  
>>> ax.set_xticks(np.arange(-np.pi,np.pi+1,np.pi/4))
# 這些tick labels本身就是Text對象。該函數(shù)會返回包含對應的9個Text對象的列表。
>>> ax.set_xticklabels([r'$-\pi$', r'$-\frac{3}{4}\pi$', r'$-\frac{1}{2}\pi$', r'$-\frac{1}{4}\pi$', r'0', r'$\frac{1}{4}\pi$', r'$\frac{1}{2}\pi$',r'$\frac{3}{4}\pi$', r'$\pi$'])
# 在原點繪制文本,后面的參數(shù)設置文本的顯示屬性。
# ha和va設置的是文本相對(0,0)的位置,‘center'是以點為中心。
>>> ax.text(0,0, r'hello world!', color='r', ha='center', va='center',rotation=30, size='medium', style = 'italic' )
  • 注釋

在圖上繪制注釋使用的是Axes.annotate)()。關于該函數(shù)的使用例子可看這里

# 在坐標(-1,0.5)處寫Text對坐標(0,0)進行注釋。
>>> ax.annotate(s=r'origin', xy=(0,0), xytext=(-1,0.5), arrowprops={'arrowstyle':'->'})

5. 保存到文件

使用plt.save()可將當前Figure中的內(nèi)容保存到文件(也可以是file-like object)中。

文件的類型可以通過給定的文件名擴展名推斷出來,或者指定函數(shù)參數(shù)format。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容