《利用Python進行數(shù)據(jù)分析》第8章 繪圖和可視化筆記

matplotlib繪圖和可視化

matplotlib是一個用于創(chuàng)建出版質(zhì)量圖表的桌面繪圖包(主要是2D方面)。繪圖是數(shù)據(jù)分析工作中最重要的任務之一,是探索過程的一部分。

import matplotlib.pyplot as plt
from pandas import Series,DataFrame
import pandas as pd
import numpy as np
from numpy.random import randn
plt.plot(np.arange(15))
plt.show()

Figure和Subplot

fig=plt.figure()
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--')

"k--"是一個線型選項,用于告訴matplotlib繪制黑色虛線圖。上面那些由fig.add_subplot所返回的對象是AxesSubplot對象,直接調(diào)用它們的實例方法就可以在其他空著的格子里面畫圖

_=ax1.hist(np.random.randn(100),bins=20,color='r',alpha=0.3)
ax2.scatter(np.arange(30),np.arange(30)+3*np.random.randn(30))
plt.show()

plt.subplots,它可以創(chuàng)建一個新的Figure,并返回一個含有已創(chuàng)建的subplot對象的NumPy數(shù)組

fig,axes=plt.subplots(2,3)
axes
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x0000000012981F98>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x0000000012835FD0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x00000000129EAFD0>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x000000001298C9B0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x00000000127EDA20>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x00000000125DBEB8>]], dtype=object)

調(diào)整subplot周圍的間距

Figure的subplots_adjust方法可以修改間距

#subplots_adjust(left=None,bottom=None,right=None,top=None,wpace=None,hspace=None)
fig,axes=plt.subplots(2,2,sharex=True,sharey=True)
for i in range(2):
    for j in range(2):
        axes[i,j].hist(randn(500),bins=50,color='k',alpha=0.6)
        
plt.subplots_adjust(wspace=0,hspace=0)
plt.show()

顏色、標記和線型

matplotlib的plot函數(shù)接受一組X和Y坐標,還可以接受一個表示顏色和線型的字符串縮寫

ax.plot(x,y,'g--')  #根據(jù)x和y繪制綠色虛線
ax.plot(x,y,linestyle='--',color='g')
plt.plot(np.random.randn(30).cumsum(),'ko--')
plt.show()

可以把它寫成更為明確的方式

plt.plot(np.random.randn(30).cumsum(),color='b',linestyle='dashed',marker='o')
plt.show()
帶有標記的線型圖示例

在線型圖中,非實際數(shù)據(jù)點默認是按線性方式插值的??梢酝ㄟ^drawstyle選項修改

data=np.random.randn(30).cumsum()
plt.plot(data,'k--',label='Default')
plt.show()
plt.plot(data,'k-',color='b',drawstyle='steps-post',label='steps-post')
plt.show()
plt.plot(data,'k-',color='b',drawstyle='steps-post',label='steps-post')
plt.legend(loc='best')
plt.show()

刻度、標簽和圖例

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

創(chuàng)建一個簡單的圖像并繪制一段隨機漫步

fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
plt.show()
演示xticks的簡單線型圖

可以使用set_xticks和set_xticklabels修改X軸的刻度

fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())

#用set_xticks修改X軸的刻度
ticks=ax.set_xticks([0,250,500,750,1000])
#可以通過set_xticklabels將任何其他的值用作標簽
labels=ax.set_xticklabels(['one','two','three','four','five'],rotation=30,fontsize='small')
#用set_title給圖表設置一個標題
ax.set_title('My first matplotlib plot')
#為X軸設置一個名稱
ax.set_xlabel('Stages')
plt.show()

添加圖例(legend)

在添加subplot的時候傳入label參數(shù)來添加圖例

fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum(),'k',label='one',color='r')
ax.plot(np.random.randn(1000).cumsum(),'k--',label='two',color='g')
ax.plot(np.random.randn(1000).cumsum(),'k.',label='three',color='b')
ax.legend(loc='best')
plt.show()

調(diào)用ax.legend()或plt.legend()來自動創(chuàng)建圖例

loc告訴matplotlib要將圖例放在哪,'beat'里面可以顯示確定的位置,如下:
best
upper right
upper left
lower left
lower right
right
center left
center right
lower center
upper center
center

如果要從圖例中去除一個或多個元素,不傳入label或傳入label='nolegend'

注解以及在Subplot上繪圖

注解可以是文本、箭頭或其他圖形等,通過text、arrow和annotate等函數(shù)進行添加。text可以將文本繪制在圖表的指定坐標(x,y),還可以加上一些自定義格式

ax.text(x,y,"hello world!",Family='monospace',fontsize=10)

例如,我們根據(jù)2007年以來的標準普爾500指數(shù)收盤價格(來自Yahoo!Finance)繪制一張曲線圖,并標出2008年到2009年金融危機期間的一些重要日期。結(jié)果如下圖所示

