0. matplotlib入門

這篇筆記主要來自《利用python進行數據分析》的第八章第一節,對matplotlib的基本使用介紹的特別清晰。關于matplotlib的基本概念(figure, subplot, axes)的介紹還可以看這里

  • Figure和Subplot
  • 顏色、標記和線型
  • 刻度、標簽和圖例
  • 注解
  • 保存到文件

pyplot模塊的API文檔,這里

1. Figure和Subplot

plt.figure()

matplotlib的圖像都位于Figure對象中,可以使用plt.figure()創建一個新的figure:

>>> fig = plt.figure()

在ipython中,執行后會彈出一個空窗口:

一個Figure

該窗口的大小可以通過在plt.figure()中傳遞參數figsize=(width,height)來指定。

可以看到窗口的標題為“Figure 1”,要想設定Figure編號為3,則可執行:

>>> fig = plt.figure(3)

可通過plt.gcf()來獲得最后一次創建的Figure對象的引用。

Figure.add_subplot()

現在雖然有了一個Figure對象fig,但是還不能在其上畫圖。必須使用add_subplot()在fig上創建一個或多個subplot才行:

# 等價于fig.add_subplot(221)
# 意思是將fig劃分為2x2,指定第一個為畫圖位置
# 這里的subplot從1開始編號
# 其實就是在fig中固定位置創建了一個Axes對象。
>>> ax1 = fig.add_subplot(2, 2, 1)

執行后會得到:

Figure中有一個subplot(Axes對象)

若接著執行:

# 執行后fig中就有了三個Axes對象
>>> ax2 = fig.add_subplot(2, 2, 2)
>>> ax3 = fig.add_subplot(2, 2, 3)

得到:

Figure中有三個subplot(Axes對象)

fig.add_subplot(2, 2, 1)并不意味著對于該fig,固定劃分了2x2個subplot,這只是指出一個固定的位置來確定要創建的Axes對象。比如還可以接著執行下面的代碼再創建個小的Axes對象:

>>> ax4 = fig.add_subplot(339)

結果為:

也可將其放到其他位置,放這里方便看

可以看到Figure.add_subplot()的功能是將Axes對象創建于規則的網格(grid)上的,如果想要在Figure中的任意位置創建任意大小的Axes對象可使用Figure.add_axes()

plot()

如果這時發出一條繪圖命令,matplotlib會在最后一個用過的Axes對象上(如果沒有則自動創建一個)進行繪制。

# 繪制黑色'k'虛線'--'
>>> plt.plot(np.random.randn(50).cumsum(), 'k--')

結果為:

可見是在最后一個創建的Axes對象上繪制的

如果想要在其他的axes中繪圖,則可以調用之前的Axes對象中的繪圖方法

# hist方法有三個返回值,不想顯示就將其賦給以變量
>>> _ = ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)
>>> ax2.scatter(np.arange(30), np.arange(30) + 3*np.random.randn(30))

結果如下:

plt.subplots()

有一條語句可以快速的建立Figure和一組subplots,也就是plt.subplots()。它可以創建一個新的Figure,并返回一個含有已創建的Axes對象的numpy數組:

# 創建一個Figure對象fig2,并在其上繪制2x3個subplots
# fig2為新創建的Figure對象
# axess為一2x3數組,其中元素為Axes對象。
>>> fig2, axess = plt.subplots(2,3)

執行上述語句,會彈出一個新的Figure窗口:

與之前不同,這里直接畫出了2x3個subplot

之前使用plt.figure()創建Figure對象時,可以傳遞figsize參數來指定Figure對象的大小。在plt.subplots()中也可以傳遞該參數,見文檔中對**fig_kw參數的描述。
但是如果在創建完Figure對象后想改變figure size該怎么辦呢?可調用Figure類的方法set_figheight()set_figweight()來分別設置Figure對象的長和寬。可見Figure類的文檔說明

可以看axess的內容:

>>> axess
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x1178f9240>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117920438>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117947710>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x117b28438>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117b50748>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x117b7a9e8>]], dtype=object)

可以通過指定參數sharex=True使各列Axes對象使用同一個x軸(這樣,調整某列的xlim將會影響對應的axes),而設置sharey=True使各行Axes對象使用同一個y軸(這樣,調整某行的ylim將會影響對應的axes)。

>>> plt.close(2)
>>> fig2, axess = plt.subplots(2,3, sharex=Ture, sharey=Ture)

結果為:

plt.subplots_adjust()

默認情況下(matplotlib有默認的配置文件),matplotlib會在subplot外圍留下一定的邊距,并在subplot之間留下一定的間距。利用plt.subplots_adjust()Figure.subplots_adjust()可以修改這些間距。兩個函數的參數都是一樣的(見文檔),但前者是在當前Figure中操作,而后者是在指定的Figure中操作的。

