8.3 Matplotlib 可視化
原文:Visualization with Matplotlib
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
本節(jié)是《Python 數(shù)據(jù)科學手冊》(Python Data Science Handbook)的摘錄瓢谢。
我們現(xiàn)在將深入研究M atplotlib 包,以便在 Python 中進行可視化忘分。Matplotlib 是一個基于 NumPy 數(shù)組的多平臺數(shù)據(jù)可視化庫,旨在兼容更廣泛的 SciPy 技術(shù)棧。它由 John Hunter 在 2002 年構(gòu)思捐顷,最初是作為 IPython 的補丁舷暮,用于通過來自 IPython 命令行的gnuplot
實現(xiàn) MATLAB 風格的交互式繪圖铲敛。
IPython 的創(chuàng)始人 Fernando Perez 當時正努力完成他的博士學位待错,并且 John 知道他幾個月都沒時間審查補丁籽孙。John 把它看做一個使自己開始的動機,之后 Matplotlib 軟件包誕生了火俄,2003 年發(fā)布了 0.1 版本。當它被用作太空望遠鏡科學研究所(哈勃望遠鏡背后的人)選擇的繪圖包時讲冠,它得到了早期的贊助瓜客,該研究所在財務(wù)上支持了 Matplotlib 的開發(fā),并極大地擴展了它的能力竿开。
Matplotlib 最重要的功能之一是谱仪,它能夠很好地兼容許多操作系統(tǒng)和圖形后端。Matplotlib 支持許多后端和輸出類型否彩,這意味著無論你使用哪種操作系統(tǒng)或你希望使用哪種輸出格式疯攒,你都可以依賴它。
這種跨平臺的通用方法是 Matplotlib 的強大優(yōu)勢之一列荔。它帶來了龐大的用戶群敬尺,這反過來又產(chǎn)生了活躍的開發(fā)人員的基礎(chǔ),和 Python 科學世界中的 Matplotlib 的威力和普遍性贴浙。
然而砂吞,近年來,Matplotlib 的界面和風格已經(jīng)有些過時崎溃。
比起 R 語言中的ggplot
和ggvis
等新工具蜻直,以及基于 D3js 和 HTML5 畫布的 Web 可視化工具包,Matplotlib 顯得笨重和陳舊袁串。盡管如此概而,我認為我們不能忽視 Matplotlib 作為經(jīng)過良好測試的跨平臺圖形引擎的優(yōu)勢。
最近的 Matplotlib 版本囱修,使得設(shè)置新的全局繪圖樣式變得相對容易(參見“自定義 Matplotlib:配置和樣式表”)赎瑰,人們一直在開發(fā)新的包,它們基于 Matplotlib 的強大內(nèi)核蔚袍,通過更清潔乡范,更現(xiàn)代的 API 驅(qū)動 Matplotlib - 例如配名,Seaborn(“可視化與 Seaborn”),[ggpy](http://yhat.github.io/ggpy /)晋辆,HoloViews渠脉,Altair,甚至 Pandas 本身都可以用作 Matplotlib API 的包裝瓶佳。
即使使用這樣的包裝器芋膘,通常也可以深入研究 Matplotlib 的語法來調(diào)整最終的繪圖輸出。出于這個原因霸饲,我相信 Matplotlib 本身为朋,仍將是數(shù)據(jù)可視化技術(shù)棧的重要組件,即使新工具意味著社區(qū)逐漸不再使用 Matplotlib API厚脉。
一般 Matplotlib 提示
在我們深入了解使用 Matplotlib 創(chuàng)建可視化的細節(jié)之前习寸,你應(yīng)該了解一些使用該軟件包的有用信息。
導入 Matplotlib
正如我們對 NumPy 使用np
簡寫傻工,對 Pandas 使用pd
簡寫一樣霞溪,我們將對 Matplotlib 導入使用一些標準簡寫:
import matplotlib as mpl
import matplotlib.pyplot as plt
我們將經(jīng)常使用plt
接口,我們將在本章中看到中捆。
設(shè)置樣式
我們將使用plt.style
指令鸯匹,為我們的圖形選擇合適的美學風格。在這里泄伪,我們將設(shè)置classic
樣式殴蓬,確保我們創(chuàng)建的圖使用經(jīng)典的 Matplotlib 樣式:
plt.style.use('classic')
在本節(jié)中,我們將按需調(diào)整此樣式蟋滴。請注意染厅,此處使用的樣式表從 Matplotlib 1.5 版開始得到支持;如果你使用的是早期版本的 Matplotlib 脓杉,則只能使用默認樣式糟秘。樣式表的更多信息,請參閱“自定義 Matplotlib:配置和樣式表”球散。
show()
還是不show()
尿赚?如何展示你的繪圖
你看不到的可視化并沒什么用,但是你查看 Matplotlib 繪圖的方式取決于上下文蕉堰。Matplotlib 的最佳用法取決于你的使用方式凌净;粗略地說,三個適用的上下文是屋讶,在腳本冰寻,IPython 終端或 IPython 筆記本中使用 Matplotlib。
來自腳本的繪圖
如果你在腳本中使用 Matplotlib皿渗,函數(shù)plt.show()
就是你的伙伴斩芭。plt.show()
啟動一個事件循環(huán)轻腺,查找所有當前活動的圖形對象,并打開一個或多個顯示你的圖形的交互式窗口划乖。
因此贬养,例如,你可能有一個名為myplot.py
的文件琴庵,其中包含以下內(nèi)容:
# ------- 文件:myplot.py ------
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))
plt.show()
然后误算,你可以從命令行運行此腳本,這將打開一個窗口并顯示你的圖形:
$ python myplot.py
plt.show()
命令做了很多工作迷殿,因為它必須與系統(tǒng)的交互式圖形后端進行交互儿礼。此操作的細節(jié)可能因不同系統(tǒng),甚至安裝而異庆寺,但 matplotlib 會盡力對你隱藏所有這些細節(jié)蚊夫。
有一點需要注意:plt.show()
命令應(yīng)該在每個 Python 會話中只使用一次,并且最常見于腳本的最后止邮。多個show()
命令可能產(chǎn)生不可預測的后端依賴的行為这橙,并且多數(shù)情況下應(yīng)該避免。
來自 IPython shell 的繪圖
在 IPython shell 中以交互方式使用 Matplotlib 非常方便(參見“IPython:不只是普通的 Python”)导披。如果指定 Matplotlib 模式,IPython 可以很好地配合 Matplotlib埃唯。要啟用此模式撩匕,可以在啟動ipython
后使用%matplotlib
魔術(shù)命令:
In [1]: %matplotlib
Using matplotlib backend: TkAgg
In [2]: import matplotlib.pyplot as plt
此時,任何plt
繪圖命令都會打開一個圖形窗口墨叛,可以運行更多命令來更新繪圖止毕。一些更改(例如修改已繪制的直線的屬性)將不會自動繪制:要強制更新,請使用plt.draw()
漠趁。不需要在 Matplotlib 模式下使用plt.show()
扁凛。
來自 IPython 筆記本的繪圖
IPython 筆記本是一個基于瀏覽器的,交互式數(shù)據(jù)分析工具闯传,可以將敘述谨朝,代碼,圖形甥绿,HTML 元素等組合到一個可執(zhí)行文檔中(參見“IPython:不只是普通的 Python”)字币。
IPython 筆記本中的交互式繪圖,可以使用%matplotlib
命令完成共缕,其工作方式與 IPython shell 類似洗出。在 IPython 筆記本中,你還可以選擇直接在筆記本中嵌入圖形图谷,有兩種可能的選擇:
-
%matplotlib notebook
將產(chǎn)生嵌入在筆記本中的交互式繪圖 -
%matplotlib inline
將產(chǎn)生嵌入在筆記本中的繪圖的靜態(tài)圖像
對于本書翩活,我們通常會選擇%matplotlib inline
:
%matplotlib inline
運行此命令后(每個內(nèi)核/會話只需執(zhí)行一次)阱洪,筆記本中創(chuàng)建繪圖的任何單元格,都將嵌入所得圖形的 PNG 圖像:
import numpy as np
x = np.linspace(0, 10, 100)
fig = plt.figure()
plt.plot(x, np.sin(x), '-')
plt.plot(x, np.cos(x), '--');
將圖形保存到文件
Matplotlib 的一個很好的功能菠镇,是以各種格式保存圖形的能力冗荸。保存圖形可以使用savefig()
命令完成。例如辟犀,要將上一個圖形保存為 PNG 文件俏竞,可以運行以下命令:
fig.savefig('my_figure.png')
在當前工作目錄中,我們現(xiàn)在有一個名為my_figure.png
的文件:
!ls -lh my_figure.png
# -rw-r--r-- 1 jakevdp staff 16K Aug 11 10:59 my_figure.png
為了確認它包含我們認為它包含的內(nèi)容堂竟,讓我們使用 IPython Image
對象來顯示該文件的內(nèi)容:
from IPython.display import Image
Image('my_figure.png')
在savefig()
中魂毁,文件格式是從給定文件名的擴展名推斷出來的。根據(jù)你安裝的后端出嘹,可以使用許多不同的文件格式席楚。通過使用圖形畫布對象的以下方法,可以找到系統(tǒng)支持的文件類型列表:
fig.canvas.get_supported_filetypes()
'''
{'eps': 'Encapsulated Postscript',
'jpeg': 'Joint Photographic Experts Group',
'jpg': 'Joint Photographic Experts Group',
'pdf': 'Portable Document Format',
'pgf': 'PGF code for LaTeX',
'png': 'Portable Network Graphics',
'ps': 'Postscript',
'raw': 'Raw RGBA bitmap',
'rgba': 'Raw RGBA bitmap',
'svg': 'Scalable Vector Graphics',
'svgz': 'Scalable Vector Graphics',
'tif': 'Tagged Image File Format',
'tiff': 'Tagged Image File Format'}
'''
請注意税稼,在保存圖形時烦秩,不必使用前面討論過的plt.show()
或相關(guān)命令。
一個功能的兩個接口
Matplotlib 的一個可能令人困惑的特性是它的兩個接口:一個是方便的 MATLAB 風格的郎仆,基于狀態(tài)的接口只祠,以及一個更強大的面向?qū)ο蟮慕涌凇N覀儗⒃谶@里快速強調(diào)兩者之間的差異扰肌。
MATLAB 風格的接口
Matplotlib 最初編寫為 MATLAB 用戶的 Python 替代品抛寝,其大部分語法都反映了這一事實。MATLAB 風格的工具包含在pyplot
(plt
)接口中曙旭。例如盗舰,以下代碼可能對 MATLAB 用戶來說非常熟悉:
plt.figure() # 創(chuàng)建繪圖圖形
# 創(chuàng)建兩個面板的第一個并設(shè)置當前軸
plt.subplot(2, 1, 1) # 行,列桂躏,面板號
plt.plot(x, np.sin(x))
# 創(chuàng)建第二個面板并設(shè)置當前軸
plt.subplot(2, 1, 2)
plt.plot(x, np.cos(x));
重要的是要注意這個接口是有狀態(tài)的:它跟蹤“當前”圖形和軸域钻趋,這是所有plt
命令都適用的地方。你可以使用plt.gcf()
(獲取當前圖形)和plt.gca()
(獲取當前軸域)例程來獲取這些引用剂习。
雖然這種狀態(tài)接口對于簡單的繪圖來說既快速又方便蛮位,但很容易遇到問題。例如进倍,一旦創(chuàng)建了第二個面板土至,我們?nèi)绾畏祷夭⑾虻谝粋€面板添加內(nèi)容?這在 MATLAB 風格的接口中是可能的猾昆,但有點笨拙陶因。幸運的是,有一種更好的方法垂蜗。
面向?qū)ο蟮慕涌?/h4>
面向?qū)ο蟮慕涌诳捎糜谶@些更復雜的情況楷扬,以及需要對圖形進行更多控制的時候解幽。在面向?qū)ο蟮慕缑嬷校L圖函數(shù)并不依賴于“活動”圖形或軸域的某些概念烘苹,而是顯式“圖形”和“軸域”對象的方法躲株。要使用此風格的繪圖重新創(chuàng)建上一個繪圖,你可以執(zhí)行以下操作:
# 首先創(chuàng)建繪圖網(wǎng)格
# ax will be an array of two Axes objects
fig, ax = plt.subplots(2)
# 在對應(yīng)對象上調(diào)用 plot() 方法
ax[0].plot(x, np.sin(x))
ax[1].plot(x, np.cos(x));
對于更簡單的圖镣衡,選擇使用哪種樣式在很大程度上取決于偏好霜定,但隨著變得更復雜,面向?qū)ο蟮姆椒赡艹蔀楸匾扰浮T诒菊轮型疲覀儗⒏鶕?jù)最方便的方式,在 MATLAB風 格和面向?qū)ο蟮慕缑嬷g切換惰说。在大多數(shù)情況下磨德,差異就像切換plt.plot()
到ax.plot()
一樣小,但是在下面的章節(jié)中我們會強調(diào)一些問題吆视。