matplotlib繪圖和可視化
matplotlib是一個用於創建出版質量圖表的桌面繪圖包(主要是2D方面)。繪圖是數據分析工作中最重要的任務之一,是探索過程的一部分。
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對象,直接調用它們的實例方法就可以在其他空着的格子裏面畫圖
_=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,它可以創建一個新的Figure,並返回一個含有已創建的subplot對象的NumPy數組
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)
調整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函數接受一組X和Y座標,還可以接受一個表示顏色和線型的字符串縮寫
ax.plot(x,y,'g--') #根據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()
在線型圖中,非實際數據點默認是按線性方式插值的。可以通過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()
刻度、標籤和圖例
設置標題、軸標籤、刻度以及刻度標籤
創建一個簡單的圖像並繪製一段隨機漫步
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
plt.show()
可以使用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參數來添加圖例
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()
調用ax.legend()或plt.legend()來自動創建圖例
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等函數進行添加。text可以將文本繪製在圖表的指定座標(x,y),還可以加上一些自定義格式
ax.text(x,y,"hello world!",Family='monospace',fontsize=10)
例如,我們根據2007年以來的標準普爾500指數收盤價格(來自Yahoo!Finance)繪製一張曲線圖,並標出2008年到2009年金融危機期間的一些重要日期。結果如下圖所示
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年金融危機期間的重要日期
要在圖表中添加一個圖形,你需要創建一個塊對象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')
在發佈圖片時最常用到兩個重要的選項是dpi(控制“每英寸點數”分辨率)和bbox_inches(可以剪除當前圖表周圍的空白部分)。要得到一張帶有最小白邊且分辨率爲400DPI的PNG圖片可以這樣做:
plt.savefig('figpath.png',dpi=400,bbox_inches='tight')
savefig並非一定要寫入磁盤,也可以寫入任何文件型的對象,比如StringIO。其中,這個在Web上提供動態生成的圖片是很實用
from io import StringIO
plt.savefig(buffer)
plot_data=buffer.getvaule()
matplotlib配置
matplotlib自帶一些配色方案,以及爲生成出版質量的圖片而設定的默認配置信息,可以管理圖像大小、subplot邊距、配色方案、字體大小、網格類型等。操作matplotlib配置系統的方式主要有兩種。第一種是Python編程方式,即利用rc方法
將全局的圖像默認大小設置爲10×10
plt.rc('figure',figsize=(10,10))
rc的第一個參數是希望自定義的對象,如’figure’、’axes’、’xtick’、’ytick’、’grid’、’legend’等。其後可以跟上一系列的關鍵字參數。最簡單的辦法是將這些選項寫成一個字典
font_opinions={'family':'monospace','weight':'bold','size':'samll'}
plt.rc('font',**font_options)
pandas中的繪圖函數
pandas在線文檔將會是最好的繪圖函數學習資源。
線型圖
Series對象的索引會被傳給matplotlib,並用以繪製X軸。可以通過use_index=False禁用該功能。
X軸的刻度和界限可以通過xticks和xlim選項進行調節,Y軸就用yticks和ylim
s=Series(np.random.randn(10).cumsum(),index=np.arange(0,100,10))
s.plot()
plt.show()
pandas的大部分繪圖方法都有一個可選的ax參數,它可以是一個matplotlib的subplot對象。這使你能夠在網格佈局中更爲靈活地處理subplot的位置。
DataFrame的plot方法會在一個subplot中爲各列繪製一條線,並自動創建圖例。
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的其他關鍵字參數會被傳給相應的matplotlib繪圖函數,所以要更深入地自定義圖表,就必須學習更多有關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中各值的出現頻率,比如s.value_counts ().plot(kind=’bar’)。
df.plot(kind='barh',stacked=True,alpha=0.8)
plt.show()
以本書的有關小費的數據集爲例,假設我們想要做一張堆積柱狀圖以展示每天各種聚會規模的數據點的百分比。我用read_csv將數據加載進來,然後根據日期和聚會規模創建一張交叉表
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 |
進行規格化,使得各行的和爲1(必須轉換成浮點數),並生成圖表
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 |
通過該數據集就可以看出,聚會規模在週末會變大
直方圖和密度圖
直方圖(histogram)是一種可以對值頻率進行離散化顯示的柱狀圖。數據點被拆分到離散的、間隔均勻的面元中,繪製的是各面元中數據點的數量
以前面那個小費數據爲例,通過Series的hist方法,我們可以生成一張“小費佔消費總額百分比”的直方圖
tips['tip_pct']=tips['tip']/tips['total_bill']
tips['tip_pct'].hist(bins=50)
plt.show()
小費百分比的直方圖
與此相關的一種圖表類型是密度圖,它是通過計算“可能會產生觀測數據的連續概率分佈的估計”而產生的。一般的過程是將該分佈近似爲一組核(即諸如正態(高斯)分佈之類的較爲簡單的分佈)。
調用plot時加上kind=’kde’即可生成一張密度圖(標準混合正態分佈KDE)
tips['tip_pct'].plot(kind='kde')
plt.show()
小費百分比的密度圖
這兩種圖表常常會被畫在一起。直方圖以規格化形式給出(以便給出面元化密度),然後再在其上繪製核密度估計。接下來來看一個由兩個不同的標準正態分佈組成的雙峯分佈
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)是觀察兩個一維數據序列之間的關係的有效手段。matplotlib的scatter方法是繪製散佈圖的主要方法
通過例子看看,首先加載了來自statsmodels項目的macrodata數據集,選擇其中幾列,然後計算對數差
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創建散佈圖矩陣的scatter_matrix函數。它還支持在對角線上放置各變量的直方圖或密度圖
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可視化的知識,學習到對數據繪圖的基礎知識,瞭解到matplotlib其他的繪圖接口 seaborn和 ggplot。
完善並深入練習還是需要去官方網站去查看相關的用法。
有興趣可以去官網查看手冊:https://matplotlib.org/