Matplotlib使用介紹

Matplotlib 最重要的特性之一就是具有良好的操作系統(tǒng)兼容性和圖形顯示底層接口兼容性。雖然,近幾年Matplotlib 的界面與風(fēng)格似乎有點(diǎn)跟不上時代,但仍然是數(shù)據(jù)可視化技術(shù)不可缺少的一環(huán)。

1. 最常用的基本知識

類似numpy和pandas,matplotlib也有自己約定俗成的引入方式:

In [20]: import matplotlib as mpl
In [22]: import matplotlib.pyplot as plt

通過plt.style來選擇圖形的繪圖風(fēng)格。

In [23]: plt.style.use('classic')

Matplotlib包含有3種實(shí)驗(yàn)環(huán)境:分別是腳本、IPython shell 和 IPython Notebook。如果使用腳本,為了顯示圖片就必須使用plt.show()語句,plt.show() 會啟動一個事件循環(huán)(eventloop),并找到所有當(dāng)前可用的圖形對象,然后打開一個或多個交互式窗口顯示圖形。需要注意,一個 Python 會話(session)中只能使用一次 plt.show(),因此通常都把它放在腳本的最后。
在IPython中啟動 Matplotlib 模式就可以使用,使用語句%matplotlib,此后的任何 plt 命令都會自動打開一個圖形窗口,增加新的命令,圖形就會更新(圖形是交互式變化的)。對于這些變化,可以使用 plt.draw() 強(qiáng)制更新。不需要使用plt.show()了。
使用IPython Notebook與IPython類似:
%matplotlib notebook 會在 Notebook 中啟動交互式圖形。
%matplotlib inline 會在 Notebook 中啟動靜態(tài)圖形。(經(jīng)常使用)

In [3]: %matplotlib
Using matplotlib backend: MacOSX

In [4]: x = np.linspace(0,10,100)

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

In [7]: plt.plot(x,np.sin(x),'-')
Out[7]: [<matplotlib.lines.Line2D at 0x12371a490>]

In [8]: plt.plot(x,np.cos(x),'--')
Out[8]: [<matplotlib.lines.Line2D at 0x10f82e110>]

In [16]: fig.savefig('first_pic.png')   #保存為PNG格式的文件

In [17]: fig.canvas.get_supported_filetypes()
Out[17]: 
{u'eps': u'Encapsulated Postscript',
 u'jpeg': u'Joint Photographic Experts Group',
 u'jpg': u'Joint Photographic Experts Group',
 u'pdf': u'Portable Document Format',
 u'pgf': u'PGF code for LaTeX',
 u'png': u'Portable Network Graphics',
 u'ps': u'Postscript',
 u'raw': u'Raw RGBA bitmap',
 u'rgba': u'Raw RGBA bitmap',
 u'svg': u'Scalable Vector Graphics',
 u'svgz': u'Scalable Vector Graphics',
 u'tif': u'Tagged Image File Format',
 u'tiff': u'Tagged Image File Format'}

得到下邊的圖形:



Matplotlib 的一個優(yōu)點(diǎn)是能夠?qū)D形保存為各種不同的數(shù)據(jù)格式。你可以用 savefig() 命令將圖形保存為文件。不同格式的文件是以文件后綴名來區(qū)分的,上邊的命令列出了matplotlib支持的所有格式名。

2. 兩種畫圖接口

Matplotlib 有一個容易讓人混淆的特性,就是它的兩種畫圖接口:
(1) 便捷的 MATLAB 風(fēng)格接口。
(2)功能更強(qiáng)大的面向?qū)ο蠼涌凇?/p>

2.1. MATLAB風(fēng)格

MATLAB 風(fēng)格的工具位于 pyplot(plt)接口中,如下邊一個例子:

x = np.linspace(0,10,100)
fig = plt.figure()
plt.subplot(2,1,1)   # 行、列、編號 (圖形矩陣)
plt.plot(x,np.sin(x),'-')

plt.subplot(2,1,2)
plt.plot(x,np.cos(x),'--')

這種接口最重要的特性是有狀態(tài)的(stateful)。可以用plt.gcf()(獲取當(dāng)前圖形)和 plt.gca()(獲取當(dāng)前坐標(biāo)軸)來查看。 這種圖畫起圖來又快又方便,但是也很容易出問題。例如,在畫第2個圖時,已經(jīng)無法修改第1個圖了。

2.2. 面向?qū)ο箫L(fēng)格

面向?qū)ο蠼涌诳梢蕴幚砀訌?fù)雜的場景,畫圖函數(shù)不再受到當(dāng)前“活動”圖形或坐標(biāo)軸的限制,而變成了顯式的 Figure 和 Axes 的方法。

