以下內(nèi)容主要學(xué)習(xí)自《利用Python進行數(shù)據(jù)分析》
第9章 繪圖與可視化
信息的可視化是數(shù)據(jù)分析中最重要的任務(wù)之一,因為可視化是數(shù)據(jù)探索過程的一部分,例如:幫助識別異常值或所需的數(shù)據(jù)交換,或者為建模提供一些想法。
matplotlib由John Hunter于2002年發(fā)起,目的是在Python環(huán)境下進行MATLAB風(fēng)格的繪圖。matplotlib支持所有操作系統(tǒng)上的各種GUI后端,還可以將可視化結(jié)果導(dǎo)出為常見的矢量和位圖格式(SVG、JPG、PNG、GIF、PDF等)。
如果想在Jupyter notebook中使用交互式繪圖,首先需要在Jupyter notebook中輸入如下語句:
% matplotlib notebook
簡明matplotlib API入門
在使用matplotlib時,我們使用如下的導(dǎo)入慣例:
In [1]: import matplotlib.pyplot as plt
如下的代碼會使用默認的設(shè)置繪制一個最簡單的圖形:
In [2]: import numpy as np
In [3]: data = np.arange(10)
In [4]: data
Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [5]: plt.plot(data)
Out[5]: [<matplotlib.lines.Line2D at 0x1c2c3dd3e80>]
# 顯示繪圖結(jié)果
In [6]: plt.show()
得到的圖形如下:

本筆記只記錄了關(guān)鍵的特性,如果要深入matplotlib,那么它的可視化作品庫和文檔是學(xué)習(xí)高級功能的最佳資源。
圖片與子圖
matplotlib所繪制的圖在Figure對象中,使用該對象的add_subplot方法可以創(chuàng)建一個或多個子圖。
In [1]: import matplotlib.pyplot as plt
In [2]: import numpy as np
In [3]: fig = plt.figure()
In [4]: ax1 = fig.add_subplot(2, 2, 1)
In [5]: ax2 = fig.add_subplot(2, 2, 2)
In [6]: ax3 = fig.add_subplot(2, 2, 3)
# 用numpy生成一個隨機漫步的數(shù)據(jù)集
In [7]: data = np.random.randn(50).cumsum()
# 用黑色分段線繪制圖形
In [8]: plt.plot(data, 'k--')
In [9]: plt.show()
上面代碼的意思是圖片應(yīng)該是2X2的(最多4個圖形),接著創(chuàng)建了3個子圖(序號從1開始),執(zhí)行后可以看到如下圖形。

觀察如上的圖片,可以得出:如不特別指明,matplotlib會在最后一個子圖上進行繪圖。
由于創(chuàng)建子圖是非常常見的任務(wù),所以matplotlib提供了一個便捷的plt.subplots方法創(chuàng)建多子圖的圖形,該方法返回了包含子圖對象的Numpy數(shù)組。
In [1]: fig, axes = plt.subplots(2,2)
In [2]: axes.size
Out[2]: 4
# 用黑色分段線繪制圖形,在最后一個子圖上繪制。
In [3]: plt.plot(np.random.randn(50).cumsum(), 'k--')
Out[3]: [<matplotlib.lines.Line2D at 0x26e230918d0>]
# 在第1個子圖上繪制柱狀圖
In [4]: axes[0,0].hist(np.random.randn(100), bins=20, color='k', alpha=0.3)
# 在第2個子圖上繪制散點圖
In [5]: axes[0,1].scatter(np.arange(30), np.arange(30) +3 * np.random.randn(30))
In [6]: plt.show()
執(zhí)行后得到如下的圖形。

調(diào)整子圖的間距
默認情況下,matplotlib會在子圖的外部和子圖之間留出一定的間距,可以使用subplots_adjust方法更改間距,該方法的完整聲明如下:
subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
其中wspace和hspace分別控制了子圖間的間距。
In [1]: fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
In [2]: for i in range(2):
...: for j in range(2):
...: axes[i,j].hist(np.random.randn(500), bins=50, color='#0000ff', alpha=0.75)
In [3]: plt.subplots_adjust(wspace=0, hspace=0)
In [4]: plt.show()
上面的代碼中,通過設(shè)置sharex和sharey來表明子圖擁有相同的x軸、y軸,當在相同的比例下進行數(shù)據(jù)對比時,這非常有用。執(zhí)行后得到如下的圖形。