# 操作的是fig2
>>> plt.subplots_adjust(wspace=0, hspace=0)

結果為:

可以看到matplotlib中的畫圖是很自由的,并不會檢查坐標的重疊。

# 操作的是上面的Figure 1
>>> fig.subplots_adjust(wspace=0, hspace=0)

結果為:

當畫完圖之后,要記得使用plt.close()關掉對應的Figure,釋放內存。有多種關閉方式,可看文檔。

# 關閉所有Figure。
>>> plt.close('all')

總結一下,Figure對象就相當于一個巨大的畫板,可以在畫板上放置多個畫紙,各個畫紙也就是Axes對象,畫圖就是畫在Axes對象上的。各個Axes對象都有自己的坐標軸,可以分別控制。文檔中對這幾個概念的描述在這里。其中有張圖可以很好的理解Figure與Axes的各部分。

下面都以plot畫線來介紹。

2. 顏色、標記和線型

上一節中調用plot()畫線時(plt.plot()axes.plot()),傳遞了一個參數'k--',指出畫的線為黑色虛線,這是對線的顏色和形式一種便捷的設置,這種簡便寫法中還可以加入一個標記的形式控制(也就是(x,y)點的形式)。

注意,plot()的字典參數**kwargs用于指定要畫的Line2D線對象的各種屬性。

控制格式為,注意順序不能變:
fmt = '[color][marker][line]'

如:

>>> fig, ax = plt.subplots(1,1)
# 相當于,這種顯示控制:
# ax.plot(np.random.randn(20), linestyle='-', color='r', marker='o')
>>> ax.plot(np.random.randn(20), 'ro-')

得到下圖:


fmt中的三項都是可選的,各項可配置的值可看這里的Notes部分。

但是要注意,fmt這種簡便設置方式與顯示參數的設置還是不同的。

# 只設置顏色和marker形式,則只畫點,不畫線
>>> ax.plot(np.random.randn(20), 'bo‘)
# 雖只設置顏色和marker形式,依然畫出了線
>>> ax.plot(np.random.randn(20), color='g', marker='o')

另外使用color參數設置顏色時,或fmt中只設置顏色時,可以使用更多的顏色設置方式,具體可看這里

在線型圖中,非實際的數據點默認是按照線性方式插值的。可以通過plot()的參數drawstyle來修改插值方式:

# 清除axes上的繪制
>>> ax.clear()
>>> ax.plot(np.random.randn(20), 'ko-', drawstyle='steps-post')

3. 刻度、標簽和圖例

這一節講解的就是對坐標軸的控制,包括軸標簽、軸刻度的標簽、軸刻度、軸刻度范圍、圖例。下面都是顯示指定要控制的Axes對象,使用Axes類中的方法。

先繪制一個簡單的圖像,并在其上舉例。

>>> fig, ax = plt.subplots(1,1)
>>> np.random.seed(985)
>>> ax.plot(np.random.randn(30), 'ro-')
# 設置標題
>>> ax.set_title('random plot')
# 設置xy軸標簽
>>> ax.set_xlabel('x')
>>> ax.set_ylabel('y')

對應的,可以通過Axes.get_title()Axes.get_xlabel()Axes.get_ylabel()來得到對應的值。

>>> ax.get_title()
'random plot'
>>> ax.get_xlabel()
'x'
>>> ax.get_ylabel()
'y'
  • 軸的范圍
    由于沒有指定要畫線的x值,所以默認為range(0,30),而看圖上的x軸坐標范圍,其在左右明顯要小于0并大于29,我們可以使用Axes.get_xlim()Axes.get_ylim()來分別得到x軸和y軸的坐標范圍。
>>> ax.get_xlim()
(-1.4500000000000002, 30.449999999999999)
>>> ax.get_ylim()
(-1.271508964835969, 2.6919009419421762)

可見畫圖時默認增加了些冗余,當然我們可以對其更改。

可以使用Axes.set_xlim()Axes.set_ylim()來分別設置軸的范圍:

>>> ax.set_xlim(-10, 40)

同樣也可以縮小:

>>> ax.set_xlim(10, 20)

兩次縮放了軸的范圍,與原始圖對比下可發現,在縮放中,x坐標(只操作了x軸)刻度也在自動變化。這是因為我們沒有顯示設置x軸的坐標刻度值,所以matplotlib自動設置的。如果顯示設置了,那么會一直使用我們設置好的,不論如何縮放軸范圍。

# 接著上面執行代碼。
>>> ax.get_xticks()
array([ 10.,  12.,  14.,  16.,  18.,  20.])
>>> ax.get_yticks()
array([-1.5, -1. , -0.5,  0. ,  0.5,  1. ,  1.5,  2. ,  2.5,  3. ])

可見也就是軸上的坐標值,同樣的可以使用Axes.set_xticks()Axes.set_yticks()來更改:

# 會返回一個列表,包含11個創建的XTick對象。
>>> ticks = ax.set_xticks(range(0,33,3))
可見自動按我們設置的x坐標來放大了x軸范圍

此時x軸的坐標刻度也就固定了,再放大x軸范圍也不會改變坐標刻度,而只是縮放了圖像。如:

# 設置為最初的x軸范圍
>>> ax.set_xlim(-1.4500000000000002, 30.449999999999999)
  • 軸刻度標簽的控制
    目前在x軸上有11個刻度,都是數字表示的,還可以使用Axes.set_xticklabels()將其他任何值用做標簽:
# 改為其他數值
>>> labels = ax.set_xticklabels(range(10,43,3))
# 改為字符串
>>> labels = ax.set_xticklabels([i for i in 'abcdefghijk'])
# 指定的字符串還可以為LateX數學表達式。
>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)])