fig,ax = plt.subplots(2)
ax[0].plot(x,np.sin(x))
ax[1].plot(x,np.cos(x))

3. 線形圖

要畫 Matplotlib 圖形時,都需要先創(chuàng)建一個圖形 fig 和一個坐標(biāo)軸ax。
最簡單地,通過下邊方法創(chuàng)建這2個對象:

fig = plt.figure()
ax = plt.axes()

在 Matplotlib 里面,figure(plt.Figure 類的一個實(shí)例)可以被看成是一個能夠容納各種坐標(biāo)軸、圖形、文字和標(biāo)簽的容器。axes(plt.Axes 類的一個實(shí)例)是一個帶有刻度和標(biāo)簽的矩形,最終會包含所有可視化的圖形元素。

fig = plt.figure()
ax = plt.axes()
ax.plot(x,np.sin(x),color='blue',linestyle = '--',label='sin(x)')
ax.plot(x,np.sin(x-1),color='olive',linestyle ='-.',label='sin(x-1)')
ax.plot(x,np.sin(x-2),'-g',label='sin(x-2)')     #線條風(fēng)格+顏色簡寫形式
ax.set(xlim=(-2,11),ylim=(-2,2),xlabel='x',ylabel='y',title='A simple plot')
ax.legend()  # 顯示圖例
image.png

如果需要在一個fig畫多個線,直接plot多次即可。ax對象可以通過set()方法來統(tǒng)一設(shè)置很多屬性。

matplotlib 可選的線條風(fēng)格和顏色:
https://blog.csdn.net/detaswc/article/details/81086757

最后,通過一張表格來總結(jié)下本節(jié)介紹過的一些常用的屬性(更詳細(xì)可以參考官方文檔):

name 說明 應(yīng)用層級
color 配置線條顏色 曲線
linestyle 線條風(fēng)格(直線、虛線等) 曲線
label 曲線標(biāo)簽(圖例) 曲線
xlim 圖形x軸取值范圍 整個圖表
ylim 圖形y軸取值范圍 整個圖表
xlabel 圖形x軸標(biāo)簽名 整個圖表
ylabel 圖形y軸標(biāo)簽名 整個圖表
title 圖形的標(biāo)題 整個圖表
legend() 生成圖例的方法 方法

4. 散點(diǎn)圖

散點(diǎn)圖(scatter plot)與線形圖類似,不再由線段連接,而是由獨(dú)立的點(diǎn)、圓圈或其他形狀構(gòu)成。

4.1 使用plt.plot畫散點(diǎn)圖

第一種方式與上邊線形圖的構(gòu)造方法十分類似,只修改下linestyle參數(shù)即可(之前是- 修改為o),執(zhí)行效果如下:

plt.plot(x,np.sin(x),'o',color='black')

4.2 使用plt.scatter畫散點(diǎn)圖

