python深入类底层_深入理解matplotlib的底层架构

matplotlib 的 API 有 3 个层次

python深入类底层_深入理解matplotlib的底层架构_第1张图片matplotlib.backend_bases.FigureCanvas,相当于一块画布,画出的图形都是要落到画布上的

matplotlib.backend_bases.Renderer,渲染器,相当于画笔和颜料,用来渲染图形

matplotlib.artist.Artist,艺术家,可以想象是一个艺术家的手,利用画笔和颜料(renderer)在画布(FigureCanvas)上画图

FigureCanvas 和 Renderer 属于底层的结构,用来控制 backend(用户界面如wxPython或者图形语言如PostScript),Artist 是上层接口,控制 figure,text,lines 等对象。用户 95% 的时间都是在和 Artist 打交道。

Artist 分为两类:primitives 和 containers,primitives 表示我们要渲染在画布上的标准的图形对象:Line2D, Rectangle, Text, AxesImage等,containers 是容纳这些图形对象的地方(Axis, Axes 和 Figure)。标准的流程是创建一个 Figure 实例,然后用 Figure 实例创建一个或多个 Axes 或 Subplot 实例,之后用 Axes 实例的方法创建 primitives。联系平日里画图的起手式,就很好理解了import matplotlib.pyplot as plt

fig = plt.figure()

ax = plt.add_subplot(2, 1, 1) # 创建 Axes 实例

python深入类底层_深入理解matplotlib的底层架构_第2张图片

Axes 可能是 matplotlib 中最重要的类,因为用户绝大部分时间都是在围着它转。因为 Axes 是主要的绘图区域,大多数图形对象都落在这个区域内,并且 Axes 还有很多特殊的辅助方法(plot(), text(), hist(), imshow())用来创建大多数通用的 primitives(Line2D, Text, Rectangle, Image),这些辅助方法会拿着用户的数据并根据需要创建 primitives 类型的 Artist 实例,加到相应的 containers 并渲染成图形。

大多数人可能对 Subplot 比较熟悉,它仅仅是 Axes 的一个特例,以 Subplot 实例的规则的行和列的网格形式呈现。如果你想在任意位置创建 Axes,只需要以一个列表[left, bottom, width, height] 为参数调用 add_axes() 方法就可以,列表中的元素是 0 – 1 之间的相对坐标。fig2 = plt.figure()

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

python深入类底层_深入理解matplotlib的底层架构_第3张图片

继续看我们的例子,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)

python深入类底层_深入理解matplotlib的底层架构_第4张图片

在上面的例子中,ax 是用fig.add_subplot 方法创建的一个 Axes 实例,当我们调用 ax.plot 时,就创建了一个 Line2D 实例并将它加到 Axes.lines 列表中,line

ax.lines

[]

Axes 类还有很多辅助方法可以调整 x-axis 和 y-axis tick, tick labels 及 axis labelsxtext = ax.set_xlabel('my xdata') # returns a Text instance

ytext = ax.set_ylabel('my ydata')

当我们调用 ax.set_xlabel方法时,它会将信息传递给 XAxis的Text实例,每个 Axes 实例都有一个 XAxis 实例和一个 YAxis 实例,用来控制图形的 ticks, tick labels 和 axis labels。下面是一个完整是示例,fig = plt.figure()

fig.subplots_adjust(top=0.8)

ax1 = fig.add_subplot(211)

ax1.set_ylabel('volts')

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

python深入类底层_深入理解matplotlib的底层架构_第5张图片

定制化对象

图形中的每一个元素都由一个对应的 matplotlib Artist 对象代表,且各自都有广泛的属性可以控制其表现。figure 本身有一个同自身尺寸一致的 Rectangle实例,可以用来设置figure的背景色和透明度。同样的,每个 Axes 实例的边框(经典matplotlib 图形里黑色边框的白色区域)也有一个 Rectangle 实例用来控制 Axes 的颜色,透明度等属性。这些实例以成员变量 Figure.patch 和 Axes.patch 储存。每个 Artist 都有以下属性,PropertyDescriptionalphaThe transparency – a scalar from 0-1

animatedA boolean that is used to facilitate animated drawing

axesThe axes that the Artist lives in, possibly None

clip_boxThe bounding box that clips the Artist

clip_onWhether clipping is enabled

clip_pathThe path the artist is clipped to

containsA picking function to test whether the artist contains the pick point

figureThe figure instance the artist lives in, possibly None

labelA text label (e.g., for auto-labeling)

pickerA python object that controls object picking

transformThe transformation

visibleA boolean whether the artist should be drawn

zorderA number which determines the drawing order

rasterizedBoolean; Turns vectors into raster graphics (for compression & eps transparency)

每个属性都可以通过 setter 或getter 来控制,a = o.get_alpha()

o.set_alpha(0.5*a)matplotlib.artist.getp(fig.patch)agg_filter = None

alpha = None

animated = False

antialiased = 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 = (1.0, 1.0, 1.0, 0.0)

extents = Bbox(x0=0.0, y0=0.0, x1=432.0, y1=288.0)

facecolor = (1.0, 1.0, 1.0, 0.0)

figure = Figure(432×288)

fill = True

gid = None

hatch = None

