天天看點

Matplotlib 中文使用者指南 3.5 藝術家教程藝術家教程

藝術家教程

原文: Artist tutorial 譯者: 飛龍 協定: CC BY-NC-SA 4.0

matplotlib API 有三個層級。

matplotlib.backend_bases.FigureCanvas

是繪制圖形的區域,

matplotlib.backend_bases.Renderer

是知道如何在

ChartCanvas

上繪制的對象,而

matplotlib.artist.Artist

是知道如何使用渲染器在畫布上畫圖的對象。

FigureCanvas

Renderer

處理與使用者界面工具包(如 wxPython)或 PostScript® 等繪圖語言互動的所有細節,

Artist

處理所有進階結構,如表示和布局圖形,文本和線條。使用者通常要花費95%的時間來處理藝術家。

有兩種類型的藝術家:基本類型和容器類型。基本類型表示我們想要繪制到畫布上的标準圖形對象:

Line2D

Rectangle

Text

AxesImage

等,容器是放置它們的位置(

Axis

Axes

Figure

)。标準用法是建立一個

Figure

執行個體,使用

Figure

建立一個或多個

Axes

Subplot

執行個體,并使用

Axes

執行個體的輔助方法來建立基本類型。在下面的示例中,我們使用

matplotlib.pyplot.figure()

建立一個

Figure

執行個體,這是一個便捷的方法,用于執行個體化

Figure

執行個體并将它們與你的使用者界面或繪圖工具包

FigureCanvas

連接配接。正如我們将在下面讨論的,這不是必須的 - 你可以直接使用 PostScript,PDF,Gtk+ 或 wxPython

FigureCanvas

執行個體,直接執行個體化你的圖形并連接配接它們 - 但是因為我們在這裡關注藝術家 API,我們讓

pyplot

為我們處理一些細節:

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(2,1,1) # two rows, one column, first plot           

Axes

可能是 matplotlib API 中最重要的類,你将在大多數時間使用它。 這是因為

Axes

是大多數對象所進入的繪圖區域,

Axes

有許多特殊的輔助方法(

plot()

text()

hist()

imshow()

)來建立最常見的圖形基本類型

Line2D

Text

Rectangle

Image

)。 這些輔助方法将擷取你的資料(例如 numpy 數組和字元串),并根據需要建立基本

Artist

執行個體(例如,

Line2D

),将它們添加到相關容器中,并在請求時繪制它們。 大多數人可能熟悉子圖,這隻是

Axes

的一個特例,它存在于

Subplot

執行個體的列網格的固定行上。 如果要在任意位置建立

Axes

,隻需使用

add_axes()

方法,該方法接受

[left, bottom, width, height]

值的清單,以 0~1 的圖形相對坐标為機關:

fig2 = plt.figure()
ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3])           

以我們的例子繼續:

import numpy as np
t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2*np.pi*t)
line, = ax.plot(t, s, color='blue', lw=2)           

在這個例子中,

ax

是上面的

fig.add_subplot

調用建立的

Axes

執行個體(記住

Subplot

隻是

Axes

的一個子類),當你調用

ax.plot

時,它建立一個

Line2D

執行個體并将其添加到

Axes.lines

清單中。 在下面的 ipython 互動式會話中,你可以看到

Axes.lines

清單的長度為 1,并且包含由

line, = ax.plot...

調用傳回的相同線條:

In [101]: ax.lines[0]
Out[101]: <matplotlib.lines.Line2D instance at 0x19a95710>

In [102]: line
Out[102]: <matplotlib.lines.Line2D instance at 0x19a95710>           

如果你對

ax.plot

進行連續調用(并且保持狀态為『on』,這是預設值),則将在清單中添加其他線條。 你可以稍後通過調用清單方法删除線條;任何一個方法都可以:

del ax.lines[0]
ax.lines.remove(line)  # one or the other, not both!           

軸域也擁有輔助方法,用于設定和裝飾 x 和 y 軸的刻度、刻度标簽和軸标簽:

xtext = ax.set_xlabel('my xdata') # returns a Text instance
ytext = ax.set_ylabel('my ydata')           

當你調用

ax.set_xlabel

時,它将資訊傳遞給

XAxis

Text

執行個體,每個

Axes

執行個體都包含

XAxis

YAxis