plt.scatter 與 plt.plot 的主要差別在于,前者在創(chuàng)建散點(diǎn)圖時具有更高的靈活性,可以單獨(dú)控制每個散點(diǎn)與數(shù)據(jù)匹配,也可以讓每個散點(diǎn)具有不同的屬性(大小、表面顏色、邊框顏色等)。
當(dāng)數(shù)據(jù)變大到幾千個散點(diǎn)時,plt.plot 的效率將大大高于plt.scatter。因此面對大型數(shù)據(jù)集時,plt.plot 方法比 plt.scatter 方法好。
下面以sklearn的鳶尾花數(shù)據(jù)為例制作一個散點(diǎn)圖:
['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
了解特征數(shù)據(jù)的說明:

from sklearn.datasets import load_iris
iris = load_iris()
iris.keys()
iris.DESCR
iris.feature_names

作圖代碼:

from sklearn.datasets import load_iris
iris = load_iris()
features = iris.data.T
feature_names = iris.feature_names
fig = plt.plot()
ax = plt.axes()
ax.scatter(features[0],features[1],alpha=0.2,s=100*features[3], c=iris.target, cmap='viridis')
ax.set(xlabel=feature_names[0] , ylabel=feature_names[1],title='First Scatter Plot')

Scatter參數(shù)詳見:https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.scatter.html#matplotlib.axes.Axes.scatter

5. 誤差線圖

基本誤差線(errorbar)可以通過一個 Matplotlib 函數(shù)來創(chuàng)建。
其中yerr指定是在縱軸方向誤差,xerr是在橫軸方向誤差,當(dāng)然可以兩方向同時誤差。
下面是個簡單的例子:

fig = plt.figure()
ax = plt.axes()
dy = 0.8
x_e = np.linspace(0,10,50)
y_e = np.sin(x_e) + dy * np.random.randn(50)
ax.errorbar(x_e,y_e,yerr=dy,fmt='o',color='black',ecolor='lightgray',
elinewidth=3,capsize=0)

errorbar參數(shù)詳見:https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.errorbar.html#matplotlib.axes.Axes.errorbar

6. 密度圖與等高線圖

在二維圖上用等高線圖或者彩色圖來表示三維數(shù)據(jù)是個不錯的方法。用 plt.contour 畫等高線圖、用 plt.contourf 畫帶有填充色的等高線圖(filled contourplot)的色彩、用 plt.imshow 顯示圖形。
等高線圖可以用 plt.contour 函數(shù)來創(chuàng)建。它需要三個參數(shù):x 軸、y軸、z 軸三個坐標(biāo)軸的網(wǎng)格數(shù)據(jù)。x 軸與 y 軸表示圖形中的位置,而 z 軸將通過等高線的等級來表示。
np.meshgrid 函數(shù)可以從一維數(shù)組構(gòu)建二維網(wǎng)格數(shù)據(jù)。

理解np.meshgrid :
實(shí)際上就是 生成網(wǎng)格點(diǎn)坐標(biāo)矩陣
我以一個簡單的例子展開說明:
t_ga = np.array([0,4,5,8,9])
t_gb = np.array([1,3,9,12])
XT,YT = np.meshgrid(t_ga,t_gb)
plt.plot(XT,YT,color='green',linestyle='',marker='o')
plt.show()
以上代碼得到圖形如下:


實(shí)際上,以提供的兩個數(shù)組,在X軸和Y軸做垂線,這些所有線的交點(diǎn)也成了所謂的網(wǎng)格矩陣了。
參考文章:
https://blog.csdn.net/lllxxq141592654/article/details/81532855

介紹完meshgrid概念后,看看最簡單的等高圖:

def f(x, y):
    return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
x_f = np.linspace(0,5,50)
y_f = np.linspace(0,5,40)

X,Y = np.meshgrid(x_f,y_f)
Z = f(X,Y)
fig = plt.figure()
ax = plt.axes()
ax.contour(X,Y,Z,colors='black')

當(dāng)圖形中只使用一種顏色時,默認(rèn)使用虛線表示負(fù)數(shù),使用實(shí)線表示正數(shù)。此圖確實(shí)比較難看,下邊提供了一系列改進(jìn)方式。

改進(jìn)1:
你可以用 cmap 參數(shù)設(shè)置一個線條配色方案來自定義顏色。下邊語句將數(shù)據(jù)范圍等分為 20 份,然后用不同的顏色表示。Matplotlib 有非常豐富的配色方案,你可以在IPython 里用 Tab 鍵瀏覽 plt.cm 模塊對應(yīng)的信息。plt.cm.<TAB>

ax.contour(X,Y,Z,30,cmap='RdGy')

改進(jìn)2:
上邊圖形的線條間的間隙很大,可以通過plt.contourf來改進(jìn),其語法與contour完全一致。另外,通過 plt.colorbar() 命令自動創(chuàng)建一個表示圖形各種顏色對應(yīng)標(biāo)簽信息的顏色條。

ax0 = ax.contourf(X,Y,Z,30,cmap='RdGy')
fig.colorbar(ax0,ax=ax)

改進(jìn)3:
上邊的圖形的主要問題是顏色的改變是一個離散而非連續(xù)的過程,這導(dǎo)致了圖形看起來有點(diǎn)兒“污漬斑斑”。plt.imshow() 函數(shù)可以將二維數(shù)組渲染成漸變圖。

contours = plt.contour(X, Y, Z, 3, colors='black')
plt.clabel(contours, inline=True, fontsize=8)
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower',
cmap='RdGy', alpha=0.5)
plt.colorbar();

7. 頻次直方圖、數(shù)據(jù)區(qū)間劃分和分布密度

10.多子圖

當(dāng)需要做對比分析時,有必要畫多個圖。

10.1 plt.axes()創(chuàng)建子圖

plt.axes()函數(shù)有4個參數(shù):[bottom, left, width, height](底坐標(biāo)<x軸>、左坐標(biāo)<y軸>、寬度、高度),數(shù)值的取值范圍是左下角(原點(diǎn))為 0,右上角為 1。以上參數(shù)為了生成“畫中畫”,幾個參數(shù)都是百分比。

ax_sub_3 = plt.axes()
ax_sub_4 = plt.axes([0.4,0.6,0.5,0.3])
plt.show()

面向?qū)ο螽媹D接口中類似的命令是:fig.add_axes(),例如下邊的代碼可以生成上下兩個圖:

fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.5, 0.8, 0.4],xticklabels=[], 
ylim=(-1.2, 1.2))  # xticklabels=[],表示上邊的坐標(biāo)軸無刻度。
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.4],ylim=(-1.2, 1.2))
x = np.linspace(0, 10)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x))