height = 1

in_layout = True

joinstyle = miter

label =

linestyle = solid

linewidth = 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.] [432. 0.] [432. 288.] [ 0. 288….

visible = True

width = 1

window_extent = Bbox(x0=0.0, y0=0.0, x1=432.0, y1=288.0)

x = 0

xy = (0, 0)

y = 0

zorder = 1

Object containers

我们已经知道如何查看和设置指定对象的属性,但是我们还不知道如何获取对象。前文中提到有两种类型的对象:primitives 和 containers。primitives 通常是那些我们想设置的东西(例如 Text 的字体,Line2D 的宽度);containers 虽然也含有一些属性,比如 Axes 就是一个包含很多 primitives 的容器,但是它也含有诸如 xscale 这样的属性用来控制 x 轴是 ‘linear’ 还是 ‘log’。在这一小节我们讨论储存 Artists 实例的各种 container 对象。

Figure container

Artist 的最上层 container 就是matplotlib.figure.Figure,它拥有图形中的一切。图形的背景是一个储存在 Figure.patch 中的Rectangle实例,当我们向 figure 中添加 subplots (add_subplot()) 和axes (add_axes())时,它们会被添加到 Figure.axes列表中,再来看上文中的例子fig = plt.figure()

ax = fig.add_subplot(2, 1, 1)

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

由于 figure 实例有”current axes” (see Figure.gca and Figure.sca)的概念来支持 pylab/pyplot 状态机,因此我们不应该直接往 axes 列表中加入或删除 axes,而应该用 add_subplot() 和 add_axes()方法增加 axes,用 delaxes()方法删除。

我们可以通过迭代或index来获取 axes 列表中的 axes 实例并对其进行操作for ax in fig.axes:

ax.grid(True)

python深入类底层_深入理解matplotlib的底层架构_第6张图片

figure 有它自己的 text, lines, patches 和 images,我们可以通过这些属性直接添加 primitives,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()

python深入类底层_深入理解matplotlib的底层架构_第7张图片

Axes container

matplotlib.axes.Axes是 matplotlib 宇宙的中心 —— 它拥有一个 figure 中用到的所有 Artists 中的绝大部分,以及创建这些 Artists 的辅助函数,以及访问和控制它包含的这些 Artists 的辅助方法。同 Figure 一样,它含有一个对应笛卡尔坐标系的 Rectangle类的 Patch,以及一个对应极坐标系的 Circle 类,这个patch决定了绘图区域的形状、背景和边界。fig = plt.figure()

ax = fig.add_subplot(111)

rect = ax.patch # a Rectangle instance

rect.set_facecolor('green')

python深入类底层_深入理解matplotlib的底层架构_第8张图片

每当我们调用一个绘图方法,比如经典的 plo() 方法并传入数据,它就会创建一个matplotlib.lines.Line2D()实例,用所有传入的参数更新 line 并将其加入 Axes.lines 容器,返回给用户,x, y = np.random.rand(2, 100)

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

plot 会返回一个 lines 的列表,我们利用python 的 unpacking 功能将列表元素赋值给了 line 变量。查看 Axes.lines 列表ax.lines[]

类似的,创建 patches 的方法,比如 bar(),会创建一系列 rectangles ,并将它们加入 Axes.patches 列表。n, bins, rectangles = ax.hist(np.random.randn(1000), 50, facecolor='yellow')

rectangles

print(len(ax.patches))

50

除非你明确知道自己在干什么(除非你是对底层架构了如指掌的高手),否则不应该直接向 Axes.lines 或者 Axes.patches 列表中直接添加对象,因为 Axes 在加入对象后还会做一些额外的事情,它会设置 Artist 的 figure 和 axes 属性,还会检查 Artist 中的数据以便更新控制自动缩放的数据结构,从而使绘图区域能够容纳要渲染的图形。尽管如此,你仍然可以调用辅助函数如 add_line() and add_patch()向 Axes 中加入对象。

Axis containers

matplotlib.axis.Axis实例控制 tick lines, grid lines, tick labels 和 axis label,我们可以分别控制 y-axis 左右两边的 ticks,以及 x-axis 上下两边的 ticks。

每个 Axis 对象都包含一个 label 属性以及 major ticks 和 minor ticks 的列表,ticks 是 XTick and YTick的实例,包含渲染 ticks 和 ticklabels 的 line 和 text primitives。由于 ticks 是根据需要动态创建的,我们应该通过 get_major_ticks() and get_minor_ticks()方法访问 major 和 minor ticks。Axis 实例有放回 tick lines, tick labels, tick locations 等信息的实例方法。axis = ax.xaxis

axis.get_ticklocs()array([-4., -3., -2., -1., 0., 1., 2., 3., 4.])

Tick containers

matplotlib.axis.Tick包含 tick 和 grid line 实例和上下 ticks 的 label 实例,所有这些都能以 Tick 的属性获取,Tick attributeDescriptiontick1lineLine2D instance

tick2lineLine2D instance

gridlineLine2D instance

label1Text instance

label2Text instance

python深入类底层_深入理解matplotlib的底层架构_第9张图片

https://www.jianshu.com/p/a4ac28e02e27

你可能感兴趣的:(python深入类底层)