python3繪圖和可視化(一)


      繪圖是數據分析工作中最重要的任務之一,是探索過程的一部分。python有許多可視化工具,下面主要學習matplotlib

matplotlib是一個用於創建出版質量圖表的桌面繪圖包(主要是2D方面)。該項目是由John Hunter於2002年啟動的,其目的是為了python構建一個MATLAB式的繪圖接口。如果結合使用一種GUI工具包(如IPython),matplotlib還具有諸如縮放和平移等交互功能。它不僅支持各種操作系統上許多不同的GUI后端,而且還能將圖片導出為各種常見的矢量(vector)和光柵(raster)圖:PDF、SVG、JPG、PNG、BMP、GIF等。

要使用文中的代碼實例,要確保我們的IPython是以Pylab模式啟動的(ipython --pylab),或通過%gui魔術命令打開了GUI事件循環集成。

一.matplotlib API入門

使用matplotlib的方法有很多種,最常用的方式是Pylab模式的IPython(ipython --pylab)。這樣會將IPython配置為使用我們所指定的matplotlib GUI后端(Tk、wxPython、PyQt、Mac OS X native、GTK).對大部分用戶而言,默認的后端就已經夠用了。Pylab模式還會向IPython引入一大堆模塊和函數以提供一種更接近於MATLAB的界面。繪制一張簡單的圖表即可測試是否一切准備就緒:

In [1]: plot(np.arange(10))
Out[1]: [<matplotlib.lines.Line2D at 0xfb13518>]

 

matplotlib API函數(如plot和close)都位於matplotlib.pyplot模塊中,其通常的引入約定是:

import matplotlib.pyplot as plt

雖然pandas的繪圖函數能夠處理許多普通的繪圖任務,但如果需要自定義一些高級功能的話就必須學習matplotlib API。

1.Figure和Support

matplotlib的圖像都位於Figure對象中。我們可以用plt.figure創建一個新的Figure:

In [4]: fig=plt.figure()  

這時會彈出一個空窗口(不要關閉空窗口)。plt.figure有一些選項,特別是figsize,它用於確保當圖片保存到磁盤時具有一定的大小和縱橫比。matplotlib中的Figure還支持一種MATLAB式的編號架構(例如plt.figure(2))。通過plt.gcf()即可得到當前Figure的引用。

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

In [5]: ax1=fig.add_subplot(2,2,1)

這條代碼的意思是:圖像應該是2X2的,且當前選中的是4個subplot中的第一個(編號從1開始)。如果再把后面兩個subplot也創建出來,最終得到的圖像如下圖所示:

In [6]: ax2=fig.add_subplot(2,2,2)

In [7]: ax3=fig.add_subplot(2,2,3)

 

如果這時發出一條繪圖命令(如plt.plot([1.8,3.8,-6,1.9])),matplotlib就會在最后一個用過的subplot(如果沒有則創建一個)上進行繪制。因此,如果我們執行下列命令,我們就會得到如下圖所示的結果:

In [12]: from numpy.random import randn

In [13]: plt.plot(randn(50).cumsum(),'k--')
Out[13]: [<matplotlib.lines.Line2D at 0xd8e6ef0>]

 

"k--"是一個線性選項,用於告訴matplotlib繪制黑色虛線圖。上面那些由fig.add_subplot所返回的對象是AxesSubplot對象,直接調用它們的實例方法就可以在其他空着的格子里面畫圖了,如下圖所示:

我們可以在matplotlib的文檔中找到各種圖表類型。由於根據特定布局創建Figure和subplot是一件非常常見的任務,於是便出現了一個更為方便的方法(plt.subplots),它可以創建一個新的Figure,並返回一個含有已創建的subplot對象的NumPy數組:

In [10]: fig,axes=plt.subplots(2,3)

 

 

In [11]: axes
Out[11]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D6C47F0>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D8172E8>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D83C860>],
[<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D864DD8>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D925390>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D94E1D0>]],
dtype=object)

 這是非常實用的,因為可以輕松地對axes數組進行索引,就好像是一個二維數組一樣,例如,axes[0,1]。我們還可以通過sharex和sharey指定subplot應該具有相同的X軸或Y軸。在比較相同范圍的數據時,這也是非常實用的,否則,matplotlib會自動縮放各圖表的界限。有關該方法的更多信息,參見下表

參數                   說明

nrows           subplot的行數

ncols             subplot的列數

sharex           所有subplot應該使用相同的X軸刻度(調節xlim將會影響所有subplot)

sharey           所有subplot應該使用相同的Y軸刻度(調節ylim將會影響所有subplot)

subplot_kw    用於創建各subplot的關鍵字字典

**fig_kw         創建figure時的其他關鍵字,如plt.subplots(2,2,figsize=(8,6))
 

調整subplot周圍的間距

默認情況下,matplotlib會在subplot外圍留下一定的邊距,並在subplot之間留下一定的間距。間距跟圖像的高度和寬度有關,因此,如果我們調整了圖像大小(不管是編程還是手工),間距也會自動調整。利用Figure的subplots_adjust方法可以輕而易舉地修改間距,此外,它也是個頂級函數:

subplot_adjust(left=None,bottom=None,right=None,top=None,wspace=None,hspace=None)

wspace和hspace用於控制寬度和高度的百分比,可以用作subplot之間的間距。下面是一個簡單的例子,其中將間距收縮到0,如下圖所示:

In [1]: import matplotlib.pyplot as plt

In [2]: fig=plt.figure()

In [3]: ax1=fig.add_subplot(2,2,2)

In [4]: ax2=fig.add_subplot(2,2,3)

In [5]: from numpy.random import randn

In [6]: fig,axes=plt.subplots(2,2,sharex=True,sharey=True)

In [7]: for i in range(2):
...: for j in range(2):
...: axes[i,j].hist(randn(500),bins=50,color='k',alpha=0.5)
...:

In [8]: plt.subplots_adjust(wspace=0,hspace=0)

不難看出,其中的軸標簽重疊了。matplotlib不會檢查標簽是否重疊,所以對於這樣情況,我們只能自己設定刻度位置和刻度標簽。后面將會詳細介紹該內容。

顏色、標記和線型

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

ax.plot(x,y,'g--')

這種在一個字符串中指定顏色和線型的方式非常方便。通過下面這種更為明確的方式也能得到同樣的效果:

ax.plot(x,y,linestyle='--',color='g')

