Python matplotlib高階繪圖詳解
1. 前言
前面我們介紹了使用matplotlib簡單的繪圖方法(見:Python應用matplotlib繪圖簡介 )
但是想要完全控制你的圖形,以及更高階的用法,就需要使用 pyplot 的介面顯式的建立圖形figure。
本文介紹plyplot控制繪圖的一些方法。
2. Pyplot繪圖結構
Aritists
matplotlib API包含有三層:
- backend_bases.FigureCanvas : 圖表的繪製領域
- backend_bases.Renderer : 知道如何在FigureCanvas上如何繪圖
- artist.Artist : 知道如何使用Renderer在FigureCanvas上繪圖
FigureCanvas和Renderer需要處理底層的繪圖操作,例如使用wxPython在介面上繪圖,或者使用PostScript繪製PDF。Artist則處理所有的高層結構,例如處理圖表、文字和曲線等的繪製和佈局。通常我們只和Artist打交道,而不需要關心底層的繪製細節。
Artists分為簡單型別和容器型別兩種。簡單型別的Artists為標準的繪圖元件,例如Line2D、 Rectangle、 Text、AxesImage 等等。而容器型別則可以包含許多簡單型別的Artists,使它們組織成一個整體,例如Axis、 Axes、Figure等。
Figure
Figure代表一個繪製面板,其中可以包涵多個Axes(即多個圖表)。
fig = plt.figure() # an empty figure with no axes
ax = fig.add_axes([0.15, 0.1, 0.7, 0.3])
#或者採用一下方式
fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes
Axes
Axes表示一個圖表
一個Axes包涵:titlek, xaxis, yaxis
Axis
座標軸
3. Artist的屬性
下面是Artist物件都具有的一些屬性:
alpha : 透明度,值在0到1之間,0為完全透明,1為完全不透明
animated : 布林值,在繪製動畫效果時使用
axes : 此Artist物件所在的Axes物件,可能為None
clip_box : 物件的裁剪框
clip_on : 是否裁剪
clip_path : 裁剪的路徑
contains : 判斷指定點是否在物件上的函式
figure : 所在的Figure物件,可能為None
label : 文字標籤
picker : 控制Artist物件選取
transform : 控制偏移旋轉
visible : 是否可見
zorder : 控制繪圖順序
Artist物件的所有屬性都通過相應的 get_* 和 set_* 函式進行讀寫
fig.set_alpha(0.5*fig.get_alpha())
如果你想用一條語句設定多個屬性的話,可以使用set函式:
fig.set(alpha=0.5, zorder=2)
使用 matplotlib.pyplot.getp 函式可以方便地輸出Artist物件的所有屬性名和值。
>>> plt.getp(fig.patch)
aa = True
alpha = 1.0
animated = False
antialiased or aa = True
4. Figure
如前所述,Figure是最大的一個Aritist,它包括整幅影象的所有元素,背景是一個Rectangle物件,用Figure.patch屬性表示。
通過呼叫add_subplot或者add_axes方法往圖表中新增Axes(子圖)。
PS:這兩個方法返回值型別不同
>>> fig = plt.figure()
>>> ax1 = fig.add_subplot(211)
>>> ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])
>>> ax1
<matplotlib.axes.AxesSubplot object at 0x056BCA90>
>>> ax2
<matplotlib.axes.Axes object at 0x056BC910>
>>> fig.axes
[<matplotlib.axes.AxesSubplot object at 0x056BCA90>,
<matplotlib.axes.Axes object at 0x056BC910>]
為了支援pylab中的gca()等函式,Figure物件內部儲存有當前軸的資訊,因此不建議直接對Figure.axes屬性進行列表操作,而應該使用add_subplot, add_axes, delaxes等方法進行新增和刪除操作。
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.45, 0.8, 0.5])
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.2])
plt.show()
Figure物件可以擁有自己的文字、線條以及影象等簡單型別的Artist。預設的座標系統為畫素點,但是可以通過設定Artist物件的transform屬性修改座標系的轉換方式。最常用的Figure物件的座標系是以左下角為座標原點(0,0),右上角為座標(1,1)。下面的程式建立並新增兩條直線到fig中:
>>> from matplotlib.lines import Line2D
>>> fig = plt.figure()
>>> line1 = Line2D([0,1],[0,1], transform=fig.transFigure, figure=fig, color="r")
>>> line2 = Line2D([0,1],[1,0], transform=fig.transFigure, figure=fig, color="g")
>>> fig.lines.extend([line1, line2])
>>> fig.show()
在Figure物件中手工繪製直線
注意為了讓所建立的Line2D物件使用fig的座標,我們將fig.TransFigure賦給Line2D物件的transform屬性;為了讓Line2D物件知道它是在fig物件中,我們還設定其figure屬性為fig;最後還需要將建立的兩個Line2D物件新增到fig.lines屬性中去。
Figure物件有如下屬性包含其它的Artist物件:
axes : Axes物件列表
patch : 作為背景的Rectangle物件
images : FigureImage物件列表,用來顯示圖片
legends : Legend物件列表
lines : Line2D物件列表
patches : patch物件列表
texts : Text物件列表,用來顯示文字
5. Axes
Axes容器是整個matplotlib庫的核心,它包含了組成圖表的眾多Artist物件,並且有許多方法函式幫助我們建立、修改這些物件。和Figure一樣,它有一個patch屬性作為背景,
當它是笛卡爾座標時,patch屬性是一個Rectangle物件;
當它是極座標時,patch屬性則是Circle物件。
當你呼叫Axes的繪圖方法(例如plot),它將建立一組Line2D物件,並將所有的關鍵字引數傳遞給這些Line2D物件,並將它們新增進Axes.lines屬性中,最後返回所建立的Line2D物件列表:
x1 = np.linspace(0.0, 5.0)
x2 = np.linspace(0.0, 3.0)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
y2 = np.cos(2 * np.pi * x2)
ax1.patch.set_facecolor("green")
ax1.grid(True)
line1 = ax1.plot(x1, y1, 'yo-', label="Test1")
print type(line1)
print line1
line2 = ax2.plot(x2, y2, 'r.-', label='Test2')
-----
<type 'list'>
[<matplotlib.lines.Line2D object at 0x7fa3ac96e8d0>]
注意:
plot返回的是一個Line2D物件的列表,因為我們可以傳遞多組X,Y軸的資料,一次繪製多條曲線。
與plot方法類似,繪製直方圖的方法bar和繪製柱狀統計圖的方法hist將建立一個Patch物件的列表,每個元素實際上都是Patch的子類Rectangle,並且將所建立的Patch物件都新增進Axes.patches屬性中:
>>> ax = fig.add_subplot(111)
>>> n, bins, rects = ax.hist(np.random.randn(1000), 50, facecolor="blue")
>>> rects
<a list of 50 Patch objects>
>>> rects[0]
<matplotlib.patches.Rectangle object at 0x05BC2350>
>>> ax.patches[0]
<matplotlib.patches.Rectangle object at 0x05BC2350>
一般我們不會直接對Axes.lines或者Axes.patches屬性進行操作,而是呼叫add_line或者add_patch等方法,這些方法幫助我們完成許多屬性設定工作:
>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> rect = matplotlib.patches.Rectangle((1,1), width=5, height=12)
>>> print rect.get_axes() # rect的axes屬性為空
None
>>> rect.get_transform() # rect的transform屬性為預設值
BboxTransformTo(Bbox(array([[ 1., 1.],
[ 6., 13.]])))
>>> ax.add_patch(rect) # 將rect新增進ax
<matplotlib.patches.Rectangle object at 0x05C34E50>
>>> rect.get_axes() # 於是rect的axes屬性就是ax
<matplotlib.axes.AxesSubplot object at 0x05C09CB0>
>>> # rect的transform屬性和ax的transData相同
>>> rect.get_transform()
... # 太長,省略
>>> ax.transData
... # 太長,省略
>>> ax.get_xlim() # ax的X軸範圍為0到1,無法顯示完整的rect
(0.0, 1.0)
>>> ax.dataLim._get_bounds() # 資料的範圍和rect的大小一致
(1.0, 1.0, 5.0, 12.0)
>>> ax.autoscale_view() # 自動調整座標軸範圍
>>> ax.get_xlim() # 於是X軸可以完整顯示rect
(1.0, 6.0)
>>> plt.show()
通過上面的例子我們可以看出,add_patch方法幫助我們設定了rect的axes和transform屬性。
下面詳細列出Axes包含各種Artist物件的屬性:
artists : Artist物件列表
patch : 作為Axes背景的Patch物件,可以是Rectangle或者Circle
collections : Collection物件列表
images : AxesImage物件列表
legends : Legend物件列表
lines : Line2D物件列表
patches : Patch物件列表
texts : Text物件列表
xaxis : XAxis物件
yaxis : YAxis物件
下面列出Axes的建立Artist物件的方法:
Axes的方法 | 所建立的物件 | 新增進的列表 |
---|---|---|
annotate | Annotate | texts |
bars | Rectangle | patches |
errorbar | Line2D, Rectangle | lines,patches |
fill | Polygon | patches |
hist | Rectangle | patches |
imshow | AxesImage | images |
legend | Legend | legends |
plot | Line2D | lines |
scatter | PolygonCollection | Collections |
text | Text | texts |
6. Axis
Axis容器包括座標軸上的刻度線、刻度文字、座標網格以及座標軸標題等內容。刻度包括主刻度和副刻度,分別通過Axis.get_major_ticks和Axis.get_minor_ticks方法獲得。每個刻度線都是一個XTick或者YTick物件,它包括實際的刻度線和刻度文字。為了方便訪問刻度線和文字,Axis物件提供了get_ticklabels和get_ticklines方法分別直接獲得刻度線和刻度文字
>>> axis.get_ticklocs() # 獲得刻度的位置列表
array([ 1. , 1.5, 2. , 2.5, 3. ])
>>> axis.get_ticklabels() # 獲得刻度標籤列表
<a list of 5 Text major ticklabel objects>
>>> [x.get_text() for x in axis.get_ticklabels()] # 獲得刻度的文字字串
[u'1.0', u'1.5', u'2.0', u'2.5', u'3.0']
>>> axis.get_ticklines() # 獲得主刻度線列表,圖的上下刻度線共10條
<a list of 10 Line2D ticklines objects>
>>> axis.get_ticklines(minor=True) # 獲得副刻度線列表
<a list of 0 Line2D ticklines objects>