此外,可以對函數Axes.set_xticklabels()的**kwargs傳入其他參數來控制Text對象的屬性。如字體角度rotation和字體大小fontsize(其他屬性可看文檔):

>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)], rotation = 30, fontsize='large')

此外,因為我們使用了Axes.set_xticks()設置了11個坐標刻度,所以在Axes.set_xticklabels()中需要傳遞長度11的列表指定這11刻度的label。如果列表長度小于11的話,如5,那么,只改變前5個刻度的label,后6個刻度的label為空,也就啥也沒有。如果列表中的元素多于11個,那么只用前11個。

>>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,5)], rotation = 30, fontsize='large')
  • 圖例
    可以使用Axes.legend()在Axes中添加圖例,對繪制進行說明。

對于上面畫的紅線,現在加入一個圖例:

# 返回Legend對象
>>> l1 = ax.legend(['red'])

這種方法是不推薦的,因為當Axes中繪制了多條線后,需要在legend()中傳入對應著畫線順序的label,而該順序很容易搞混的。

常用的一種加入圖例方法是在畫圖是傳入label參數,然后在使用legend():

>>> np.random.seed(211)
>>> ax.plot(np.random.randn(30), 'ko--', label='black')
>>> ax.legend()
這時只有一個圖例了,因為畫紅線時沒有傳入label

還用一種更為全面的控制方式,即指出需要圖例的那條線和其對應的字符串,清除掉這兩條線,重畫下:

>>> ax.clear()
>>> np.random.seed(233)
# 注意,plot()返回的是包含Line2D對象的列表,如果不加',‘,那么l1是列表。
>>> l1, = ax.plot(np.random.randn(30), 'ko-')
>>> np.random.seed(666)
>>> l2, = ax.plot(np.random.randn(30), 'ro--')
# 將Line2D對象放入第一個列表中,第二個列表中的字符串順序要一致。
>>> ax.legend([l1,l2], ['black', 'red'])

關于圖例的控制(位置、字體等),可看文檔Axes.legend()

4. 注解

  • 文本的繪制

在Axes對象中繪制文本可使用函數Axes.text()。該函數的使用很簡單,傳入坐標和文本,就會將文本繪制在對應的坐標上。可以向函數傳入Text屬性來控制文本的顯示。

>>> fig, ax = plt.subplots(1,1)
>>> x = np.linspace(-np.pi,np.pi,100, endpoint=True)
>>> y = np.sin(x)
>>> ax.plot(x,y, 'k-')  
>>> ax.set_xticks(np.arange(-np.pi,np.pi+1,np.pi/4))
# 這些tick labels本身就是Text對象。該函數會返回包含對應的9個Text對象的列表。
>>> ax.set_xticklabels([r'$-\pi$', r'$-\frac{3}{4}\pi$', r'$-\frac{1}{2}\pi$', r'$-\frac{1}{4}\pi$', r'0', r'$\frac{1}{4}\pi$', r'$\frac{1}{2}\pi$',r'$\frac{3}{4}\pi$', r'$\pi$'])
# 在原點繪制文本,后面的參數設置文本的顯示屬性。
# ha和va設置的是文本相對(0,0)的位置,‘center'是以點為中心。
>>> ax.text(0,0, r'hello world!', color='r', ha='center', va='center',rotation=30, size='medium', style = 'italic' )
  • 注釋

在圖上繪制注釋使用的是Axes.annotate)()。關于該函數的使用例子可看這里

# 在坐標(-1,0.5)處寫Text對坐標(0,0)進行注釋。
>>> ax.annotate(s=r'origin', xy=(0,0), xytext=(-1,0.5), arrowprops={'arrowstyle':'->'})

5. 保存到文件

使用plt.save()可將當前Figure中的內容保存到文件(也可以是file-like object)中。

文件的類型可以通過給定的文件名擴展名推斷出來,或者指定函數參數format。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容