,它們處理刻度、刻度标簽和軸标簽的布局和繪制。

嘗試建立下面的圖形:

Matplotlib 中文使用者指南 3.5 藝術家教程藝術家教程

自定義你的對象

圖中的每個元素都由一個 matplotlib 藝術家表示,每個元素都有一個擴充屬性清單用于配置它的外觀。 圖形本身包含一個

Rectangle

,正好是圖形的大小,你可以使用它來設定圖形的背景顔色和透明度。 同樣,每個

Axes

邊框(在通常的 matplotlib 繪圖中是标準的白底黑邊)擁有一個

Rectangle

執行個體,用于确定軸域的顔色,透明度和其他屬性,這些執行個體存儲為成員變量

Figure.patch

Axes.patch

(『Patch』是一個繼承自 MATLAB 的名稱,它是圖形上的一個顔色的 2D『更新檔』,例如矩形,圓和多邊形)。每個 matplotlib 藝術家都有以下屬性。

屬性 描述
alpha 透明度 - 0 ~ 1 的标量
animated 用于幫助動畫繪制的布爾值
axes 藝術家所在的軸域,可能為空
clip_box 用于剪切藝術家的邊框
clip_on 剪切是否開啟
clip_path 藝術家被剪切的路徑
contains 一個拾取函數,用于判斷藝術家是否位于拾取點
figure 藝術家所在的圖形執行個體,可能為空
label 文本标簽(用于自動标記)
picker 控制對象拾取的 Python 對象
transform 變換
visible 布爾值,表示藝術家是否應該繪制
zorder 确定繪制順序的數值
rasterized 布爾值,是否将向量轉換為光栅圖形(出于壓縮或 eps 透明度)

每個屬性都使用一個老式的

setter

getter

(是的,我們知道這會刺激 Python 愛好者,我們計劃支援通過屬性或 traits 直接通路,但它還沒有完成)。 例如,要将目前

alpha

值變為一半:

a = o.get_alpha()
o.set_alpha(0.5*a)           

如果你打算可以一次性設定一些屬性,你也可以以關鍵字參數使用

set

方法,例如:

o.set(alpha=0.5, zorder=2)           

如果你在 Python 互動式 Shell 中工作,檢查

Artist

屬性的一種友善的方法是使用

matplotlib.artist.getp()

函數(在 pylab 中隻需要

getp()

),它列出了屬性及其值。 這适用于從

Artist

派生的類,例如

Figure

Rectangle

。 這裡是上面提到的

Figure

的矩形屬性:

In [149]: matplotlib.artist.getp(fig.patch)
    alpha = 1.0
    animated = False
    antialiased or aa = True
    axes = None
    clip_box = None
    clip_on = False
    clip_path = None
    contains = None
    edgecolor or ec = w
    facecolor or fc = 0.75
    figure = Figure(8.125x6.125)
    fill = 1
    hatch = None
    height = 1
    label =
    linewidth or lw = 1.0
    picker = None
    transform = <Affine object at 0x134cca84>
    verts = ((0, 0), (0, 1), (1, 1), (1, 0))
    visible = True
    width = 1
    window_extent = <Bbox object at 0x134acbcc>
    x = 0
    y = 0
    zorder = 1           

所有類的文檔字元串也包含

Artist

屬性,是以你可以查閱互動式『幫助』或

Artist

子產品

,來擷取給定對象的屬性清單。

對象容器

現在我們知道如何檢查和設定我們想要配置的給定對象的屬性,現在我們需要如何擷取該對象。 前面提到了兩種對象:基本類型和容器類型。 基本類型通常是你想要配置的東西(

Text

執行個體的字型,

Line2D

的寬度),雖然容器也有一些屬性 - 例如

Axes

是一個容器藝術家,包含你的繪圖中的許多基本類型,但它也有屬性,比如

xscale

來控制

xaxis

是『線性』還是『對數』。 在本節中,我們将回顧各種容器對象存儲你想要通路的藝術家的位置。

圖形容器

頂層容器藝術家是

matplotlib.figure.Figure

,它包含圖形中的所有内容。 圖形的背景是一個

Rectangle

,存儲在

Figure.patch

中。 當你向圖形中添加子圖(

add_subplot()

)和軸域(

add_axes()

)時,這些會附加到