10.2 plt.subplot()創(chuàng)建子圖

plt.subplot() 在一個網(wǎng)格中創(chuàng)建一個子圖。
plt.subplots_adjust 命令可以調(diào)整子圖之間的間隔。
使用MATLAB接口創(chuàng)建子圖使用:plt.subplot(2,3,i)
使用面向?qū)ο蠼涌趧?chuàng)建子圖使用:fig.add_subplot(2,3,i)
上邊例子中,subplot,前2個參數(shù)是子圖矩陣的行和列(2行3列子圖,共6個),最后一個i是子圖的編號(從1到6)。下邊是2個例子:

for i in range(1,7):
    plt.subplot(2,3,i)
    plt.text(0.5,0.5,str((2,3,i)),fontsize=18,ha='center')
plt.subplots_adjust(hspace=0.4,wspace=0.4)  #間隙的高和寬分別是子圖的40%
fig = plt.figure()
fig.subplots_adjust(hspace=0.4,wspace=0.4)
for i in range(1,7):
    axi=fig.add_subplot(2,3,i)
    axi.text(0.5,0.5,str((2,3,i)),fontsize=16,ha='center')    

10.3 plt.subplots()

本節(jié)介紹的方法跟上邊相比多個s,如果需要隱藏子圖的x軸和y軸,可以使用 plt.subplots()。該方法返回子圖的Numpy數(shù)組。
plt.subplots()的參數(shù)包括:子圖矩陣的行數(shù)和列數(shù),可選參數(shù)sharex和sharey,參考下邊例子:

fig,ax = plt.subplots(3,2,sharex='col' , sharey='row')  #列共享x軸(sharex),行共享y軸
for i in range(0,3):
    for j in range(0,2):
        ax[i][j].text(0.5,0.5,str((i,j)),fontsize=16,ha='center')
fig.subplots_adjust(hspace=0.4,wspace=0.4)

10.4 plt.GridSpec()實(shí)現(xiàn)更復(fù)雜的排列方式

上邊10.2和10.3節(jié)畫的都是規(guī)則的多行多列子圖網(wǎng)格,如果想畫不規(guī)則的,可以使用plt.GridSpec()。plt.GridSpec()并不是規(guī)則圖形,而是plt.subplot()的簡易接口。
例如,下邊的例子,生成了不規(guī)則的圖形:

grid = plt.GridSpec(3,3)
plt.subplot(grid[0,:2])
plt.subplot(grid[0,2])
plt.subplot(grid[1:,:2])
plt.subplot(grid[1:,2])

下面是plt.GridSpec()的一個應(yīng)用,多軸頻次直方圖:

11.文字和注釋

在圖表中增加文字標(biāo)簽,主要通過ax.text方法。
ax.text 方法需要一個 x 軸坐標(biāo)、一個 y 軸坐標(biāo)、一個字符串和一些可選參數(shù),比如文字的顏色、字號、風(fēng)格、對齊方式以及其他文字屬性。
下邊是一個例子:

births=pd.read_csv('python_science_handbook_data/births.csv')
quartiles = np.percentile(births['births'],[25,50,75])  #25,50,75分位數(shù)
mid,sig = quartiles[1],0.74*(quartiles[2]-quartiles[0])
# (mid - 5*sig,mid + 5*sig)
births = births.query('(births > @mid - 5*@sig) & (births < @mid + 5*@sig)')
births['day'] = births['day'].astype(int)  #day列轉(zhuǎn)化為int
# births['unix_time'] = 10000*births.year + 100*births.month + births.day        ##19690101
births.index = pd.to_datetime(10000*births.year + 100*births.month + births.day,format='%Y%m%d')
births_by_date = births.pivot_table('births',[births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day)for (month, day) in births_by_date.index]
fig, ax = plt.subplots(figsize=(12, 4))
# births_by_date.loc['2012-1-1':'2012-1-1']

births_by_date.plot(ax=ax);

# 在圖上增加文字標(biāo)簽
style = dict(size=10, color='gray')

ax.text('2012-1-1', 3950, "New Year's Day", **style)
ax.text('2012-7-4', 4250, "Independence Day", ha='center', **style)
ax.text('2012-9-4', 4850, "Labor Day", ha='center', **style)
ax.text('2012-10-31', 4600, "Halloween", ha='right', **style)
ax.text('2012-11-25', 4450, "Thanksgiving", ha='center', **style)
ax.text('2012-12-25', 3850, "Christmas ", ha='right', **style)

ax.set(title='USA births by day of year (1969-1988)',ylabel='average daily births')

ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
ax.xaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'));
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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