顏色、標記和線類型
matplotlib的plot方法接收帶有x和y軸的數(shù)組以及一些可選的字符串縮寫參數(shù)來指明顏色、線類型。例如,要用綠色破折號繪制,需要執(zhí)行如下代碼:
ax.plot(x, y, 'g--')
與上面同樣效果的、更為易懂的代碼是:
ax.plot(x, y, linstyle='--', color='g')
除了可以使用顏色縮寫,還可以使用十六進制顏色代碼(如#ff0000)來指定顏色。參考plot函數(shù)的說明文檔可以看到全部線類型。
折線圖還可以有標記來凸顯實際的數(shù)據(jù)點,如下:
In [1]: from numpy.random import randn
In [2]: import matplotlib.pyplot as plt
In [3]: plt.plot(randn(30).cumsum(), 'ko--')
Out[3]: [<matplotlib.lines.Line2D at 0x1f4592e87b8>]
In [4]: plt.show()
以上第3行代碼的等價代碼(更容易理解的代碼)是:
plt.plot(randn(30).cumsum(), color='k', linestyle='dashed', marker='o')
執(zhí)行后得到如下的圖形

你會注意到,折線圖默認會在兩個數(shù)據(jù)點之間線性內(nèi)插繪制,可以通過drawstyle選項進行更改,參考如下代碼:
In [1]: data = np.random.randn(30).cumsum()
In [2]: plt.plot(data, 'k--', label='Default')
Out[2]: [<matplotlib.lines.Line2D at 0x1f45d35c940>]
In [3]: plt.plot(data, 'b-', drawstyle='steps-post', label='steps-
...: post')
Out[3]: [<matplotlib.lines.Line2D at 0x1f45d36f278>]
In [4]: plt.legend(loc='best')
Out[4]: <matplotlib.legend.Legend at 0x1f45d36f6d8>
In [5]: plt.show()
上面的代碼中,我們還設(shè)置了label參數(shù),并且使用plt.legend方法生成了用于區(qū)分的圖例,如果你不挑剔,使用loc='best'會自動選擇最合適的位置。效果如下。

刻度、標簽
為了講解軸的自定義,先用如下代碼繪制一個隨機漫步圖:
In [1]: fig = plt.figure()
In [2]: ax = fig.add_subplot(1,1,1)
In [3]: data = np.random.randn(1000).cumsum()
In [4]: ax.plot(data)
Out[4]: [<matplotlib.lines.Line2D at 0x1f45d1565f8>]
In [5]: plt.show()
運行后的效果如下

我們用set_xticks方法和set_xticklabels方法來改變x軸的刻度,代碼如下:
In [1]: fig = plt.figure()
In [2]: ax = fig.add_subplot(1,1,1)
In [3]: ax.plot(data)
Out[3]: [<matplotlib.lines.Line2D at 0x1f4542ce1d0>]
In [4]: ticks = ax.set_xticks([0,250,500,750,1000])
In [5]: labels = ax.set_xticklabels(['one','two','three','four','f
...: ive'], rotation=30, fontsize='small')
# 為圖形設(shè)置標題
In [6]: ax.set_title('My first matplotlab plot')
Out[6]: Text(0.5, 1.0, 'My first matplotlab plot')
# 為x軸設(shè)置標題
In [7]: ax.set_xlabel('Stages')
Out[7]: Text(0.5, 0, 'Stages')
In [8]: plt.show()
調(diào)整后的代碼執(zhí)行效果如下

將圖片保存到文件
可以使用plt.savefig方法將圖片保存到文件(figure對象也有同名的實例方法),例如將圖片保存為SVG,你只需要輸入如下代碼:
plt.savefig('figpath.svg')
保存的文件類型是從文件擴展名推斷出來的。幾個重要的選項參數(shù)有:
- dpi,控制每英寸點數(shù)分辨率;
- bbox_inches,修剪圖形的空白。
例如,為了得到一個png圖片,且使用最小的空白,擁有400DPI,那么代碼如下:
plt.savefig('figpath.png', dpi=400, bbox_inches='tight')
matplotlib設(shè)置
幾乎所有的matplotlib默認設(shè)置都可以通過全局參數(shù)來定制,包括圖形大小、子圖間距、顏色、字體大小和網(wǎng)格樣式等。使用rc方法是編程修改配置的一種方式。例如,要將全局默認的數(shù)字大小設(shè)置為10X10,可以輸入:
plt.rc('figure', figsize=(10,10))
rc的第一個參數(shù)是想要自定義的配置,如figure、axes、xtick、ytick、grid、legend等。如果要變更的設(shè)置較多,可以使用字典對象,讓代碼更加易讀:
font_options = {'family': 'monospace',
'weight': 'blod',
'size': 'small'}
plt.rc('font', **font_options)
如果需要更深入的理解和定制全局參數(shù),可以參考matplotlib的配置文件matplotlibrc,該文件位于matplotlib/mpl-data路徑下。matplotlib的官方網(wǎng)址是https://matplotlib.org。