Figure.axes

。 它們也由建立它們的方法傳回:

In [156]: fig = plt.figure()

In [157]: ax1 = fig.add_subplot(211)

In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])

In [159]: ax1
Out[159]: <matplotlib.axes.Subplot instance at 0xd54b26c>

In [160]: print fig.axes
[<matplotlib.axes.Subplot instance at 0xd54b26c>, <matplotlib.axes.Axes instance at 0xd3f0b2c>]           

因為圖形維護了『目前軸域』(見

figure.gca

和圖

figure.sca

)的概念以支援 pylab/pyplot 狀态機,是以不應直接從軸域清單中插入或删除軸域,而應使用

add_subplot()

add_axes()

方法進行插入,并使用

delaxes()

方法進行删除。 然而,你可以自由地周遊軸域清單或索引,來通路要自定義的

Axes

執行個體。 下面是一個打開所有軸域網格的示例:

for ax in fig.axes:
    ax.grid(True)           

圖形還擁有自己的文本,線條,更新檔和圖像,你可以使用它們直接添加基本類型。 圖形的預設坐标系統簡單地以像素(這通常不是你想要的)為機關,但你可以通過設定你添加到圖中的藝術家的

transform

屬性來控制它。

更有用的是『圖形坐标系』,其中

(0,0)

是圖的左下角,

(1,1)

是圖的右上角,你可以通過将

Artist

的變換設定為

fig.transFigure

來獲得:

In [191]: fig = plt.figure()

In [192]: l1 = matplotlib.lines.Line2D([0, 1], [0, 1],
           transform=fig.transFigure, figure=fig)

In [193]: l2 = matplotlib.lines.Line2D([0, 1], [1, 0],
           transform=fig.transFigure, figure=fig)

In [194]: fig.lines.extend([l1, l2])

In [195]: fig.canvas.draw()           
Matplotlib 中文使用者指南 3.5 藝術家教程藝術家教程

這裡是圖形可以包含的藝術家總結:

圖形屬性

axes

Axes