常用的顏色都有一個縮寫詞,要使用其他任意顏色則可以通過指定其RGB值的形式使用(例如,‘#CECECE’)。

線型圖還可以加一些標記(marker),以強調實際的數據點。由於matplotlib創建的是連續的線型圖(點與點之間插值),因此有時可能不太容易看出真實數據點的位置。標記也可以放到格式字符串中,但標記類型和線型必須放在顏色后面:

In [24]: plt.plot(randn(30).cumsum(),'ko--')
Out[24]: [<matplotlib.lines.Line2D at 0x105ce208>]

還可以將其寫成更為明確的形式:

In [25]: plot(randn(30).cumsum(),color='k',linestyle='dashed',marker='o')
Out[25]: [<matplotlib.lines.Line2D at 0x10608278>]

在線型圖中,非實際數據點默認是按線性方式插值的。可以通過drawstyle選項修改:

In [26]: data=randn(30).cumsum()

In [27]: plt.plot(data,'k--',label='Default')
Out[27]: [<matplotlib.lines.Line2D at 0x107c20f0>]

In [29]: plt.plot(data,'k--',drawstyle='steps-post',label='steps-post')
Out[29]: [<matplotlib.lines.Line2D at 0x107d9ac8>]

In [31]: plt.legend(loc='best')
No handles with labels found to put in legend.
Out[31]: <matplotlib.legend.Legend at 0x10d2f080>

刻度、標簽和圖例

對於大多數的圖表裝飾項,其主要實現方式有二:使用過程型的pyplot接口(MATLAB用戶非常熟悉)以及更為面向對象的原生matplotlib API。

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

(1)調用時不帶參數,則返回當前的參數值。例如,plt.xlim()返回當前的X軸繪圖范圍。

(2)調用時帶參數,則設置參數值。因此,plt.xlim([0,10])會將X軸的范圍設置為0到10。

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

 

設置標題、軸標簽、刻度以及刻度標簽

為了說明軸的自定義,我們將創建一個簡單的圖像並繪制一段隨機漫步:

In [34]: fig=plt.figure()

In [35]: ax=fig.add_subplot(1,1,1)

In [36]: ax.plot(randn(1000).cumsum())
Out[36]: [<matplotlib.lines.Line2D at 0x108361d0>]

要修改X軸的刻度,最簡單的辦法是使用set_xticks和set_xticklabels。前者告訴matplotlib要將刻度放在數據范圍中的哪些位置,默認情況下,這些位置也就是刻度標簽。但我們可以通過set_xticklabels將任何其他的值用作標簽:

In [37]: ticks=ax.set_xticks([0,250,500,750,1000])

In [38]: labels=ax.set_xticklabels(['one','two','three','four','five'],rotation
...: =30,fontsize='small')

最后,再用set_xlabel為X軸設置一個名稱,並用set_title設置一個標題:

In [6]: ax.set_title('My first matplotlib plot')
Out[6]: Text(0.5, 1.0, 'My first matplotlib plot')

In [7]: ax.set_xlabel('Stages')
Out[7]: Text(0.5, 10.763891973024519, 'Stages')

最終的結果如下圖所示。Y軸的修改方式與此類似,只需將上述代碼中的x替換為y即可。

添加圖例 

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

In [9]: fig=plt.figure();ax=fig.add_subplot(1,1,1)

In [10]: ax.plot(randn(1000).cumsum(),'k',label='one')
Out[10]: [<matplotlib.lines.Line2D at 0xd638320>]

In [11]: ax.plot(randn(1000).cumsum(),'k--',label='two')
Out[11]: [<matplotlib.lines.Line2D at 0xd663128>]

In [12]: ax.plot(randn(1000).cumsum(),'k.',label='three')
Out[12]: [<matplotlib.lines.Line2D at 0xd6a2208>]

在此之后,我們可以調用ax.legend()或plt.legend()來自動創建圖例:

In [13]: ax.legend(loc='best')
Out[13]: <matplotlib.legend.Legend at 0xd6f52e8>

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

 注解以及在subplot上繪圖

除標准的圖表對象之外,我們可能還希望繪制一些自定義的注解(比如文本、箭頭或其他圖形等)。注解可以通過text、arrow和annotate等函數進行添加。text可以將文本繪制在圖表的指定坐標(x,y),還可以加上一些自定義格式:

ax.text(x,y,'Hello world!'.family='monospace',fontsize=10)

注解中可以既含有文本也含有箭頭。例如,我們用箭頭和文本注解如下圖的波浪線

In [1]: import matplotlib.pyplot as plt

In [2]: fig=plt.figure()

In [3]: ax=fig.add_subplot()

In [4]: ax=fig.add_subplot(1,1,1)

In [5]: import numpy as np

In [7]: t=np.arange(0,5,0.01)

In [9]: s=np.cos(2*np.pi*t)

In [10]: line,=ax.plot(t,s,lw=2)

In [11]: ax.annotate('local max',xy=(2,1),xytext=(3,1.5),arrowprops=dict(faceco
...: lor='black',shrink=0.05),)
Out[11]: Text(3, 1.5, 'local max')

In [13]: ax.set_ylim(-2,2)
Out[13]: (-2, 2)

 

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

要在圖表中添加一個圖形,我們需要創建一個塊對象shp,然后通過ax.add_patch(shp)將其添加到subplot中(如下圖所示):

In [26]: fig=plt.figure()

In [27]: ax=fig.add_subplot(1,1,1)

In [28]: rect=plt.Rectangle((0.2,0.75),0.8,0.25,color='k',alpha=0.3)

In [29]: circ=plt.Circle((0.7,0.2),0.1,color='b',alpha=0.3)

In [30]: pgon=plt.Polygon([[0.15,0.15],[0.35,0.6],[0.2,0.8]],color='g',alpha=0.
...: 5)

In [31]: ax.add_patch(rect)
Out[31]: <matplotlib.patches.Rectangle at 0xdb339b0>

In [32]: ax.add_patch(circ)
Out[32]: <matplotlib.patches.Circle at 0xdb33780>

In [33]: ax.add_patch(pgon)
Out[33]: <matplotlib.patches.Polygon at 0xda5c828>

如果查看許多常見圖表對象的具體實現代碼,我們就會發現它們其實就是由塊組裝而成的。

 將圖表保存到文件

利用plt.savefig可以將當前圖表保存到文件。該方法相當於Figure對象的實例方法savefig。例如,要將圖表保存為SVG文件,我們只需輸入:

plt.savefig('figpath.svg')

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

plt.savefig('figpath.png',dpi=400,bbox_inches='tight')

savefig並非一定要寫入磁盤,也可以寫入任何文件型的對象,比如StringIO:

from io import StringIO

buffer=StringIO()

plt.savefig(buffer)

plot_data=buffer.getvalue()

這對在Web上提供動態生成的圖片是很實用的。

Figure.savefig方法的部分參數及說明如下表所示:

參數                            說明

fname              含有文件路徑的字符串或Python的文件型對象。圖像格式由文件擴展名推斷得出,例如,.pdf推斷出PDF,.png推斷出PNG

dpi                 圖像分辨率(每英寸點數),默認為100

facecolor、edgecolor  圖像的背景色,默認為“w”(白色)

format          顯式設置文件格式(“png”、”pdf”、“svg”、“ps”、“eps”......)

bbox_inches  圖表需要保存的部分。如果設置為“tight”,則將嘗試剪除圖表周圍的空白部分

matplotlib配置

matplotlib自帶一些配色方案,以及為生成出版質量的圖片而設定的默認配置信息。幸運的是,幾乎所有默認行為都能通過一組全局參數進行自定義,它們可以管理圖像大小、subplot邊距、配色方案、字體大小、網格類型等。操作matplotlib配置系統的方式主要有兩種。第一種是Python編程方式,即利用rc方法。比如說,要將全局的圖像默認大小設置為10X10,我們可以執行:

 plt.rc('lines',linewidth=10)

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

font_options={'family':'monospace',

                        'weight':'bold',

                        'size':'small'}

plt.rc('font',**font_options)

要了解全部的自定義選項,查閱https://matplotlib.org/api/_as_gen/matplotlib.pyplot.rc.html?highlight=rc#matplotlib.pyplot.rc。如果對該文件進行了自定義,並將其放在自己的.matplotlib目錄中,則每次使用matplotlib時就會加載該文件。

例子,繪出地球的兩極

In [1]: import matplotlib.pylab as plt

In [2]: import numpy as np

#自定義圖像

In [3]: plt.rc('grid',color='#316931',linewidth=1,linestyle='-')

In [4]: plt.rc('xtick',labelsize=15)

In [5]: plt.rc('ytick',labelsize=15)

#繪出一個圖像

In [6]: fig=plt.figure(figsize=(8,8))

#在上面圖像上繪出兩極圖形

In [7]: ax=fig.add_axes([0.1,0.1,0.8,0.8],projection='polar',facecolor='#d5de9c
...: ')

#兩極上繪出兩條線

In [8]: r=np.arange(0,3.0,0.01)

In [9]: theta=2*np.pi*r

In [10]: ax.plot(theta,r,color='#ee8d18',lw=3,label='a line')
Out[10]: [<matplotlib.lines.Line2D at 0xfb00da0>]

In [11]: ax.plot(0.5*theta,r,color='blue',ls='--',lw=3,label='another line')
Out[11]: [<matplotlib.lines.Line2D at 0xfb4c080>]

In [12]: ax.legend()
Out[12]: <matplotlib.legend.Legend at 0xfb58630>

In [13]: plt.show()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM