matplotib入門練習

數據分析

 

 

▲行文目錄結構,重點是右三分支

 

 

01 關於Matplotlib

 

Matplotlib是Python的一個繪圖庫,與Numpy、pandas共享數據科學三劍客的美譽,也是很多高級可視化庫的基礎。Matplotlib不是Python內置庫,調用前需手動安裝,且需依賴Numpy庫。截至當前,Matplotlib發行版本號爲3.2.1,適配Python3.6及以上版本。

 

Matplotlib,是matrix + plot + library的縮寫,雖然命名很是直觀,但個人接觸之初卻是常常不禁嗤之以鼻:

 

  • 類比Numpy、pandas、sklearn這些簡潔易寫的庫名,Matplotlib由三個單詞縮略而成,冗餘得多;尤其是後面加了個lib,好像不加lib就不是庫?

  • Matplotlib自身名字長也就罷了,但調用它的時候居然還不能簡單的直接調用,而是要用它的子模塊pyplot。那既然pyplot是核心繪圖模塊,爲什麼不把其接口引入到頂層呢?那樣直接import matplotlib就行,而無需每次都import matplotlib.pyplot as plt了

  • 雖然pyplot是Matplotlib下的子模塊,但二者的調用關係卻不是Matplotlib調用pyplot,而是在pyplot中調用Matplotlib,略顯本末倒置?

 

當然,我等作爲使用者、調包俠,自然是無法領會開發者的獨特考慮,也絕無資格對其評三道四,僅做吐槽一二。

 

▲pyplot部分調用模塊

 

前面說到,調用Matplotlib庫繪圖一般是用pyplot子模塊,其集成了絕大部分常用方法接口,查看pyplot源碼文件可以發現,它內部調用了Matplotlib路徑下的大部分子模塊(不是全部),共同完成各種豐富的繪圖功能。

 

其中有兩個需要重點指出:figure和axes,其中前者爲所有繪圖操作定義了頂層類對象Figure,相當於是提供了畫板;而後者則定義了畫板中的每一個繪圖對象Axes,相當於畫板內的各個子圖。

 

換句話說,figure是axes的父容器,而axes是figure的內部元素,而我們常用的各種圖表、圖例、座標軸等則又是axes的內部元素。

 

當然,之所以不能稱pyplot爲一級命名空間的原因,不僅僅在於它在形式上隸屬於Matplotlib,最主要的在於它還不算是Matplotlib的“獨裁者”,因爲Matplotlib的另一個重要模塊——pylab——或許稱得上是真正意義上的集大成者:

 

pylab被定位是Python中對MATLAB的替代產品,也就是說凡是MATLAB可以實現的功能,pylab通通都要有,例如矩陣運算(包括常規矩陣運算、線性代數、隨機數、FFT等)、繪圖功能等等。

 

▲pylab導入的那些重量級模塊

 

至此,關於Matplotlib的pyplot和pylab兩個子模塊,我們可以得出2點結論:

 

  • pyplot的功能定位決定其不能成爲一級命名空間:即便是尋找Matplotlib的替代包名,那麼也該是pylab而不是pyplot

  • 簡單地講,以後也不用import numpy 和 import matplotlib.pyplot了,直接import matplotlib.pylab就夠了,畢竟它集成了二者的全部功能

 

▲pylab集成了Numpy和pyplot全部功能

 

當了解pylab模塊功能之後,才真正理解開發者的深謀遠慮:原以爲Matplotlib的意思是"面向矩陣的繪圖庫",哪知其真正意義是"矩陣+繪圖庫",繪圖只是它的一半。不過,也正因爲pylab模塊集成了過多的功能,直接調用並不是一個明智的選擇,官方已不建議用其繪圖。

 

注:按照慣例,本文後續多以plt作爲matplotlib.pyplot別名使用。

 

 

02 3種繪圖接口

 

 

用Matplotlib繪製可視化圖表,主要有3種接口形式:

 

  • plt接口,例如常用的plt.plot(),用官方文檔的原話,它是Matplotlib的一個state-based交互接口,相關操作不面向特定的實例對象,而是面向"當前"圖

  • 面向對象接口,這裏的面向對象主要是指Figure和Axes兩類對象。前文提到,Figure提供了容納多個Axes的畫板,而Axes則是所有圖標數據、圖例配置等繪圖形元素的容器。面向對象的繪圖,就是通過調用Figure或Axes兩類實例的方法完成繪圖的過程(當然,Figure和Axes發揮的作用是不同的)。通俗的說,就是將plt中的圖形賦值給一個Figure或Axes實例,方便後續調用操作

  • pylab接口,如前所述,其引入了Numpy和pyplot的所有接口,自然也可用於繪製圖表,仍然可看做是pyplot接口形式。因其過於龐大官方不建議使用

 

▲plt接口和麪向對象接口混合繪圖

 

鑑於pylab的特殊性,Matplotlib繪圖主要採用前2種方式。而在二者之間:

 

  • 如果是簡單的單圖表繪製,或者是交互實驗環境,則plt接口足以滿足需要,且操作簡單易用

  • 如果是多圖表繪製,需要相對複雜的圖例配置和其他自定義設置,那麼毫無疑問面向對象接口繪圖是當之無愧的不二選擇

 

需要指出,Axes從形式上是座標軸axis一詞的複數形式,但意義上卻遠非2個或多個座標軸那麼簡單:如果將Figure比作是畫板的話,那麼Axes就是畫板中的各個子圖,這個子圖提供了真正用於繪圖的空間,除了包含純粹的兩個座標軸(axes)外,自然還包括圖形、圖例等。

 

所以準確的講,如果說Axes和座標軸有何關聯的話,那麼Axes應該算是廣義的座標軸,或簡單稱之爲子圖即可。

 

 

03 繪圖3步走

 

 

如同把大象裝進冰箱需要3步一樣,用Matplotlib繪圖一般也可以分3步。下面以plt接口繪圖爲例,面向對象接口繪圖流程完全一致,僅僅是個別接口方法名略有改動:

 

  • 創建畫板,包括創建figure和axes對象,常用有3種方法

  • plt.figure,主要接收一個元組作爲figsize參數設置圖形大小,返回一個figure對象用於提供畫板

  • plt.axes,接收一個figure或在當前畫板上添加一個子圖,返回該axes對象,並將其設置爲"當前"圖,缺省時會在繪圖前自動添加

  • plt.subplot,主要接收3個數字或1個3位數(自動解析成3個數字,要求解析後數值合理)作爲子圖的行數、列數和當前子圖索引,索引從1開始(與MATLAB保存一致),返回一個axes對象用於繪圖操作。這裏,可以理解成是先隱式執行了plt.figure,然後在創建的figure對象上添加子圖,並返回當前子圖實例

  • plt.subplots,主要接收一個行數nrows和列數ncols作爲參數(不含第三個數字),創建一個figure對象和相應數量的axes對象,同時返回該figure對象和axes對象嵌套列表,並默認選擇最後一個子圖作爲"當前"圖

▲plt.subplots同時返回figure和axes實例,默認將最後一個axes子圖作爲"當前"圖

 

  • 繪製圖表,常用圖表形式包括:

  • plot,折線圖或點圖,實際是調用了line模塊下的Line2D圖表接口

  • scatter,散點圖,常用於表述兩組數據間的分佈關係,也可由特殊形式下的plot實現

  • bar/barh,條形圖或柱狀圖,常用於表達一組離散數據的大小關係,比如一年內每個月的銷售額數據;默認豎直條形圖,可選barh繪製水平條形圖

  • hist,直方圖,形式上與條形圖很像,但表達意義卻完全不同:直方圖用於統計一組連續數據的分區間分佈情況,比如有1000個正態分佈的隨機抽樣,那麼其直方圖應該是大致滿足鍾型分佈;條形圖主要是適用於一組離散標籤下的數量對比

  • pie,餅圖,主要用於表達構成或比例關係,一般適用於少量對比

  • imshow,顯示圖像,根據像素點數據完成繪圖並顯示

▲plot接口文檔及部分參數

 

當然,各圖表接口參數繁多且不盡一致,全部熟記幾乎不現實,可僅記住常用參數及相關可選項,其他留作使用時查閱即可。

 

  • 配置圖例:對所繪圖形進一步添加圖例元素,例如設置標題、座標軸、文字說明等,常用接口如下:

  • title,設置圖表標題

  • axis/xlim/ylim,設置相應座標軸範圍,其中axis是對後xlim和ylim的集成,接受4個參數分別作爲x和y軸的範圍參數

  • grid,添加圖表網格線

  • legend,在圖表中添加label圖例參數後,通過legend進行顯示

  • xlabel/ylabel,分別用於設置x、y軸標題

  • xticks/yticks,分別用於自定義座標軸刻度顯示

  • text/arrow/annotation,分別在圖例指定位置添加文字、箭頭和標記,一般很少用

▲關於圖例配置的官方解釋

 

▲plt接口繪圖中配置常用圖例

 

前面提到,繪圖接口有2種形式,分別是面向"當前"圖的plt接口和麪向對象接口,在這2種方式的相應接口中,多數接口名是一致的,例如:plt.plot()和axes.plot()、plt.legend()和axes.legend(),但也有一些不一致的接口:

 

  • plt.axes()——fig.add_axes()

  • plt.subplot()——fig.add_subplot()

  • plt.GridSped()——fig.add_gridspec()

  • plt.xlabel()——axes.set_xlabel()

  • plt.ylabel()——axes.set_ylabel()

  • plt.xlim()——axes.set_xlim()

  • plt.ylim()——axes.set_ylim()

  • plt.title()——axes.set_title()

 

