藝術家教學#

使用「藝術家」物件在畫布上渲染。

Matplotlib API 有三個層級。

  • matplotlib.backend_bases.FigureCanvas 是繪製圖形的區域

  • matplotlib.backend_bases.Renderer 是一個知道如何在 matplotlib.backend_bases.FigureCanvas 上繪圖的物件

  • matplotlib.artist.Artist 是一個知道如何使用渲染器在畫布上繪圖的物件。

matplotlib.backend_bases.FigureCanvasmatplotlib.backend_bases.Renderer 處理與使用者介面工具組(如 wxPython)或繪圖語言(如 PostScript®)溝通的所有細節,而 Artist 則處理所有高階的結構,如表示和佈局圖形、文字和線條。一般使用者將花費 95% 的時間與 Artist 互動。

有兩種類型的 Artist:基本圖元和容器。基本圖元表示我們想要繪製在畫布上的標準圖形物件:Line2DRectangleTextAxesImage 等,而容器則是放置它們的位置(AxisAxesFigure)。標準用法是建立一個 Figure 實例,使用 Figure 建立一個或多個 Axes 實例,並使用 Axes 實例的輔助方法來建立基本圖元。在下面的範例中,我們使用 matplotlib.pyplot.figure() 建立一個 Figure 實例,這是一個方便的方法,用於實例化 Figure 實例並將它們與您的使用者介面或繪圖工具組 FigureCanvas 連接。正如我們將在下面討論的,這不是必要的 -- 您可以直接使用 PostScript、PDF Gtk+ 或 wxPython FigureCanvas 實例,直接實例化您的 Figure 並自行連接它們 -- 但由於我們在這裡重點關注 Artist 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())來建立最常用的圖形基本圖元(分別是 Line2DTextRectangleAxesImage)。這些輔助方法將採用您的資料(例如,numpy 陣列和字串),並根據需要建立基本 Artist 實例(例如,Line2D),將它們新增到相關的容器中,並在要求時繪製它們。如果您想在任意位置建立一個 Axes,只需使用 add_axes() 方法,該方法採用 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 實例,當您呼叫 ax.plot 時,它會建立一個 Line2D 實例並將其新增到 Axes。在下面的互動式 IPython 工作階段中,您可以看到 Axes.lines 列表的長度為一,並且包含與 line, = ax.plot... 呼叫傳回的相同線條

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

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

如果您後續呼叫 ax.plot(且 hold 狀態為「開啟」,這是預設值),則會將其他線條新增到列表中。您可以稍後呼叫其 remove 方法來移除一條線

line = ax.lines[0]
line.remove()

Axes 也有輔助方法來設定和裝飾 x 軸和 y 軸刻度、刻度標籤和軸標籤

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

當您呼叫 ax.set_xlabel 時,它會將資訊傳遞到 Text 實例,該實例是 XAxis 的一部分。每個 Axes 實例都包含一個 XAxis 和一個 YAxis 實例,它們處理刻度、刻度標籤和軸標籤的佈局和繪製。

嘗試建立下面的圖形。

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
fig.subplots_adjust(top=0.8)
ax1 = fig.add_subplot(211)
ax1.set_ylabel('Voltage [V]')
ax1.set_title('A sine wave')

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

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

ax2 = fig.add_axes([0.15, 0.1, 0.7, 0.3])
n, bins, patches = ax2.hist(np.random.randn(1000), 50,
                            facecolor='yellow', edgecolor='yellow')
ax2.set_xlabel('Time [s]')

plt.show()
A sine wave

自訂您的物件#

圖表中的每個元素都由一個 Matplotlib Artist 表示,並且每個元素都有大量的屬性可以設定其外觀。圖表本身包含一個與圖表大小完全相同的 Rectangle,您可以使用它來設定圖表的背景顏色和透明度。同樣地,每個 Axes 邊界框(典型 Matplotlib 繪圖中帶有黑色邊緣的標準白色框)都有一個 Rectangle 實例,用於確定 Axes 的顏色、透明度和其他屬性。這些實例儲存為成員變數 Figure.patchAxes.patch ("Patch" 是從 MATLAB 繼承的名稱,是指圖表上 2D 的顏色「區塊」,例如矩形、圓形和多邊形)。每個 Matplotlib Artist 都有以下屬性

