matplotlib从起点出发(7)_Tutorial_7_Artist

1 Artist教程

使用Artist对象来渲染画布。

matplotlib API一共有三个层次:

  • matplotlib.backend_bases.FigureCanvas是绘制图形的区域;
  • matplotlib.backend_bases.Renderer是知道如何在FigureCanvas上绘制的对象;
  • matplotlib.artist.Artist是知道如何使用渲染器在画布上绘图的对象。

matplotlib从起点出发(7)_Tutorial_7_Artist_第1张图片

FigureCanvasRenderer处理与用户界面工具包(如wxPython)或绘图语言(如PostScript)通信的所有细节。而Artist处理所有高级构造,如表示和布局图形、文本和线条 。用户通常要花费95%的时间使用Artists

有两种类型的Artist:基元和容器。基元表示我们要在画布上绘制的标准图形对象:Line2DRectangleTextAxesImage等;容器是放置它们的地方(AxisAxesFigure)。标准用法是创建一个Figure实例,并使用Figure来创建一个或多个Axes实例,并使用Axes实例帮助程序方法创建基元。在下面的示例中,我们使用matplotlib.pyplot.figure()创建一个Figure实例,这是一种实例化Figure实例并将它们与你的用户界面或绘图工具包FigureCanvas连接起来的便捷方法。正如我们将在下面讨论的,这不是必需的——你可以直接使用PostScriptPDFGtk+,或者wxPython FigureCanvas实例,直接实例化你的Figure并自己连接它们。但是由于我们在这里专注于Artist API,我们将让pyplot为我们处理其中一些细节:

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1) # 子图布局为两行,一列,先指定第一张图

matplotlib从起点出发(7)_Tutorial_7_Artist_第2张图片

Axes可能是matplotlib API中最重要的类,也是你大部分时间都会使用的类。这是因为axes是大多数对象进入的绘图区域,并且axes有许多特殊的辅助方法(plot()text()hist()imshow())来创建最常见的图形基元(分别为Line2DText, RectangleAxesImage)。这些帮助程序方法将获取你的数据(例如,numpy数组和字符串)并根据需要创建基元Artist实例(例如Line2D),将它们添加到相关窗口中,并在请求时绘制它们。如果要在任意位置创建axes,只需要使用add_axes()方法,该方法在0-1个相对图形坐标中获取[左、底、宽、高]值列表:

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

matplotlib从起点出发(7)_Tutorial_7_Artist_第3张图片

如图,左侧位置在0.15处,底侧位置在0.1处,宽度为0.7,则右侧位置到0.85处,刚好控制左右边距对称,高度到0.4处。

继续我们的例子:

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)

matplotlib从起点出发(7)_Tutorial_7_Artist_第4张图片

在此示例中,ax是由上面的fig.add_subplot()调用创建的axes实例,当你调用ax.plot时,它会创建一个Line2D实例并将其添加到axes中。在下面的交互式IPython会话中,你可以看到Axes.lines列表的长度为1,并且包含该行返回的同一行 =ax.plot...调用:

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

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

如果你随后调用ax.plot(并且保持状态为默认值 “on”),则其他线将会被添加到列表中。你可以稍后通过调用其remove方法来删除一条线:

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

Axes还具有用于配置和修饰x轴和y轴刻度、刻度标签和轴标签的帮助器方法:

xtext = ax.set_xlabel('my xdata')  # 返回一个文本实例
ytext = ax.set_ylabel('my ydata')

调用ax.set_xlabel时,它会传递有关XAxis的文本实例上的信息。每个轴实例都包含一个XAxis和一个YAxis实例,它们处理刻度、刻度标签和轴标签的布局和绘制。

尝试绘制以下的图:

import numpy as np
import matplotlib.pyplot as plt

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)

# 控制复现时的随机种子
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()

matplotlib从起点出发(7)_Tutorial_7_Artist_第5张图片

2. 自定义对象