from datetime import datetime
import pandas as pd
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
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:
    ax.annotate(label,xy=(date,spx.asof(date)+50),
                xytext=(date,spx.asof(date)+200),
                arrowprops=dict(facecolor='black'),
                horizontalalignment='left',verticalalignment='top')
    
# 放大到2007-2010
ax.set_xlim(['1/1/2007','1/1/2011'])
ax.set_ylim([600,1800])
ax.set_title('Important dates in 2008-2009 financial crisis')
plt.show()
圖2008-2009年金融危機期間的重要日期

要在圖表中添加一個圖形,你需要創(chuàng)建一個塊對象shp,然后通過ax.add_patch(shp)將其添加到subplot中

fig=plt.figure()
ax=fig.add_subplot(1,1,1)

rect=plt.Rectangle((0.2,0.75),0.4,0.15,color='r',alpha=0.6)
circ=plt.Circle((0.7,0.2),0.15,color='b',alpha=0.3)
pgon=plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color='g',alpha=0.5)
ax.add_patch(rect)
ax.add_patch(circ)
ax.add_patch(pgon)
plt.show()

將圖表保存到文件

利用plt.savefig可以將當前圖表保存到文件。該方法相當于Figure對象的實例方法savefig

plt.savefig('figpath.svg')

在發(fā)布圖片時最常用到兩個重要的選項是dpi(控制“每英寸點數(shù)”分辨率)和bbox_inches(可以剪除當前圖表周圍的空白部分)。要得到一張帶有最小白邊且分辨率為400DPI的PNG圖片可以這樣做:

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

savefig并非一定要寫入磁盤,也可以寫入任何文件型的對象,比如StringIO。其中,這個在Web上提供動態(tài)生成的圖片是很實用

from io import StringIO
plt.savefig(buffer)
plot_data=buffer.getvaule()

matplotlib配置

matplotlib自帶一些配色方案,以及為生成出版質(zhì)量的圖片而設定的默認配置信息,可以管理圖像大小、subplot邊距、配色方案、字體大小、網(wǎng)格類型等。操作matplotlib配置系統(tǒng)的方式主要有兩種。第一種是Python編程方式,即利用rc方法

將全局的圖像默認大小設置為10×10

plt.rc('figure',figsize=(10,10))

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

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

pandas中的繪圖函數(shù)

pandas在線文檔將會是最好的繪圖函數(shù)學習資源。

線型圖

Series對象的索引會被傳給matplotlib,并用以繪制X軸。可以通過use_index=False禁用該功能。
X軸的刻度和界限可以通過xticks和xlim選項進行調(diào)節(jié),Y軸就用yticks和ylim

s=Series(np.random.randn(10).cumsum(),index=np.arange(0,100,10))
s.plot()
plt.show()

pandas的大部分繪圖方法都有一個可選的ax參數(shù),它可以是一個matplotlib的subplot對象。這使你能夠在網(wǎng)格布局中更為靈活地處理subplot的位置。
DataFrame的plot方法會在一個subplot中為各列繪制一條線,并自動創(chuàng)建圖例。

df=DataFrame(np.random.randn(10,4).cumsum(0),columns=['A','B','C','D'],index=np.arange(0,100,10))
df.plot()
plt.show()

注意: plot的其他關鍵字參數(shù)會被傳給相應的matplotlib繪圖函數(shù),所以要更深入地自定義圖表,就必須學習更多有關matplotlib API的知識。

柱狀圖

在生成線型圖的代碼中加上kind='bar'(垂直柱狀圖)或kind='barh'(水平柱狀圖)即可生成柱狀圖。這時,Series和DataFrame的索引將會被用作X(bar)或Y(barh)刻度

fig,axes=plt.subplots(2,1)
data=Series(np.random.rand(16),index=list('abcdefghijklmnop'))
data.plot(kind='bar',ax=axes[0],color='g',alpha=0.6)
data.plot(kind='barh',ax=axes[1],color='g',alpha=0.6)
plt.show()

對于DataFrame,柱狀圖會將每一行的值分為一組

df=DataFrame(np.random.rand(6,4),index=['one','two','three','four','five','six'],columns=['A','B','C','D'])
df
A B C D
one 0.381932 0.042627 0.290334 0.700356
two 0.212308 0.519060 0.241667 0.653755
three 0.223746 0.233344 0.714892 0.620117
four 0.401946 0.862935 0.874891 0.862926
five 0.680490 0.879683 0.562349 0.036203
six 0.791145 0.873458 0.604575 0.479191
df.plot(kind='bar')
plt.show()

DataFrame各列的名稱"Genus"被用作了圖例的標題。設置stacked=True即可為DataFrame生成堆積柱狀圖,這樣每行的值就會被堆積在一起

提示:柱狀圖有一個非常不錯的用法:利用value_counts圖形化顯示Series中各值的出現(xiàn)頻率,比如s.value_counts ().plot(kind='bar')。

df.plot(kind='barh',stacked=True,alpha=0.8)
plt.show()