對此,一方面兩類接口雖然略有區別,但也還算有規律;另一方面,在面向對象繪圖配置圖例時,有更爲便捷的設置圖例接口axes.set(),其可以接收多種參數一次性完成所有配置,這也正是面向對象繪圖的強大之處。

 

 

04 自定義子圖

 

 

前面提到,figure爲繪圖創建了畫板,而axes基於當前畫板創建了1個或多個子圖對象。爲了創建各種形式的子圖,Matplotlib主要支持4種添加子圖的方式。

 

常用的添加子圖的方法莫過於subplot和subplots兩個接口,其中前者用於一次添加一個子圖,而後者則是創建一組子圖。

 

除此之外,plt.axes也可通過接收尺寸參數實現多子圖繪製:在添加子圖時傳入一個含有4個數值的元組,分別表示子圖的底座標和左座標(設置子圖原點位置)、寬度和高度(設置子圖大小),從而間接實現子圖僅佔據畫板的一塊子區域。

 

相應的方法接口在面向對象接口中是fig.add_axes(),僅僅是接口名字不同,但參數和原理是一致的。例如:

 

▲應用plt.axes繪製多子圖

 

通過axes繪製多子圖,應對簡單需求尚可,但面對複雜圖表繪製時難免過於繁瑣:需要手工計算各子圖的原點位置和大小,意味着可能需要多次嘗試。此時,可選的另一種繪製多子圖的接口是plt.GridSpec。

 

實際上,GridSpec只是對subplot接口的一個變形,本質上仍然是執行類似subplot多子圖流程:通過切片將多子圖合併,實現不規則多子圖的繪製。與subplot、axes在面向對象和plt兩類繪圖接口間的區別類似,GridSpec在面向對象時的接口爲add_gridspec()。

 

這裏直接給出官網的一個繪製圖例,具體可查看官方示例代碼:

▲應用plt.GridSpec實現複雜多子圖繪製

 

 

05 自定義配置

 

實際上,前述在配置圖例過程中,每次繪製都需要進行大量自定義代碼設置(這也是Matplotlib的一個短板),在少量繪圖工作時尚可接受,但在大量相似繪圖存在重複操作時,仍然採取這一方法不會是一個明智的選擇(雖然也可以簡單的封裝成一個函數)。

 

爲此,Matplotlib提供了自定義參數實現批量配置——rcParams,全稱runtime configuration Parameters,即運行時配置參數。顧名思義,就是在Python程序運行時臨時執行的配置參數。

 

rcParams是一個字典格式,當前共有299個鍵值對,分別對應一組參數配置選項。其中用得最多的可能是通過設置字體和減號編碼來解決亂碼的問題,但實際上它的功能強大之處可遠非如此。

 

▲設置rcParams解決中文亂碼的問題

 

另一個簡單易用的自定義配置選項是style,即設置繪圖風格,最早在Matplotlib1.4版本中引入,當前共支持26種繪圖風格,這裏的繪圖風格類似於很多IDE支持不同主題。可以通過plt.style.available命令查看,返回一個可選風格的列表。例如,以下命令設置繪圖爲senborn風格:

 

▲設置seaborn繪圖風格

 

 

06 走向3D

 

在可視化愈發重要的當下,Matplotlib當然不僅支持簡單的2D圖表繪製,其也提供了對3D繪圖的豐富接口。

 

  • contour,實際上是一個僞3D圖形,仍然是在2維空間繪圖,但可以表達3維信息。例如在機器學習中,contour常用於繪製分類算法的超平面:

 

 

如果需要繪製真3D圖形,則需要額外導入Matplotlib專用3D繪圖庫:mpl_toolkits,包括3D版的Axes對象和常用圖表的3D版:

 

  • plot3D,3D版plot,可用於繪製3維空間的折線圖或點圖

  • scatter3D,3維散點圖

  • bar3D,3維條形圖

  • contour3D,3維等高線

 

 

07 更高級的封裝

 

Matplotlib提供了大量豐富的可視化繪圖接口,但仍然存在短板:例如繪圖操作略顯繁瑣、圖表不夠美觀。爲此,在Matplotlib基礎上產生了一些封裝更爲便捷的可視化庫,實現更爲簡單易用的接口和美觀的圖表形式,包括:

 

  • pandas.plot,一個最直接的對Matplotlib繪圖的封裝,接口方法非常接近

  • seaborn,是對Matplotlib的高級封裝,具有更爲美觀的圖形樣式和顏色配置,並提供了常用的統計圖形接口,如pairplot()適用於表達多組數據間的關係

  • ggplot,也是對Matplotlib進行二次封裝的可視化庫,主要適用於pandas的DataFrame數據結構

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章