執行個體的清單(包括

Subplot

patch

Rectangle

背景

images

FigureImages

更新檔的清單 - 用于原始像素顯示

legends

圖形

Legend

執行個體的清單(不同于

Axes.legends

lines

Line2D

執行個體的清單(很少使用,見

Axes.lines

patches

圖形更新檔清單(很少使用,見

Axes.patches

texts

Text

執行個體的清單

軸域容器

matplotlib.axes.Axes

是 matplotlib 宇宙的中心 - 它包含絕大多數在一個圖形中使用的藝術家,并帶有許多輔助方法來建立和添加這些藝術家本身,以及通路和自定義所包含的藝術家的輔助方法。 就像

Figure

那樣,它包含一個

Patch patch

,它是一個用于笛卡爾坐标的

Rectangle

和一個用于極坐标的

Cirecle

; 這個更新檔決定了繪圖區域的形狀,背景和邊框:

ax = fig.add_subplot(111)
rect = ax.patch  # a Rectangle instance
rect.set_facecolor('green')           

當調用繪圖方法(例如通常是

plot()

)并傳遞數組或值清單時,該方法将建立一個

matplotlib.lines.Line2D()

執行個體,将所有

Line2D

屬性作為關鍵字參數傳遞, 将該線條添加到

Axes.lines

容器,并将其傳回給你:

In [213]: x, y = np.random.rand(2, 100)

In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2)           

plot

傳回一個線條清單,因為你可以傳入多個

x,y

偶對來繪制,我們将長度為一的清單的第一個元素解構到

line

變量中。 該線條已添加到

Axes.lines

清單中:

In [229]: print ax.lines
[<matplotlib.lines.Line2D instance at 0xd378b0c>]           

與之類似,建立更新檔的方法(如

bar()

)會建立一個矩形清單,将更新檔添加到

Axes.patches

In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50, facecolor='yellow')

In [234]: rectangles
Out[234]: <a list of 50 Patch objects>

In [235]: print len(ax.patches)           

你不應該直接将對象添加到

Axes.lines

Axes.patches

清單,除非你确切知道你在做什麼,因為

Axes

需要在它建立和添加對象做一些事情。 它設定

Artist

figure

axes

屬性,以及預設

Axes

變換(除非設定了變換)。 它還檢查

Artist

中包含的資料,來更新控制自動縮放的資料結構,以便可以調整視圖限制來包含繪制的資料。 但是,你可以自己建立對象,并使用輔助方法(如

add_line()

add_patch()

)将它們直接添加到

Axes

。 這裡是一個注釋的互動式會話,說明正在發生什麼:

In [261]: fig = plt.figure()

In [262]: ax = fig.add_subplot(111)

# create a rectangle instance
In [263]: rect = matplotlib.patches.Rectangle( (1,1), width=5, height=12)

# by default the axes instance is None
In [264]: print rect.get_axes()
None

# and the transformation instance is set to the "identity transform"
In [265]: print rect.get_transform()
<Affine object at 0x13695544>

# now we add the Rectangle to the Axes
In [266]: ax.add_patch(rect)

# and notice that the ax.add_patch method has set the axes
# instance
In [267]: print rect.get_axes()
Axes(0.125,0.1;0.775x0.8)

# and the transformation has been set too
In [268]: print rect.get_transform()
<Affine object at 0x15009ca4>

# the default axes transformation is ax.transData
In [269]: print ax.transData
<Affine object at 0x15009ca4>

# notice that the xlimits of the Axes have not been changed
In [270]: print ax.get_xlim()
(0.0, 1.0)

# but the data limits have been updated to encompass the rectangle
In [271]: print ax.dataLim.bounds
(1.0, 1.0, 5.0, 12.0)

# we can manually invoke the auto-scaling machinery
In [272]: ax.autoscale_view()

# and now the xlim are updated to encompass the rectangle
In [273]: print ax.get_xlim()
(1.0, 6.0)

# we have to manually force a figure draw
In [274]: ax.figure.canvas.draw()           

有非常多的

Axes

輔助方法用于建立基本藝術家并将它們添加到他們各自的容器中。 下表總結了他們的一部分,他們創造的

Artist

的種類,以及他們在哪裡存儲它們。

輔助方法 藝術家 容器

ax.annotate

- 文本标注

Annotate

ax.texts

ax.bar

- 條形圖

Rectangle

ax.patches

ax.errorbar

- 誤差條形圖

Line2D

Rectangle

ax.lines

ax.patches

ax.fill

- 共享區域

Polygon

ax.patches

ax.hist

- 直方圖

Rectangle

ax.patches

ax.imshow

- 圖像資料

AxesImage

ax.images

ax.legend

- 軸域圖例

Legend

ax.legends

ax.plot

- xy 繪圖

Line2D

ax.lines

ax.scatter

- 散點圖

PolygonCollection

ax.collections

ax.text

- 文本

Text

ax.texts

除了所有這些藝術家,

Axes

包含兩個重要的藝術家容器:

XAxis

YAxis

,它們處理刻度和标簽的繪制。 它們被存儲為執行個體變量

xaxis

yaxis

XAxis

YAxis

容器将在下面詳細介紹,但請注意,

Axes

包含許多輔助方法,它們會将調用轉發給

Axis

執行個體,是以你通常不需要直接使用它們,除非你願意。 例如,你可以使用

Axes

輔助程式方法設定

XAxis

刻度标簽的字型大小:

for label in ax.get_xticklabels():
    label.set_color('orange')           

下面是軸域所包含的藝術家的總結

軸域屬性

artists

Artist

patch

用于軸域背景的

Rectangle

執行個體

collections

Collection

images

AxesImage

的清單

legends

Legend

lines

Line2D

patches

Patch

texts

Text

xaxis

matplotlib.axis.XAxis

yaxis

matplotlib.axis.YAxis

軸容器

matplotlib.axis.Axis

執行個體處理刻度線,網格線,刻度标簽和軸标簽的繪制。你可以分别為y軸配置左和右刻度,為x軸分别配置上和下刻度。

Axis

還存儲在自動縮放,平移和縮放中使用的資料和視圖間隔,以及

Locator

Formatter

執行個體,它們控制刻度位置以及它們表示為字元串的方式。

每個

Axis

對象都包含一個

label

屬性(這是 pylab 在調用

xlabel()

ylabel()

時修改的東西)以及主和次刻度的清單。刻度是

XTick

YTick

執行個體,它包含渲染刻度和刻度标簽的實際線條和文本基本類型。因為刻度是按需動态建立的(例如,當平移和縮放時),你應該通過通路器方法

get_major_ticks()

get_minor_ticks()

通路主和次刻度的清單。雖然刻度包含所有下面要提及的基本類型,

Axis

方法包含通路器方法來傳回刻度線,刻度标簽,刻度位置等:

In [285]: axis = ax.xaxis

In [286]: axis.get_ticklocs()
Out[286]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])

