1. 程式人生 > >Python matplotlib高階繪圖詳解

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>

7. 參考文獻: