藝術(shù)家教程
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
matplotlib API 有三個層級。 matplotlib.backend_bases.FigureCanvas
是繪制圖形的區(qū)域,matplotlib.backend_bases.Renderer
是知道如何在ChartCanvas
上繪制的對象,而matplotlib.artist.Artist
是知道如何使用渲染器在畫布上畫圖的對象。 FigureCanvas
和Renderer
處理與用戶界面工具包(如 wxPython)或 PostScript? 等繪圖語言交互的所有細(xì)節(jié),Artist
處理所有高級結(jié)構(gòu),如表示和布局圖形,文本和線條。用戶通常要花費(fèi)95%的時間來處理藝術(shù)家。
有兩種類型的藝術(shù)家:基本類型和容器類型。基本類型表示我們想要繪制到畫布上的標(biāo)準(zhǔn)圖形對象:Line2D
,Rectangle
,Text
,AxesImage
等,容器是放置它們的位置(Axis
,Axes
和Figure
)。標(biāo)準(zhǔn)用法是創(chuàng)建一個Figure
實例,使用Figure
創(chuàng)建一個或多個Axes
或Subplot
實例,并使用Axes
實例的輔助方法來創(chuàng)建基本類型。在下面的示例中,我們使用matplotlib.pyplot.figure()
創(chuàng)建一個Figure
實例,這是一個便捷的方法,用于實例化Figure
實例并將它們與你的用戶界面或繪圖工具包FigureCanvas
連接。正如我們將在下面討論的,這不是必須的 - 你可以直接使用 PostScript,PDF,Gtk+ 或 wxPython FigureCanvas
實例,直接實例化你的圖形并連接它們 - 但是因為我們在這里關(guān)注藝術(shù)家 API,我們讓pyplot
為我們處理一些細(xì)節(jié):
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(2,1,1) # two rows, one column, first plot
Axes
可能是 matplotlib API 中最重要的類,你將在大多數(shù)時間使用它。 這是因為Axes
是大多數(shù)對象所進(jìn)入的繪圖區(qū)域,Axes
有許多特殊的輔助方法(plot()
,text()
,hist()
,imshow()
)來創(chuàng)建最常見的圖形基本類型 Line2D
,Text
,Rectangle
,Image
)。 這些輔助方法將獲取你的數(shù)據(jù)(例如 numpy 數(shù)組和字符串),并根據(jù)需要創(chuàng)建基本Artist
實例(例如,Line2D
),將它們添加到相關(guān)容器中,并在請求時繪制它們。 大多數(shù)人可能熟悉子圖,這只是Axes
的一個特例,它存在于Subplot
實例的列網(wǎng)格的固定行上。 如果要在任意位置創(chuàng)建Axes
,只需使用add_axes()
方法,該方法接受[left, bottom, width, height]
值的列表,以 0~1 的圖形相對坐標(biāo)為單位:
fig2 = plt.figure()
ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3])
以我們的例子繼續(xù):
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
調(diào)用創(chuàng)建的Axes
實例(記住Subplot
只是Axes
的一個子類),當(dāng)你調(diào)用ax.plot
時,它創(chuàng)建一個Line2D
實例并將其添加到Axes.lines
列表中。 在下面的 ipython 交互式會話中,你可以看到Axes.lines
列表的長度為 1,并且包含由line, = ax.plot...
調(diào)用返回的相同線條:
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
進(jìn)行連續(xù)調(diào)用(并且保持狀態(tài)為『on』,這是默認(rèn)值),則將在列表中添加其他線條。 你可以稍后通過調(diào)用列表方法刪除線條;任何一個方法都可以:
del ax.lines[0]
ax.lines.remove(line) # one or the other, not both!
軸域也擁有輔助方法,用于設(shè)置和裝飾 x 和 y 軸的刻度、刻度標(biāo)簽和軸標(biāo)簽:
xtext = ax.set_xlabel('my xdata') # returns a Text instance
ytext = ax.set_ylabel('my ydata')
當(dāng)你調(diào)用ax.set_xlabel
時,它將信息傳遞給XAxis
的Text
實例,每個Axes
實例都包含XAxis
和YAxis
,它們處理刻度、刻度標(biāo)簽和軸標(biāo)簽的布局和繪制。
嘗試創(chuàng)建下面的圖形:
自定義你的對象
圖中的每個元素都由一個 matplotlib 藝術(shù)家表示,每個元素都有一個擴(kuò)展屬性列表用于配置它的外觀。 圖形本身包含一個Rectangle
,正好是圖形的大小,你可以使用它來設(shè)置圖形的背景顏色和透明度。 同樣,每個Axes
邊框(在通常的 matplotlib 繪圖中是標(biāo)準(zhǔn)的白底黑邊)擁有一個Rectangle
實例,用于確定軸域的顏色,透明度和其他屬性,這些實例存儲為成員變量Figure.patch
和Axes.patch
(『Patch』是一個繼承自 MATLAB 的名稱,它是圖形上的一個顏色的 2D『補(bǔ)丁』,例如矩形,圓和多邊形)。每個 matplotlib 藝術(shù)家都有以下屬性。
屬性 | 描述 |
---|---|
alpha | 透明度 - 0 ~ 1 的標(biāo)量 |
animated | 用于幫助動畫繪制的布爾值 |
axes | 藝術(shù)家所在的軸域,可能為空 |
clip_box | 用于剪切藝術(shù)家的邊框 |
clip_on | 剪切是否開啟 |
clip_path | 藝術(shù)家被剪切的路徑 |
contains | 一個拾取函數(shù),用于判斷藝術(shù)家是否位于拾取點 |
figure | 藝術(shù)家所在的圖形實例,可能為空 |
label | 文本標(biāo)簽(用于自動標(biāo)記) |
picker | 控制對象拾取的 Python 對象 |
transform | 變換 |
visible | 布爾值,表示藝術(shù)家是否應(yīng)該繪制 |
zorder | 確定繪制順序的數(shù)值 |
rasterized | 布爾值,是否將向量轉(zhuǎn)換為光柵圖形(出于壓縮或 eps 透明度) |
每個屬性都使用一個老式的setter
或getter
(是的,我們知道這會刺激 Python 愛好者,我們計劃支持通過屬性或 traits 直接訪問,但它還沒有完成)。 例如,要將當(dāng)前alpha
值變?yōu)橐话耄?/p>
a = o.get_alpha()
o.set_alpha(0.5*a)
如果你打算可以一次性設(shè)置一些屬性,你也可以以關(guān)鍵字參數(shù)使用set
方法,例如:
o.set(alpha=0.5, zorder=2)
如果你在 Python 交互式 Shell 中工作,檢查Artist
屬性的一種方便的方法是使用matplotlib.artist.getp()
函數(shù)(在 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
模塊,來獲取給定對象的屬性列表。
對象容器
現(xiàn)在我們知道如何檢查和設(shè)置我們想要配置的給定對象的屬性,現(xiàn)在我們需要如何獲取該對象。 前面提到了兩種對象:基本類型和容器類型。 基本類型通常是你想要配置的東西(Text
實例的字體,Line2D
的寬度),雖然容器也有一些屬性 - 例如 Axes
是一個容器藝術(shù)家,包含你的繪圖中的許多基本類型,但它也有屬性,比如xscale
來控制xaxis
是『線性』還是『對數(shù)』。 在本節(jié)中,我們將回顧各種容器對象存儲你想要訪問的藝術(shù)家的位置。
圖形容器
頂層容器藝術(shù)家是matplotlib.figure.Figure
,它包含圖形中的所有內(nèi)容。 圖形的背景是一個Rectangle
,存儲在Figure.patch
中。 當(dāng)你向圖形中添加子圖(add_subplot()
)和軸域(add_axes()
)時,這些會附加到Figure.axes
。 它們也由創(chuàng)建它們的方法返回:
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>]
因為圖形維護(hù)了『當(dāng)前軸域』(見figure.gca
和圖figure.sca
)的概念以支持 pylab/pyplot 狀態(tài)機(jī),所以不應(yīng)直接從軸域列表中插入或刪除軸域,而應(yīng)使用add_subplot()
和add_axes()
方法進(jìn)行插入,并使用delaxes()
方法進(jìn)行刪除。 然而,你可以自由地遍歷軸域列表或索引,來訪問要自定義的Axes
實例。 下面是一個打開所有軸域網(wǎng)格的示例:
for ax in fig.axes:
ax.grid(True)
圖形還擁有自己的文本,線條,補(bǔ)丁和圖像,你可以使用它們直接添加基本類型。 圖形的默認(rèn)坐標(biāo)系統(tǒng)簡單地以像素(這通常不是你想要的)為單位,但你可以通過設(shè)置你添加到圖中的藝術(shù)家的transform
屬性來控制它。
更有用的是『圖形坐標(biāo)系』,其中(0,0)
是圖的左下角,(1,1)
是圖的右上角,你可以通過將Artist
的變換設(shè)置為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()
這里是圖形可以包含的藝術(shù)家總結(jié):
圖形屬性 | 描述 |
---|---|
axes |
Axes 實例的列表(包括Subplot ) |
patch |
Rectangle 背景 |
images |
FigureImages 補(bǔ)丁的列表 - 用于原始像素顯示 |
legends |
圖形Legend 實例的列表(不同于Axes.legends ) |
lines |
圖形Line2D 實例的列表(很少使用,見Axes.lines ) |
patches |
圖形補(bǔ)丁列表(很少使用,見Axes.patches ) |
texts |
圖形Text 實例的列表 |
軸域容器
matplotlib.axes.Axes
是 matplotlib 宇宙的中心 - 它包含絕大多數(shù)在一個圖形中使用的藝術(shù)家,并帶有許多輔助方法來創(chuàng)建和添加這些藝術(shù)家本身,以及訪問和自定義所包含的藝術(shù)家的輔助方法。 就像Figure
那樣,它包含一個Patch patch
,它是一個用于笛卡爾坐標(biāo)的Rectangle
和一個用于極坐標(biāo)的Cirecle
; 這個補(bǔ)丁決定了繪圖區(qū)域的形狀,背景和邊框:
ax = fig.add_subplot(111)
rect = ax.patch # a Rectangle instance
rect.set_facecolor('green')
當(dāng)調(diào)用繪圖方法(例如通常是plot()
)并傳遞數(shù)組或值列表時,該方法將創(chuàng)建一個matplotlib.lines.Line2D()
實例,將所有Line2D
屬性作為關(guān)鍵字參數(shù)傳遞, 將該線條添加到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
偶對來繪制,我們將長度為一的列表的第一個元素解構(gòu)到line
變量中。 該線條已添加到Axes.lines
列表中:
In [229]: print ax.lines
[<matplotlib.lines.Line2D instance at 0xd378b0c>]
與之類似,創(chuàng)建補(bǔ)丁的方法(如bar()
)會創(chuàng)建一個矩形列表,將補(bǔ)丁添加到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)
你不應(yīng)該直接將對象添加到Axes.lines
或Axes.patches
列表,除非你確切知道你在做什么,因為Axes
需要在它創(chuàng)建和添加對象做一些事情。 它設(shè)置Artist
的figure
和axes
屬性,以及默認(rèn)Axes
變換(除非設(shè)置了變換)。 它還檢查Artist
中包含的數(shù)據(jù),來更新控制自動縮放的數(shù)據(jù)結(jié)構(gòu),以便可以調(diào)整視圖限制來包含繪制的數(shù)據(jù)。 但是,你可以自己創(chuàng)建對象,并使用輔助方法(如add_line()
和add_patch()
)將它們直接添加到Axes
。 這里是一個注釋的交互式會話,說明正在發(fā)生什么:
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
輔助方法用于創(chuàng)建基本藝術(shù)家并將它們添加到他們各自的容器中。 下表總結(jié)了他們的一部分,他們創(chuàng)造的Artist
的種類,以及他們在哪里存儲它們。
輔助方法 | 藝術(shù)家 | 容器 |
---|---|---|
ax.annotate - 文本標(biāo)注 |
Annotate |
ax.texts |
ax.bar - 條形圖 |
Rectangle |
ax.patches |
ax.errorbar - 誤差條形圖 |
Line2D 和 Rectangle
|
ax.lines 和 ax.patches
|
ax.fill - 共享區(qū)域 |
Polygon |
ax.patches |
ax.hist - 直方圖 |
Rectangle |
ax.patches |
ax.imshow - 圖像數(shù)據(jù) |
AxesImage |
ax.images |
ax.legend - 軸域圖例 |
Legend |
ax.legends |
ax.plot - xy 繪圖 |
Line2D |
ax.lines |
ax.scatter - 散點圖 |
PolygonCollection |
ax.collections |
ax.text - 文本 |
Text |
ax.texts |
除了所有這些藝術(shù)家,Axes
包含兩個重要的藝術(shù)家容器:XAxis
和YAxis
,它們處理刻度和標(biāo)簽的繪制。 它們被存儲為實例變量xaxis
和yaxis
。 XAxis
和YAxis
容器將在下面詳細(xì)介紹,但請注意,Axes
包含許多輔助方法,它們會將調(diào)用轉(zhuǎn)發(fā)給Axis
實例,因此你通常不需要直接使用它們,除非你愿意。 例如,你可以使用Axes
輔助程序方法設(shè)置XAxis
刻度標(biāo)簽的字體大小:
for label in ax.get_xticklabels():
label.set_color('orange')
下面是軸域所包含的藝術(shù)家的總結(jié)
軸域?qū)傩?/th> | 描述 |
---|---|
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
實例處理刻度線,網(wǎng)格線,刻度標(biāo)簽和軸標(biāo)簽的繪制。你可以分別為y軸配置左和右刻度,為x軸分別配置上和下刻度。 Axis
還存儲在自動縮放,平移和縮放中使用的數(shù)據(jù)和視圖間隔,以及Locator
和Formatter
實例,它們控制刻度位置以及它們表示為字符串的方式。
每個Axis
對象都包含一個label
屬性(這是 pylab 在調(diào)用xlabel()
和ylabel()
時修改的東西)以及主和次刻度的列表。刻度是XTick
和YTick
實例,它包含渲染刻度和刻度標(biāo)簽的實際線條和文本基本類型。因為刻度是按需動態(tài)創(chuàng)建的(例如,當(dāng)平移和縮放時),你應(yīng)該通過訪問器方法get_major_ticks()
和get_minor_ticks()
訪問主和次刻度的列表。雖然刻度包含所有下面要提及的基本類型,Axis
方法包含訪問器方法來返回刻度線,刻度標(biāo)簽,刻度位置等:
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
的一些有用的訪問器方法的總結(jié)(它們擁有相應(yīng)的setter
,如set_major_formatter
)。
訪問器方法 | 描述 | |
---|---|---|
get_scale | 軸的比例,例如'log' 或'linear'
|
|
get_view_interval | 軸視圖范圍的內(nèi)部實例 | |
get_data_interval | 軸數(shù)據(jù)范圍的內(nèi)部實例 | |
get_gridlines | 軸的網(wǎng)格線列表 | |
get_label | 軸標(biāo)簽 - Text 實例 |
|
get_ticklabels |
Text 實例的列表 - 關(guān)鍵字`minor=True |
False` |
get_ticklines |
Line2D 實例的列表 - 關(guān)鍵字`minor=True |
False` |
get_ticklocs |
Tick 位置的列表 - 關(guān)鍵字`minor=True |
False` |
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 | 為主或次刻度打開或關(guān)閉網(wǎng)格 |
這里是個例子,出于美觀不太推薦,它自定義了軸域和刻度屬性。
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.axis.Tick
是我們從Figure
到Axes
再到Axis
再到Tick
的最終的容器對象。Tick
包含刻度和網(wǎng)格線的實例,以及上側(cè)和下側(cè)刻度的標(biāo)簽實例。 每個都可以直接作為Tick
的屬性訪問。此外,也有用于確定上標(biāo)簽和刻度是否對應(yīng)x
軸,以及右標(biāo)簽和刻度是否對應(yīng)y
軸的布爾變量。
刻度屬性 | 描述 |
---|---|
tick1line |
Line2D 實例 |
tick2line |
Line2D 實例 |
gridline |
Line2D 實例 |
label1 |
Text 實例 |
label2 |
Text 實例 |
gridOn |
確定是否繪制刻度線的布爾值 |
tick1On |
確定是否繪制主刻度線的布爾值 |
tick2On |
確定是否繪制次刻度線的布爾值 |
label1On |
確定是否繪制主刻度標(biāo)簽的布爾值 |
label2On |
確定是否繪制次刻度標(biāo)簽的布爾值 |
這里是個例子,使用美元符號設(shè)置右側(cè)刻度,并在y
軸右側(cè)將它們設(shè)成綠色。
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()