In [287]: axis.get_ticklabels()
Out[287]: <a list of 10 Text major ticklabel objects>

# note there are twice as many ticklines as labels because by
#  default there are tick lines at the top and bottom but only tick
#  labels below the xaxis; this can be customized
In [288]: axis.get_ticklines()
Out[288]: <a list of 20 Line2D ticklines objects>

# by default you get the major ticks back
In [291]: axis.get_ticklines()
Out[291]: <a list of 20 Line2D ticklines objects>

# but you can also ask for the minor ticks
In [292]: axis.get_ticklines(minor=True)
Out[292]: <a list of 0 Line2D ticklines objects>           

下面是

Axis

的一些有用的通路器方法的總結(它們擁有相應的

setter

,如

set_major_formatter

)。

通路器方法
get_scale 軸的比例,例如

'log'

'linear'

get_view_interval 軸視圖範圍的内部執行個體
get_data_interval 軸資料範圍的内部執行個體
get_gridlines 軸的網格線清單
get_label 軸标簽 -

Text

get_ticklabels

Text

執行個體的清單 - 關鍵字`minor=True
get_ticklines

Line2D

get_ticklocs

Tick

位置的清單 - 關鍵字`minor=True
get_major_locator 用于主刻度的

matplotlib.ticker.Locator

get_major_formatter

matplotlib.ticker.Formatter

get_minor_locator 用于次刻度的

matplotlib.ticker.Locator

get_minor_formatter

matplotlib.ticker.Formatter

get_major_ticks

Tick

執行個體清單
get_minor_ticks

Tick

grid 為主或次刻度打開或關閉網格

這裡是個例子,出于美觀不太推薦,它自定義了軸域和刻度屬性。

import numpy as np
import matplotlib.pyplot as plt

# plt.figure creates a matplotlib.figure.Figure instance
fig = plt.figure()
rect = fig.patch # a rectangle instance
rect.set_facecolor('lightgoldenrodyellow')

ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4])
rect = ax1.patch
rect.set_facecolor('lightslategray')


for label in ax1.xaxis.get_ticklabels():
    # label is a Text instance
    label.set_color('red')
    label.set_rotation(45)
    label.set_fontsize(16)

for line in ax1.yaxis.get_ticklines():
    # line is a Line2D instance
    line.set_color('green')
    line.set_markersize(25)
    line.set_markeredgewidth(3)

plt.show()           
Matplotlib 中文使用者指南 3.5 藝術家教程藝術家教程

刻度容器

matplotlib.axis.Tick

是我們從

Figure

Axes

再到

Axis

Tick

的最終的容器對象。

Tick

包含刻度和網格線的執行個體,以及上側和下側刻度的标簽執行個體。 每個都可以直接作為

Tick

的屬性通路。此外,也有用于确定上标簽和刻度是否對應

x

軸,以及右标簽和刻度是否對應

y

軸的布爾變量。

刻度屬性

tick1line

Line2D

tick2line

Line2D

gridline

Line2D

label1

Text

label2

Text

gridOn

确定是否繪制刻度線的布爾值

tick1On

确定是否繪制主刻度線的布爾值

tick2On

确定是否繪制次刻度線的布爾值

label1On

确定是否繪制主刻度标簽的布爾值

label2On

确定是否繪制次刻度标簽的布爾值

這裡是個例子,使用美元符号設定右側刻度,并在

y

軸右側将它們設成綠色。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

# Fixing random state for reproducibility
np.random.seed(19680801)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(100*np.random.rand(20))

formatter = ticker.FormatStrFormatter('$%1.2f')
ax.yaxis.set_major_formatter(formatter)

for tick in ax.yaxis.get_major_ticks():
    tick.label1On = False
    tick.label2On = True
    tick.label2.set_color('green')

plt.show()           
Matplotlib 中文使用者指南 3.5 藝術家教程藝術家教程