以本書的有關小費的數(shù)據(jù)集為例,假設我們想要做一張堆積柱狀圖以展示每天各種聚會規(guī)模的數(shù)據(jù)點的百分比。我用read_csv將數(shù)據(jù)加載進來,然后根據(jù)日期和聚會規(guī)模創(chuàng)建一張交叉表

tips=pd.read_csv('examples/tips.csv')
#如果通過tips.size,取到的是一整列的和
party_counts=pd.crosstab(tips.day,tips['size'])
party_counts
size 1 2 3 4 5 6
day
Fri 1 16 1 1 0 0
Sat 2 53 18 13 1 0
Sun 0 39 15 18 3 1
Thur 1 48 4 5 1 3

進行規(guī)格化,使得各行的和為1(必須轉(zhuǎn)換成浮點數(shù)),并生成圖表

party_counts=party_counts.ix[:,2:5]# 1個人和6個人的聚會都比較少
party_pcts=party_counts.div(party_counts.sum(1).astype(float),axis=0)
party_pcts
size 2 3 4 5
day
Fri 0.888889 0.055556 0.055556 0.000000
Sat 0.623529 0.211765 0.152941 0.011765
Sun 0.520000 0.200000 0.240000 0.040000
Thur 0.827586 0.068966 0.086207 0.017241

通過該數(shù)據(jù)集就可以看出,聚會規(guī)模在周末會變大

直方圖和密度圖

直方圖(histogram)是一種可以對值頻率進行離散化顯示的柱狀圖。數(shù)據(jù)點被拆分到離散的、間隔均勻的面元中,繪制的是各面元中數(shù)據(jù)點的數(shù)量

以前面那個小費數(shù)據(jù)為例,通過Series的hist方法,我們可以生成一張“小費占消費總額百分比”的直方圖

tips['tip_pct']=tips['tip']/tips['total_bill']
tips['tip_pct'].hist(bins=50)
plt.show()
小費百分比的直方圖

與此相關的一種圖表類型是密度圖,它是通過計算“可能會產(chǎn)生觀測數(shù)據(jù)的連續(xù)概率分布的估計”而產(chǎn)生的。一般的過程是將該分布近似為一組核(即諸如正態(tài)(高斯)分布之類的較為簡單的分布)。

調(diào)用plot時加上kind='kde'即可生成一張密度圖(標準混合正態(tài)分布KDE)

tips['tip_pct'].plot(kind='kde')
plt.show()
小費百分比的密度圖

這兩種圖表常常會被畫在一起。直方圖以規(guī)格化形式給出(以便給出面元化密度),然后再在其上繪制核密度估計。接下來來看一個由兩個不同的標準正態(tài)分布組成的雙峰分布

comp1=np.random.normal(0,1,size=200)#N(0,1)
comp2=np.random.normal(10,2,size=200)# (10,4)
values=Series(np.concatenate([comp1,comp2]))
values.hist(bins=100,alpha=0.3,color='g',normed=True)
values.plot(kind='kde',style='k--')
plt.show()

散布圖

散布圖(scatter plot)是觀察兩個一維數(shù)據(jù)序列之間的關系的有效手段。matplotlib的scatter方法是繪制散布圖的主要方法

通過例子看看,首先加載了來自statsmodels項目的macrodata數(shù)據(jù)集,選擇其中幾列,然后計算對數(shù)差

macro=pd.read_csv('examples/macrodata.csv')
data=macro[['cpi','m1','tbilrate','unemp']]
trans_data=np.log(data).diff().dropna()
trans_data[-5:]
cpi m1 tbilrate unemp
198 -0.007904 0.045361 -0.396881 0.105361
199 -0.021979 0.066753 -2.277267 0.139762
200 0.002340 0.010286 0.606136 0.160343
201 0.008419 0.037461 -0.200671 0.127339
202 0.008894 0.012202 -0.405465 0.042560

利用plt.scatter即可輕松繪制一張簡單的散布圖

plt.scatter(trans_data['m1'],trans_data['unemp'])
plt.title('Cahnges in log %s vs. log %s '%('m1','unemp'))
plt.show()

散布圖矩陣(scatter plot matrix)。
pandas提供了一個能從DataFrame創(chuàng)建散布圖矩陣的scatter_matrix函數(shù)。它還支持在對角線上放置各變量的直方圖或密度圖

pd.scatter_matrix(trans_data,diagonal='kde',alpha=0.3)
plt.show()
e:\python\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: pandas.scatter_matrix is deprecated. Use pandas.plotting.scatter_matrix instead
  """Entry point for launching an IPython kernel.

通過練習python matplotlib可視化的知識,學習到對數(shù)據(jù)繪圖的基礎知識,了解到matplotlib其他的繪圖接口 seaborn和 ggplot。
完善并深入練習還是需要去官方網(wǎng)站去查看相關的用法。
有興趣可以去官網(wǎng)查看手冊:https://matplotlib.org/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容