屬性

描述

alpha

透明度 - 介於 0 到 1 之間的純量

animated

一個布林值,用於輔助動畫繪圖

axes

Artist 所在的 Axes,可能為 None

clip_box

剪裁 Artist 的邊界框

clip_on

是否啟用剪裁

clip_path

Artist 剪裁的路徑

contains

一個選取函數,用於測試 Artist 是否包含選取點

figure

Artist 所在的圖表實例,可能為 None

label

文字標籤(例如,用於自動標籤)

picker

一個控制物件選取的 Python 物件

transform

轉換

visible

一個布林值,表示是否應該繪製 Artist

zorder

一個數字,決定繪製順序

rasterized

布林值;將向量圖形轉換為點陣圖形(用於壓縮和 EPS 透明度)

每個屬性都使用傳統的 setter 或 getter 來存取(是的,我們知道這會讓 Python 愛好者感到惱火,我們計劃支援透過屬性或 trait 直接存取,但尚未完成)。例如,要將目前的 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() 函式(在 pyplot 中簡稱為 getp()),它會列出屬性和它們的值。這也適用於從 Artist 衍生的類別,例如 FigureRectangle。以下是上面提到的 Figure 矩形屬性:

In [149]: matplotlib.artist.getp(fig.patch)
  agg_filter = None
  alpha = None
  animated = False
  antialiased or aa = False
  bbox = Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0)
  capstyle = butt
  children = []
  clip_box = None
  clip_on = True
  clip_path = None
  contains = None
  data_transform = BboxTransformTo(     TransformedBbox(         Bbox...
  edgecolor or ec = (1.0, 1.0, 1.0, 1.0)
  extents = Bbox(x0=0.0, y0=0.0, x1=640.0, y1=480.0)
  facecolor or fc = (1.0, 1.0, 1.0, 1.0)
  figure = Figure(640x480)
  fill = True
  gid = None
  hatch = None
  height = 1
  in_layout = False
  joinstyle = miter
  label =
  linestyle or ls = solid
  linewidth or lw = 0.0
  patch_transform = CompositeGenericTransform(     BboxTransformTo(   ...
  path = Path(array([[0., 0.],        [1., 0.],        [1.,...
  path_effects = []
  picker = None
  rasterized = None
  sketch_params = None
  snap = None
  transform = CompositeGenericTransform(     CompositeGenericTra...
  transformed_clip_path_and_affine = (None, None)
  url = None
  verts = [[  0.   0.]  [640.   0.]  [640. 480.]  [  0. 480....
  visible = True
  width = 1
  window_extent = Bbox(x0=0.0, y0=0.0, x1=640.0, y1=480.0)
  x = 0
  xy = (0, 0)
  y = 0
  zorder = 1

所有類別的文件字串也包含 Artist 屬性,因此您可以查閱互動式「說明」或 matplotlib.artist 以取得指定物件的屬性清單。

物件容器#

現在我們知道如何檢查和設定要設定的指定物件的屬性,我們需要知道如何存取該物件。正如引言中提到的,有兩種物件:基本物件和容器。基本物件通常是您想要設定的內容(Text 實例的字型,Line2D 的寬度),儘管容器也有一些屬性 - 例如 Axes Artist 是一個容器,包含繪圖中的許多基本物件,但它也具有像 xscale 這樣的屬性,用於控制 xaxis 是「線性」還是「對數」。在本節中,我們將回顧各種容器物件在哪裡儲存您想要存取的 Artist

圖表容器#

頂層容器 Artistmatplotlib.figure.Figure,它包含圖表中的所有內容。圖表的背景是一個 Rectangle,儲存在 Figure.patch 中。當您將子圖 (add_subplot()) 和 Axes (add_axes()) 新增到圖表時,這些子圖和 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]: <Axes:>

In [160]: print(fig.axes)
[<Axes:>, <matplotlib.axes._axes.Axes object at 0x7f0768702be0>]

因為圖表維護了「目前 Axes」的概念(請參閱 Figure.gcaFigure.sca)以支援 pylab/pyplot 狀態機,您不應直接從 Axes 清單中插入或移除 Axes,而是應使用 add_subplot()add_axes() 方法插入,並使用 Axes.remove 方法刪除。但是,您可以自由地反覆運算 Axes 清單或索引到其中,以存取您想要自訂的 Axes 實例。以下範例會開啟所有 Axes 的網格:

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

圖表也有自己的 imageslinespatchestext 屬性,您可以使用這些屬性直接新增基本物件。這樣做時,Figure 的預設座標系統將只會以像素為單位(這通常不是您想要的)。如果您改用圖表層級的方法來新增 Artist(例如,使用 Figure.text 來新增文字),則預設座標系統將會是「圖表座標」,其中 (0, 0) 是圖表的左下角,而 (1, 1) 是圖表的右上角。

與所有 Artist 一樣,您可以透過設定 transform 屬性來控制此座標系統。您可以透過將 Artist 轉換設定為 fig.transFigure 來明確使用「圖表座標」

import matplotlib.lines as lines

fig = plt.figure()

l1 = lines.Line2D([0, 1], [0, 1], transform=fig.transFigure, figure=fig)
l2 = lines.Line2D([0, 1], [1, 0], transform=fig.transFigure, figure=fig)
fig.lines.extend([l1, l2])

plt.show()
artists

以下是圖表包含的 Artist 摘要

圖表屬性

描述

axes

一個 Axes 實例的清單

patch

Rectangle 背景

images

一個 FigureImage 區塊的清單 - 對於原始像素顯示很有用

legends

一個圖表 Legend 實例的清單(與 Axes.get_legend() 不同)

lines

一個圖表 Line2D 實例的清單(很少使用,請參閱 Axes.lines

patches

一個圖表 Patch 的清單(很少使用,請參閱 Axes.patches

texts

一個圖表 Text 實例的清單

Axes 容器#

matplotlib.axes.Axes 是 Matplotlib 世界的核心 — 它包含了圖形中絕大多數的 Artist,並提供許多輔助方法來建立和新增這些 Artist 到自身,以及存取和自訂它所包含的 Artist 的輔助方法。如同 Figure,它包含一個 Patch matplotlib.axes.Axes.patch,在笛卡爾坐標系中為一個 Rectangle,而在極坐標系中則為一個 Circle;這個 patch 決定了繪圖區域的形狀、背景和邊框。

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

當您調用繪圖方法時,例如典型的 plot 並傳入數值陣列或列表時,該方法將建立一個 matplotlib.lines.Line2D 實例,使用作為關鍵字參數傳遞的所有 Line2D 屬性更新該線條,將該線條新增到 Axes,並將其返回給您。

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 at 0xd378b0c>]

類似地,建立 patch 的方法,例如 bar(),會建立一個矩形列表,並將這些 patch 新增到 Axes.patches 列表中。

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

In [234]: rectangles
Out[234]: <BarContainer object of 50 artists>

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

您不應該直接將物件新增到 Axes.linesAxes.patches 列表中,因為 Axes 在建立和新增物件時需要執行一些操作。

  • 它會設定 Artistfigureaxes 屬性;

  • 它會設定預設的 Axes 轉換 (除非已設定);

  • 它會檢查 Artist 中包含的數據,以更新控制自動縮放的數據結構,以便可以調整檢視限制以包含繪製的數據。

儘管如此,您仍然可以自行建立物件,並使用諸如 add_lineadd_patch 等輔助方法將它們直接新增到 Axes。以下是一個帶註解的互動式會話,說明正在發生的事情。

In [262]: fig, ax = plt.subplots()

# 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.axes)
None

# and the transformation instance is set to the "identity transform"
In [265]: print(rect.get_data_transform())
IdentityTransform()

# 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.axes)
Axes(0.125,0.1;0.775x0.8)

# and the transformation has been set too
In [268]: print(rect.get_data_transform())
CompositeGenericTransform(
    TransformWrapper(
        BlendedAffine2D(
            IdentityTransform(),
            IdentityTransform())),
    CompositeGenericTransform(
        BboxTransformFrom(
            TransformedBbox(
                Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0),
                TransformWrapper(
                    BlendedAffine2D(
                        IdentityTransform(),
                        IdentityTransform())))),
        BboxTransformTo(
            TransformedBbox(
                Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88),
                BboxTransformTo(
                    TransformedBbox(
                        Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8),
                        Affine2D(
                            [[100.   0.   0.]
                             [  0. 100.   0.]
                             [  0.   0.   1.]])))))))

# the default Axes transformation is ax.transData
In [269]: print(ax.transData)
CompositeGenericTransform(
    TransformWrapper(
        BlendedAffine2D(
            IdentityTransform(),
            IdentityTransform())),
    CompositeGenericTransform(
        BboxTransformFrom(
            TransformedBbox(
                Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0),
                TransformWrapper(
                    BlendedAffine2D(
                        IdentityTransform(),
                        IdentityTransform())))),
        BboxTransformTo(
            TransformedBbox(
                Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88),
                BboxTransformTo(
                    TransformedBbox(
                        Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8),
                        Affine2D(
                            [[100.   0.   0.]
                             [  0. 100.   0.]
                             [  0.   0.   1.]])))))))

# 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, plus margins
In [273]: print(ax.get_xlim())
(0.75, 6.25)

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

有許多 Axes 輔助方法可以建立基本 Artist 並將它們新增到各自的容器中。下表總結了其中的一小部分、它們建立的 Artist 類型,以及它們儲存的位置。

Axes 輔助方法

Artist

容器

annotate - 文字註解

註解

ax.texts

bar - 長條圖

矩形

ax.patches

errorbar - 誤差棒圖

Line2DRectangle

ax.lines 和 ax.patches

fill - 共享區域

多邊形

ax.patches

hist - 直方圖

矩形

ax.patches

imshow - 圖像數據

AxesImage

ax.images

legend - Axes 圖例

圖例

ax.get_legend()

plot - xy 圖

Line2D

ax.lines

scatter - 散佈圖

PolyCollection

ax.collections

text - 文字

文字

ax.texts

除了所有這些 Artist 之外,Axes 還包含兩個重要的 Artist 容器:XAxisYAxis,它們負責處理刻度和標籤的繪製。這些會被儲存為實例變數 matplotlib.axes.Axes.xaxismatplotlib.axes.Axes.yaxisXAxisYAxis 容器將在下面詳細說明,但請注意,Axes 包含許多輔助方法,這些方法會將調用轉發到 Axis 實例,因此除非您想直接使用它們,否則通常不需要直接處理它們。例如,您可以使用 Axes 輔助方法設定 XAxis 刻度標籤的字體顏色。

ax.tick_params(axis='x', labelcolor='orange')

以下是 Axes 所包含的 Artists 的摘要。

Axes 屬性

描述

artists

ArtistListArtist 實例

patch

Rectangle Axes 背景的實例

collections

ArtistListCollection 實例

images

ArtistListAxesImage

lines

一個 ArtistListLine2D 實例

patches

一個 ArtistListPatch 實例

texts

一個 ArtistListText 實例

xaxis

一個 matplotlib.axis.XAxis 實例

yaxis

一個 matplotlib.axis.YAxis 實例

可以使用 get_legend 存取圖例。

軸容器#

matplotlib.axis.Axis 實例處理刻度線、網格線、刻度標籤和軸標籤的繪製。您可以分別設定 y 軸的左右刻度,以及 x 軸的上下刻度。Axis 也會儲存自動縮放、平移和縮放中使用的数据和视图区间,以及控制刻度放置位置和如何以字符串表示刻度的 LocatorFormatter 實例。

每個 Axis 物件都包含一個 label 屬性(這是 pyplot 在呼叫 xlabelylabel 時修改的內容),以及主要和次要刻度的列表。刻度是 axis.XTickaxis.YTick 實例,其中包含渲染刻度和刻度標籤的實際線條和文字圖元。由於刻度是根據需要動態建立的(例如,在平移和縮放時),您應該透過它們的存取器方法 axis.Axis.get_major_ticksaxis.Axis.get_minor_ticks 來存取主要和次要刻度的列表。儘管刻度包含所有圖元,並將在下面介紹,但 Axis 實例具有返回刻度線、刻度標籤、刻度位置等的存取器方法。

artists
array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])
[Text(0.0, 0, '0.0'), Text(0.2, 0, '0.2'), Text(0.4, 0, '0.4'), Text(0.6000000000000001, 0, '0.6'), Text(0.8, 0, '0.8'), Text(1.0, 0, '1.0')]

注意,刻度線的數量是標籤的兩倍,因為預設情況下,頂部和底部都有刻度線,但只有 xaxis 下方有刻度標籤;但是,這可以自訂。

<a list of 12 Line2D ticklines objects>

使用上述方法,預設情況下您只會獲得主要刻度的列表,但您也可以要求提供次要刻度

axis.get_ticklabels(minor=True)
axis.get_ticklines(minor=True)
<a list of 0 Line2D ticklines objects>

以下是 Axis 的一些有用存取器方法的摘要(這些方法在有用的情況下具有相應的設定器,例如 set_major_formatter())。

軸存取器方法

描述

get_scale

軸的比例,例如「log」或「linear」

get_view_interval

軸視圖限制的區間實例

get_data_interval

軸資料限制的區間實例

get_gridlines

軸的網格線列表

get_label

軸標籤 - 一個 Text 實例

get_offset_text

軸偏移文字 - 一個 Text 實例

get_ticklabels

一個 Text 實例的列表 - 關鍵字 minor=True|False

get_ticklines

一個 Line2D 實例的列表 - 關鍵字 minor=True|False

get_ticklocs

刻度位置的列表 - 關鍵字 minor=True|False

get_major_locator

主要刻度的 ticker.Locator 實例

get_major_formatter

主要刻度的 ticker.Formatter 實例

get_minor_locator

次要刻度的 ticker.Locator 實例

get_minor_formatter

次要刻度的 ticker.Formatter 實例

get_major_ticks

主要刻度的 Tick 實例的列表

get_minor_ticks

次要刻度的 Tick 實例的列表

grid

開啟或關閉主要或次要刻度的網格

以下是一個範例,不推薦其美觀性,它自訂了軸和刻度屬性。

# 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()
artists

刻度容器#

matplotlib.axis.Tick 是我們從 FigureAxesAxisTick 的下降過程中最終的容器物件。Tick 包含刻度和網格線實例,以及上下刻度的標籤實例。這些都可以直接作為 Tick 的屬性存取。

刻度屬性

描述

tick1line

一個 Line2D 實例

tick2line

一個 Line2D 實例

gridline

一個 Line2D 實例

label1

一個 Text 實例

label2

一個 Text 實例

以下是一個範例,它使用美元符號設定右側刻度的格式器,並將它們在 y 軸的右側塗成綠色。

import matplotlib.pyplot as plt
import numpy as np

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

fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))

# Use automatic StrMethodFormatter
ax.yaxis.set_major_formatter('${x:1.2f}')

ax.yaxis.set_tick_params(which='major', labelcolor='green',
                         labelleft=False, labelright=True)

plt.show()
dollar ticks

腳本的總執行時間: (0 分鐘 1.178 秒)

由 Sphinx-Gallery 產生