這篇筆記主要來(lái)自《利用python進(jìn)行數(shù)據(jù)分析》的第八章第一節(jié)细诸,對(duì)matplotlib的基本使用介紹的特別清晰杖刷。關(guān)于matplotlib的基本概念(figure, subplot, axes)的介紹還可以看這里王悍。
- Figure和Subplot
- 顏色趁俊、標(biāo)記和線型
- 刻度役拴、標(biāo)簽和圖例
- 注解
- 保存到文件
pyplot模塊的API文檔钝尸,這里辐赞。
1. Figure和Subplot
plt.figure()
matplotlib的圖像都位于Figure對(duì)象中部翘,可以使用plt.figure()創(chuàng)建一個(gè)新的figure:
>>> fig = plt.figure()
在ipython中,執(zhí)行后會(huì)彈出一個(gè)空窗口:
該窗口的大小可以通過(guò)在plt.figure()中傳遞參數(shù)figsize=(width,height)來(lái)指定响委。
可以看到窗口的標(biāo)題為“Figure 1”新思,要想設(shè)定Figure編號(hào)為3,則可執(zhí)行:
>>> fig = plt.figure(3)
可通過(guò)plt.gcf()來(lái)獲得最后一次創(chuàng)建的Figure對(duì)象的引用赘风。
Figure.add_subplot()
現(xiàn)在雖然有了一個(gè)Figure對(duì)象fig夹囚,但是還不能在其上畫(huà)圖。必須使用add_subplot()在fig上創(chuàng)建一個(gè)或多個(gè)subplot才行:
# 等價(jià)于fig.add_subplot(221)
# 意思是將fig劃分為2x2贝次,指定第一個(gè)為畫(huà)圖位置
# 這里的subplot從1開(kāi)始編號(hào)
# 其實(shí)就是在fig中固定位置創(chuàng)建了一個(gè)Axes對(duì)象崔兴。
>>> ax1 = fig.add_subplot(2, 2, 1)
執(zhí)行后會(huì)得到:
若接著執(zhí)行:
# 執(zhí)行后fig中就有了三個(gè)Axes對(duì)象
>>> ax2 = fig.add_subplot(2, 2, 2)
>>> ax3 = fig.add_subplot(2, 2, 3)
得到:
fig.add_subplot(2, 2, 1)并不意味著對(duì)于該fig,固定劃分了2x2個(gè)subplot蛔翅,這只是指出一個(gè)固定的位置來(lái)確定要?jiǎng)?chuàng)建的Axes對(duì)象敲茄。比如還可以接著執(zhí)行下面的代碼再創(chuàng)建個(gè)小的Axes對(duì)象:
>>> ax4 = fig.add_subplot(339)
結(jié)果為:
可以看到Figure.add_subplot()的功能是將Axes對(duì)象創(chuàng)建于規(guī)則的網(wǎng)格(grid)上的山析,如果想要在Figure中的任意位置創(chuàng)建任意大小的Axes對(duì)象可使用Figure.add_axes()堰燎。
plot()
如果這時(shí)發(fā)出一條繪圖命令,matplotlib會(huì)在最后一個(gè)用過(guò)的Axes對(duì)象上(如果沒(méi)有則自動(dòng)創(chuàng)建一個(gè))進(jìn)行繪制笋轨。
# 繪制黑色'k'虛線'--'
>>> plt.plot(np.random.randn(50).cumsum(), 'k--')
結(jié)果為:
如果想要在其他的axes中繪圖秆剪,則可以調(diào)用之前的Axes對(duì)象中的繪圖方法:
# hist方法有三個(gè)返回值,不想顯示就將其賦給以變量
>>> _ = 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()
有一條語(yǔ)句可以快速的建立Figure和一組subplots爵政,也就是plt.subplots()仅讽。它可以創(chuàng)建一個(gè)新的Figure,并返回一個(gè)含有已創(chuàng)建的Axes對(duì)象的numpy數(shù)組:
# 創(chuàng)建一個(gè)Figure對(duì)象fig2钾挟,并在其上繪制2x3個(gè)subplots
# fig2為新創(chuàng)建的Figure對(duì)象
# axess為一2x3數(shù)組洁灵,其中元素為Axes對(duì)象。
>>> fig2, axess = plt.subplots(2,3)
執(zhí)行上述語(yǔ)句掺出,會(huì)彈出一個(gè)新的Figure窗口:
之前使用plt.figure()創(chuàng)建Figure對(duì)象時(shí)苫费,可以傳遞figsize參數(shù)來(lái)指定Figure對(duì)象的大小。在plt.subplots()中也可以傳遞該參數(shù)双抽,見(jiàn)文檔中對(duì)**fig_kw參數(shù)的描述百框。
但是如果在創(chuàng)建完Figure對(duì)象后想改變figure size該怎么辦呢?可調(diào)用Figure類的方法set_figheight()和set_figweight()來(lái)分別設(shè)置Figure對(duì)象的長(zhǎng)和寬。可見(jiàn)Figure類的文檔說(shuō)明渐扮。
可以看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)
可以通過(guò)指定參數(shù)sharex=True使各列Axes對(duì)象使用同一個(gè)x軸(這樣,調(diào)整某列的xlim將會(huì)影響對(duì)應(yīng)的axes)方椎,而設(shè)置sharey=True使各行Axes對(duì)象使用同一個(gè)y軸(這樣,調(diào)整某行的ylim將會(huì)影響對(duì)應(yīng)的axes)钧嘶。
>>> plt.close(2)
>>> fig2, axess = plt.subplots(2,3, sharex=Ture, sharey=Ture)
結(jié)果為:
plt.subplots_adjust()
默認(rèn)情況下(matplotlib有默認(rèn)的配置文件)棠众,matplotlib會(huì)在subplot外圍留下一定的邊距,并在subplot之間留下一定的間距有决。利用plt.subplots_adjust()或Figure.subplots_adjust()可以修改這些間距闸拿。兩個(gè)函數(shù)的參數(shù)都是一樣的(見(jiàn)文檔),但前者是在當(dāng)前Figure中操作书幕,而后者是在指定的Figure中操作的新荤。
# 操作的是fig2
>>> plt.subplots_adjust(wspace=0, hspace=0)
結(jié)果為:
可以看到matplotlib中的畫(huà)圖是很自由的,并不會(huì)檢查坐標(biāo)的重疊台汇。
# 操作的是上面的Figure 1
>>> fig.subplots_adjust(wspace=0, hspace=0)
結(jié)果為:
當(dāng)畫(huà)完圖之后苛骨,要記得使用plt.close()關(guān)掉對(duì)應(yīng)的Figure,釋放內(nèi)存苟呐。有多種關(guān)閉方式痒芝,可看文檔。
# 關(guān)閉所有Figure牵素。
>>> plt.close('all')
總結(jié)一下严衬,Figure對(duì)象就相當(dāng)于一個(gè)巨大的畫(huà)板,可以在畫(huà)板上放置多個(gè)畫(huà)紙笆呆,各個(gè)畫(huà)紙也就是Axes對(duì)象请琳,畫(huà)圖就是畫(huà)在Axes對(duì)象上的。各個(gè)Axes對(duì)象都有自己的坐標(biāo)軸赠幕,可以分別控制俄精。文檔中對(duì)這幾個(gè)概念的描述在這里。其中有張圖可以很好的理解Figure與Axes的各部分榕堰。
下面都以plot畫(huà)線來(lái)介紹嘀倒。
2. 顏色、標(biāo)記和線型
上一節(jié)中調(diào)用plot()畫(huà)線時(shí)(plt.plot()或axes.plot()),傳遞了一個(gè)參數(shù)'k--'测蘑,指出畫(huà)的線為黑色虛線,這是對(duì)線的顏色和形式一種便捷的設(shè)置康二,這種簡(jiǎn)便寫(xiě)法中還可以加入一個(gè)標(biāo)記的形式控制(也就是(x,y)點(diǎn)的形式)碳胳。
注意,plot()的字典參數(shù)**kwargs用于指定要畫(huà)的Line2D線對(duì)象的各種屬性沫勿。
控制格式為挨约,注意順序不能變:
fmt = '[color][marker][line]'
如:
>>> fig, ax = plt.subplots(1,1)
# 相當(dāng)于,這種顯示控制:
# ax.plot(np.random.randn(20), linestyle='-', color='r', marker='o')
>>> ax.plot(np.random.randn(20), 'ro-')
得到下圖:
fmt中的三項(xiàng)都是可選的产雹,各項(xiàng)可配置的值可看這里的Notes部分诫惭。
但是要注意,fmt這種簡(jiǎn)便設(shè)置方式與顯示參數(shù)的設(shè)置還是不同的蔓挖。
# 只設(shè)置顏色和marker形式夕土,則只畫(huà)點(diǎn),不畫(huà)線
>>> ax.plot(np.random.randn(20), 'bo‘)
# 雖只設(shè)置顏色和marker形式瘟判,依然畫(huà)出了線
>>> ax.plot(np.random.randn(20), color='g', marker='o')
另外使用color參數(shù)設(shè)置顏色時(shí)怨绣,或fmt中只設(shè)置顏色時(shí),可以使用更多的顏色設(shè)置方式拷获,具體可看這里篮撑。
在線型圖中,非實(shí)際的數(shù)據(jù)點(diǎn)默認(rèn)是按照線性方式插值的匆瓜∮浚可以通過(guò)plot()的參數(shù)drawstyle來(lái)修改插值方式:
# 清除axes上的繪制
>>> ax.clear()
>>> ax.plot(np.random.randn(20), 'ko-', drawstyle='steps-post')
3. 刻度、標(biāo)簽和圖例
這一節(jié)講解的就是對(duì)坐標(biāo)軸的控制驮吱,包括軸標(biāo)簽茧妒、軸刻度的標(biāo)簽、軸刻度糠馆、軸刻度范圍嘶伟、圖例。下面都是顯示指定要控制的Axes對(duì)象又碌,使用Axes類中的方法九昧。
先繪制一個(gè)簡(jiǎn)單的圖像,并在其上舉例毕匀。
>>> fig, ax = plt.subplots(1,1)
>>> np.random.seed(985)
>>> ax.plot(np.random.randn(30), 'ro-')
- 設(shè)置該Axes對(duì)象的標(biāo)題為'random plot'铸鹰,并設(shè)置軸標(biāo)簽為'x','y'皂岔,分別使用Axes.set_title()蹋笼,Axes.set_xlabel(),Axes.set_ylabel()。
# 設(shè)置標(biāo)題
>>> ax.set_title('random plot')
# 設(shè)置xy軸標(biāo)簽
>>> ax.set_xlabel('x')
>>> ax.set_ylabel('y')
對(duì)應(yīng)的剖毯,可以通過(guò)Axes.get_title()圾笨,Axes.get_xlabel(),Axes.get_ylabel()來(lái)得到對(duì)應(yīng)的值逊谋。
>>> ax.get_title()
'random plot'
>>> ax.get_xlabel()
'x'
>>> ax.get_ylabel()
'y'
-
軸的范圍
由于沒(méi)有指定要畫(huà)線的x值擂达,所以默認(rèn)為range(0,30),而看圖上的x軸坐標(biāo)范圍胶滋,其在左右明顯要小于0并大于29板鬓,我們可以使用Axes.get_xlim()和Axes.get_ylim()來(lái)分別得到x軸和y軸的坐標(biāo)范圍。
>>> ax.get_xlim()
(-1.4500000000000002, 30.449999999999999)
>>> ax.get_ylim()
(-1.271508964835969, 2.6919009419421762)
可見(jiàn)畫(huà)圖時(shí)默認(rèn)增加了些冗余究恤,當(dāng)然我們可以對(duì)其更改俭令。
可以使用Axes.set_xlim()和Axes.set_ylim()來(lái)分別設(shè)置軸的范圍:
>>> ax.set_xlim(-10, 40)
同樣也可以縮小:
>>> ax.set_xlim(10, 20)
兩次縮放了軸的范圍部宿,與原始圖對(duì)比下可發(fā)現(xiàn)抄腔,在縮放中,x坐標(biāo)(只操作了x軸)刻度也在自動(dòng)變化窟赏。這是因?yàn)槲覀儧](méi)有顯示設(shè)置x軸的坐標(biāo)刻度值妓柜,所以matplotlib自動(dòng)設(shè)置的。如果顯示設(shè)置了涯穷,那么會(huì)一直使用我們?cè)O(shè)置好的棍掐,不論如何縮放軸范圍。
-
軸刻度的控制
刻度拷况,也就是tick作煌,可通過(guò)Axes.get_xticks()和Axes.get_yticks()來(lái)看看tick當(dāng)前的軸刻度是什么:
# 接著上面執(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. ])
可見(jiàn)也就是軸上的坐標(biāo)值赚瘦,同樣的可以使用Axes.set_xticks()和Axes.set_yticks()來(lái)更改:
# 會(huì)返回一個(gè)列表粟誓,包含11個(gè)創(chuàng)建的XTick對(duì)象。
>>> ticks = ax.set_xticks(range(0,33,3))
此時(shí)x軸的坐標(biāo)刻度也就固定了起意,再放大x軸范圍也不會(huì)改變坐標(biāo)刻度鹰服,而只是縮放了圖像。如:
# 設(shè)置為最初的x軸范圍
>>> ax.set_xlim(-1.4500000000000002, 30.449999999999999)
-
軸刻度標(biāo)簽的控制
目前在x軸上有11個(gè)刻度揽咕,都是數(shù)字表示的悲酷,還可以使用Axes.set_xticklabels()將其他任何值用做標(biāo)簽:
# 改為其他數(shù)值
>>> labels = ax.set_xticklabels(range(10,43,3))
# 改為字符串
>>> labels = ax.set_xticklabels([i for i in 'abcdefghijk'])
# 指定的字符串還可以為L(zhǎng)ateX數(shù)學(xué)表達(dá)式。
>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)])
此外亲善,可以對(duì)函數(shù)Axes.set_xticklabels()的**kwargs傳入其他參數(shù)來(lái)控制Text對(duì)象的屬性设易。如字體角度rotation和字體大小fontsize(其他屬性可看文檔):
>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)], rotation = 30, fontsize='large')
此外,因?yàn)槲覀兪褂昧薃xes.set_xticks()設(shè)置了11個(gè)坐標(biāo)刻度蛹头,所以在Axes.set_xticklabels()中需要傳遞長(zhǎng)度11的列表指定這11刻度的label顿肺。如果列表長(zhǎng)度小于11的話戏溺,如5,那么屠尊,只改變前5個(gè)刻度的label旷祸,后6個(gè)刻度的label為空,也就啥也沒(méi)有讼昆。如果列表中的元素多于11個(gè)肋僧,那么只用前11個(gè)。
>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,5)], rotation = 30, fontsize='large')
-
圖例
可以使用Axes.legend()在Axes中添加圖例控淡,對(duì)繪制進(jìn)行說(shuō)明。
對(duì)于上面畫(huà)的紅線止潘,現(xiàn)在加入一個(gè)圖例:
# 返回Legend對(duì)象
>>> l1 = ax.legend(['red'])
這種方法是不推薦的掺炭,因?yàn)楫?dāng)Axes中繪制了多條線后,需要在legend()中傳入對(duì)應(yīng)著畫(huà)線順序的label凭戴,而該順序很容易搞混的涧狮。
常用的一種加入圖例方法是在畫(huà)圖是傳入label參數(shù),然后在使用legend():
>>> np.random.seed(211)
>>> ax.plot(np.random.randn(30), 'ko--', label='black')
>>> ax.legend()
還用一種更為全面的控制方式者冤,即指出需要圖例的那條線和其對(duì)應(yīng)的字符串,清除掉這兩條線档痪,重畫(huà)下:
>>> ax.clear()
>>> np.random.seed(233)
# 注意涉枫,plot()返回的是包含Line2D對(duì)象的列表,如果不加',‘腐螟,那么l1是列表愿汰。
>>> l1, = ax.plot(np.random.randn(30), 'ko-')
>>> np.random.seed(666)
>>> l2, = ax.plot(np.random.randn(30), 'ro--')
# 將Line2D對(duì)象放入第一個(gè)列表中,第二個(gè)列表中的字符串順序要一致乐纸。
>>> ax.legend([l1,l2], ['black', 'red'])
關(guān)于圖例的控制(位置衬廷、字體等),可看文檔Axes.legend()汽绢。
4. 注解
- 文本的繪制
在Axes對(duì)象中繪制文本可使用函數(shù)Axes.text()吗跋。該函數(shù)的使用很簡(jiǎn)單,傳入坐標(biāo)和文本宁昭,就會(huì)將文本繪制在對(duì)應(yīng)的坐標(biāo)上跌宛。可以向函數(shù)傳入Text屬性來(lái)控制文本的顯示久窟。
>>> 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對(duì)象秩冈。該函數(shù)會(huì)返回包含對(duì)應(yīng)的9個(gè)Text對(duì)象的列表。
>>> 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$'])
# 在原點(diǎn)繪制文本斥扛,后面的參數(shù)設(shè)置文本的顯示屬性入问。
# ha和va設(shè)置的是文本相對(duì)(0,0)的位置丹锹,‘center'是以點(diǎn)為中心。
>>> ax.text(0,0, r'hello world!', color='r', ha='center', va='center',rotation=30, size='medium', style = 'italic' )
- 注釋
在圖上繪制注釋使用的是Axes.annotate)()芬失。關(guān)于該函數(shù)的使用例子可看這里楣黍。
# 在坐標(biāo)(-1,0.5)處寫(xiě)Text對(duì)坐標(biāo)(0,0)進(jìn)行注釋。
>>> ax.annotate(s=r'origin', xy=(0,0), xytext=(-1,0.5), arrowprops={'arrowstyle':'->'})
5. 保存到文件
使用plt.save()可將當(dāng)前Figure中的內(nèi)容保存到文件(也可以是file-like object)中棱烂。
文件的類型可以通過(guò)給定的文件名擴(kuò)展名推斷出來(lái)租漂,或者指定函數(shù)參數(shù)format。