图中的每个元素都由一个matplotlib artist表示,每个元素都有一个广泛的属性列表来配置其外观。图形本身包含一个与图形大小完全相同的矩形,可用于设置图形的背景颜色和透明度。同样,每个axes边界框(典型的matplotlib图中带有黑色边缘的标准白框)都有一个矩形实例,用于确定axes对象的颜色、透明度和其他属性。这些实例存储为成员变量Figure.patchAxes.patch("Patch"是从MATLAB中继承的名称,是图形上颜色的2D“补丁”,例如矩形、圆形和多边形)。每个matplotlibartist都有以下属性:

属性 描述
alpha 透明度——一个介于0-1之间的标量
animated 一个布尔值,用来配置动画绘制
axes Artist存在的位置,可能没有
clip_box 包围着Artist对象的边框
clip_on 是否启用裁剪
clip_path artist被剪辑到的路径
contains 用于测试artist是否包含拾取点的拾取函数
figure artist所在的figure实例,可能没有
label 文本标签(例如:自动标签)
picker 一个控制对象拾取的python对象
transform 转型
visible 一个控制artist是否可见的布尔值
zorder 控制绘制顺序的数字
rasterized 布尔值,将矢量转换为光栅图形(用于压缩和EPS)透明度

每个属性都可以使用老式的settergetter访问(是的,我们知道这激怒了Pythonistas,我们计划支持通过属性或特征直接访问在,但尚未完成)。例如,要将当前的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。下面是上面提到的图形矩形属性:

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以获取给定对象的属性列表。

3. 对象容器

现在我们知道了如何检查和设置要配置的给定对象的属性,我们需要知道如何获取该对象。如引言中所述,有两种对象:基元和容器。基元通常是你要配置的内容(文本实例的字体,line2D的宽度),尽管容器也具有一些属性——例如,Axes Artist是一个容器,其中包含绘图中的许多基元,但它也具有像xcale这样的属性来控制xaxis是“线性”还是“对数”。这本节中,我们将回顾各种容器对象存储你想要获取的Artist的位置。

Figure容器

最顶层的容器Artistmatplotlib.figure.Figure,它包含图中的所有内容。该图的背景是一个存储在Figure.patch中的矩形。当你向图形添加子图(add_subplot())和axes(add_axes())时,这些将附加到Figure.axes。这些也由创建它们的方法返回:

fig = plt.figure()

ax1 = fig.add_subplot(211)

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

ax1
Out[159]: <Axes:>

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

由于该图保留了“当前Axes”的概念(请参阅Figure.gcaFigure.sca)以支持pylab/pyplot状态机,因此不应直接从Axes列表中插入或删除轴,而应使用add_subplot()add_axes()方法插入,并使用Axes.remove方法删除。但是,你可以自由地迭代axes列表或索引 到其中以访问要自定义的Axes实例。下面是一个打开所有Axes网格的示例:

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

该图还具有自己的图像、线条、图块和文本属性,你可以使用它们直接添加基元。执行此操作时,图形的默认坐标系将仅以像素为单位(这通常不是你想要的)。如果你改用Figure级该应地来添加Artist(例如,使用Figure.text添加文本),则默认坐标系将是“图形坐标”,其中(0,0)是图形的左下角,(1,1)是图形的右上角。

与所有Artist一样,你可以通过设置transform属性来控制此坐标系。你可以通过将Aritst转换设置为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()

matplotlib从起点出发(7)_Tutorial_7_Artist_第6张图片

以下是Figure包含的Artist的摘要:

Figure属性 描述
axes Axes实例的列表
patch Rectangle矩形背景
images FigureImage补丁的列表——原始像素显示有用
legends 图像图例Legend实例的列表(和Axes.get_legend()不同)
lines 图像line2D实例中的列表(极少使用,见Axes.lines
patches 图像Patch列表(极少使用,见Axes.patches
texts 图像Text实例列表

Axes容器

matplotlib.axes.AxesMatplotlib宇宙的中心——它包含图中使用的绝大多数Artist,有许多帮助程序方法来创建和添加这些Artist到自身,以及访问和自定义它所包含的Artist的辅助方法。像Figure一样,它包含一个补丁patch,它是笛卡尔坐标的矩形和极坐标的圆;此图块确定绘图区域的形状、背景和边框:

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

当你调用一个绘图方法(例如,标准绘图并传入数组或值列表)时,该方法创建一个matplotlib.lines.Line2D实例,使用作为关键字参数传递的所有line2D属性更新该直线,将该直线添加到Axes中,然后将其返回给你:

x, y = np.random.rand(2, 100)

line, = ax.plot(x, y, '-', color='blue', linewidth=2)

plot返回一个直线列表,因为你可以传入多个x,y对来绘制,我们将长度列表的第一个元素解压缩到line变量中。该直线已经添加到Axes.lines列表中:

print(ax.lines)
[<matplotlib.lines.Line2D at 0xd378b0c>]

类似地,创建补丁patch的方法,如bar()创建一个矩形列表,会将补丁添加到Axes.patches列表中:

n, bins, rectangles = ax.hist(np.random.randn(1000), 50)

rectangles
<BarContainer object of 50 artists>

print(len(ax.patches))
50

你不应该将对象直接添加到Axes.linesAxes.patches列表中,因为Axes在创建和添加对象时还需要执行一些操作:

  • 它设置了ArtistFigureAxes属性;
  • 它设置默认的Axes变换(除非已经设置了一个);
  • 它检查Artist中包含的数据以更新控制自动缩放的数据结构,以便可以调整视图限制以包含打印数据。

不过,你可以自己创建对象,并使用如add_lineadd_patch等方法将它们直接添加到Axes中。这是一个带注释的交互式会话,它说明了发生了的一些事情:

fig, ax = plt.subplots()

# 创建一个矩形实例
rect = matplotlib.patches.Rectangle((1, 1), width=5, height=12)

# 默认时axes实例为None
print(rect.axes)
None

# transformation实例设置成"identity transform"
print(rect.get_data_transform())
IdentityTransform()

# 接着我们将矩形添加到Axes上去
ax.add_patch(rect)

# 注意ax.add_patch方法已经设置了axes实例 
print(rect.axes)
Axes(0.125,0.1;0.775x0.8)

# 并且transformation也已经设置好了
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.]])))))))

# 默认的axes转换是 ax.transData
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.]])))))))

# 注意Axes的x轴极限没有被改变
print(ax.get_xlim())
(0.0, 1.0)

# 但是数据限制已经更新为包含矩形
print(ax.dataLim.bounds)
(1.0, 1.0, 5.0, 12.0)

# 我们可以手动调用自动缩放机制
ax.autoscale_view()

# 现在xlim已经更新为包含矩形,加上边距
print(ax.get_xlim())
(0.75, 6.25)

# 我们必须手动强制绘制图形
fig.canvas.draw()

有许多Axes帮助程序方法可用于创建基元Artists并将它们添加到各自的容器中去。下表总结了它们中的一小部分样本、它们创建的Artist以及存储它们的位置:

Axes帮助程序方法 Artist 容器
annotate-文本注释 Annotation ax.texts
bar-柱形图 Rectangle ax.patches
errorbar-误差柱形图 Line2DRectangle ax.lines 和 ax.patches
fill-填充区域 Polygon ax.patches
hist-直方图 Rectangle ax.patches
imshow-图像数据 AxesImage ax.images
legend-图例 Legend ax.get_legend()
plot-xy折线图 Line2D ax.lines
scatter-散点图 PolyCollection ax.collections
text-文本 Text ax.texts

除了所有这些Artist之外,Axes还包含有两个重要的Artist容器:XAxisYAxis,它们控制刻度和标签的绘制。它们存储为实例变量xaxisyaxis。下面将详细介绍XAxisYAxis容器,但请注意,Axes包含许多将调用转发到Axis实例的帮助程序方法,因此除非你愿意,否则通常不需要直接使用它们。例如,你可以使用Axes帮助程序方法设置XAxis刻度标签的字体颜色:

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

这就把字体的颜色设置成了橙色。

以下是一些Axes包含的Artist的总结:

Axes属性 描述
artists 一个ArtistListArtist实例
patch Axes背景的Rectangle实例
collections 一个ArtistListCollection实例
images 一个AxesImage中的ArtistList
patches 一个ArtistListPatch实例
texts 一个ArtistListText实例
xaxis 一个matplotlib.axis.XAxis实例
yaxis 一个matplotlib.axis.YAxis实例

图例则可以通过get_legend进行访问。

轴容器

matplotlib.axis.Axis实例控制刻度线、网格线、刻度标签和轴标签的线控制。你可以分别为y轴配置左刻度和右刻度,为x轴分别配置上刻度及下刻度。轴还存储用于自动缩放、平移和缩放的数据和视图间隔,以及控制刻度放置位置以及如何将它们表示为字符串的定位器和格式化程序实例。

每个Axis对象都包含一个标签属性(这是pyplot在调用xlabelylabel时修改的属性)以及主要和次要刻度的列表。刻度是axis.XTickaxis.YTick实例(取决于是x轴的刻度还是y轴的刻度),其中包含呈现刻度标签的实际行和文本基元。由于刻度是根据需要动态创建的(例如,在平移和缩放时),因此你应该通过其访问器方法axis.Axis.get_major_ticksaxis.Axis.get_minor_ticks分别访问主要刻度和次要刻度的列表。尽管刻度包含所有基元,并将在下面介绍,但Axis实例具有返回刻度线、刻度标签、刻度位置等的访问器方法:

fig, ax = plt.subplots()
axis = ax.xaxis
axis.get_ticklocs()

matplotlib从起点出发(7)_Tutorial_7_Artist_第7张图片

输入为

array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])

若继续输入:

axis.get_ticklabels()

则输出为:

[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')]

请注意,刻度线的数量是标签的两倍,因为在默认情况下,顶部和底部都有刻度线,只有轴下方的刻度有标签,但这也可以自己定义。

axis.get_ticklines()

输出为:

<a list of 12 Line2D ticklines objects>

以下是Axis的一些有用的访问器方法的摘要(这些方法在有用的地方有相应的setter,例如set_major_formatter())。

Axis访问器方法 描述
get_scale 轴的比例,如’log’和’linear’
get_view_interval 轴视图上下限的间隔实例
get_data_interval 轴数据上下限的间隔实例
get_gridlines 轴的轴线列表
get_label 轴标签——一个Text实例
get_offset_text 轴补偿实例——一个Text实例
get_ticklabels 一个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 打开或关闭主次刻度线的开关

以下是一个例子,因为实在不好看,所以不推荐这样做,它自定义了Axes和Tick的属性:

# plt.figure 创建了一个 matplotlib.figure.Figure 实例
fig = plt.figure()
rect = fig.patch  # 一个矩形实例
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.set_color('red')
    label.set_rotation(45)
    label.set_fontsize(16)

for line in ax1.yaxis.get_ticklines():
    # 直线是一个 Line2D 实例
    line.set_color('green')
    line.set_markersize(25)
    line.set_markeredgewidth(3)

plt.show()

matplotlib从起点出发(7)_Tutorial_7_Artist_第8张图片

Tick 容器

matplotlib.axis.Tick是我们从Figure到Axes再到Axis再到Tick下降过程中的最后一个容器对象。刻度包含刻度和网格线实例,以及上刻度和下刻度的标签实例。这些中的每一个都可以作为Tick的属性直接进行访问。

Tick属性 描述
tick1line 一个Line2D实例
tick2line 一个Line2D实例
gridline 一个Line2D实例
label1 一个Text实例
label2 一个Text实例

下面一个示例,它用美元符号为右侧刻度设置格式,并在yaxis的右侧将它们着色为绿色。

import numpy as np
import matplotlib.pyplot as plt

# 固定随机数种子
np.random.seed(19680801)

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

# 使用自动的格式设置
ax.yaxis.set_major_formatter('${x:1.2f}')

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

plt.show()

matplotlib从起点出发(7)_Tutorial_7_Artist_第9张图片

matplotlib从起点出发(7)_Tutorial_7_Artist_第10张图片

你可能感兴趣的:(Python,matplotlib)