Figure的add_subplot()方法

本篇讨论Figure对象的另一个重要方法: add_subplot()。

很多人会认为 add_subplot() 与 add_axes() 方法一样,都是向figure容器中添加axes子容器。

如果你也是这样理解add_subplot()方法的,你就真的有必要认真看看本篇了。

本篇将从4个方面来讨论:

  1. add_subplot()方法的调用;
  2. add_subplot()方法与add_axes()方法的关系;
  3. 深入理解add_subplot()方法;
  4. 灵活使用add_subplot()方法实现复杂的图形布局。

add_suplot()方法语法

add_subplot(self, *args, **kwargs)

add_subplot()方法,“向figure添加一个Axes作为一subplot布局的一部分。”

要调用add_subplot()方法,有4种签名形式:

  1. add_subplot(nrows, ncols, index, **kwargs)
  2. add_subplot(pos, **kwargs)
  3. add_subplot(ax) ,这里的ax必须是作为子图布置的一部分创建的,即用add_subplot()创建的
  4. add_subplot() ,使用默认值创建一个子图。

add_subplot()方法的本质

add_subplot()方法本质上做了两件事:

  1. 将整个Figure区域划分为Row * col的网格;
  2. 在网格的指定格子(索引号)中创建一个Axes。

我们就可以进一步在这个axes中绘制图形元素。

add_subplot()网格有两种定义方式:

第一种是用3个参数,分别代表网格的,行数 nrows, 列数 ncols, 索引号index。它们都是位置参数。这种是第1种调用签名形式。

第二种是用一个3位数的整数,如,224,第一个2表示2行,第二个2表示2列,第3位上的4表示第4个格子。这就是第二种调用签名形式,pos为224,也是位置参数。

如果我们不提供参数,即第4种调用签名,默认pos为111。

而第三种调用签名形式,请参考一篇中的相关内容。

假如,我们要创建一个2*2的网格,参数和索引如下图所示:

Matplotlib学习手册A006_Figure的add_subplot()方法

add_subplot()方法的网格参数和索引

下面的代码就在figure中创建了一个2*2的网格,并在第4个格子中创建了一个axes坐标系。

from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.figure import Figure
from matplotlib.axes import Axes
import numpy as np
from numpy import math
fig =Figure( 
 dpi=100,
 facecolor=(239/256,239/256,239/256),
 edgecolor=(82/256,101/256,155/256),
 linewidth=6.0,
 frameon=True,
 )
canvas = FigureCanvasAgg(fig)
#创建一个2*2的网格,并在第4个格子中创建一个axes
fig.add_subplot(224)
s, (width, height) = canvas.print_to_buffer() 
from PIL import Image 
im = Image.frombytes("RGBA", (width, height), s)
im.show() 

Matplotlib学习手册A006_Figure的add_subplot()方法
22的网格是虚拟的*

注意:2*2的网格是虚拟的,起一个定位的作用,本例在第4个格子中创建axes。

再看下例:

from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.figure import Figure
from matplotlib.axes import Axes
import numpy as np
from numpy import math
fig =Figure( 
 dpi=100,
 facecolor=(239/256,239/256,239/256),
 edgecolor=(82/256,101/256,155/256),
 linewidth=6.0,
 frameon=True,
 )
canvas = FigureCanvasAgg(fig)
fig.add_subplot(224)
#再创建一个2行3列的虚拟网格
#在这个网格的第2个格子中创建axes
fig.add_subplot(232)
s, (width, height) = canvas.print_to_buffer() 
from PIL import Image 
im = Image.frombytes("RGBA", (width, height), s)
im.show() 

Matplotlib学习手册A006_Figure的add_subplot()方法

使用add_subplot()实现复杂布局

上面代码,在同一个figure中使用不同的网格定义:

  • 先定义一个2*2的网格,在第4个格子中创建axes;
  • 再定义一个2*3的网格,在第2个格子中创建axes。

这样就实现了,不规则的、复杂的子图布局。

这才是add_subplot()方法最重要用途。

小结:

  • figure就是一个矩形容器(顶层容器),可以再划分为小方格,每个方格就是一个subplot,即子绘图区。
  • 一个图形中可以有多个subplot,这些subplot又可以被看作一个整体,有一些属性如整个subplot的位置、内部(单个subplot之间)的间距等,这些属性保存在figure.SubplotParams类中。可以通过Figure的subplotpars参数来修改这些属性。
  • 子图使用了subplot,而不是subfigure。fiugre仅是一个矩形容器,而plot则是具体的图形元素了,所以subplot会自动创建一个Axes,这个Axes是属于特定subplot的。

add_axes()和add_subplot()

注意官方文档的表述差异:

  • add_axes() ,Add an axes to the figure. 向figure添加一个axes。
  • add_subplot(), Add an Axes to the figure as part of a subplot arrangement. 向figure添加一个Axes作为 subplot 布局的一部分。

两者创建的对象不同:

  • add_axes() 方法创建的对象是 <class ‘matplotlib.axes._axes.Axes’> 的实例。
  • add_subplot() 方法创建的对象,是<class ‘matplotlib.axes._subplots.AxesSubplot’>的一个实例,并且作为子图布置的一部分。

add_subplot()与add_axes()两者既紧密相关,也有区别:

  1. add_subplot()添加一个子图,同时使用工厂函数为该子图自动创建一个坐标系区域;axes的位置由row,col,index指定;
  2. add_axes()直接添加一个坐标系区域到figure容器中;位置由rect参数指定。
  3. add_axes()从外观形式上也是生成了一个子图区域,可以进一步向这个区域添加元素;
  4. 但add_axes()是通过尺寸定位的;它的位置更加灵活自由;
  5. add_subplot()是通过网格索引定位的,则调用容易,排列整齐。
  6. 要向add_subplot()创建的子图添加其它plot元素,是把子图视为一个Axes对象来处理的,即需要将add_subplot()赋给一个变量,然后如同Axes中添加元素一样的操作。

深入理解 add_subplot()

add_subplot(self, *args, **kwargs)

向Figure添加一个子图subplot,add_suplot方法会自动创建一个Axes作为子图布置的一部分。

该方法是通过调用subplot_class_factory工厂函数创建子图和Axes的实例来实现上述功能的。

matplotlib有了一个axes子包,子包内有一个_subplots私有模块。_subpltos模块包含一个类和一个工厂函数:

  • class SubplotBase(object):
  • def subplot_class_factory(axes_class=None):

class SubplotBase(object)用于subplots的基类,它们是:class: ’ Axes ‘实例,该实例带有其他方法,以方便生成和操作figure中的一组:class:’ Axes '。

工厂函数,首先,它是个函数,但工厂函数基本上都是带有返回对象的。而这些返回对象则是通过调用一种或者多种类来创建的对象。工厂函数:能够产生类实例的内建函数。

这将生成一个继承自SubplotBase和给定axes_class(假定axes_class是axes.axes的子类)的新类。像这样动态创建一个新类可能有点迂回,但这意味着不必为每种类型的坐标系创建一个新的Subplot类。

subplot_class_factory()工厂函数,继承了SubplotBase类和axes_calss参数给定的类,默认axes_class = Axes

查看该工厂函数的源码有助于理解它

def subplot_class_factory(axes_class=None):
 if axes_class is None:
 axes_class = Axes
 try:
 # Avoid creating two different instances of GeoAxesSubplot...
 # Only a temporary backcompat fix. This should be removed in
 # 3.4
 return next(cls for cls in SubplotBase.__subclasses__()
 if cls.__bases__ == (SubplotBase, axes_class))
 except StopIteration:
 return type("%sSubplot" % axes_class.__name__,
 (SubplotBase, axes_class),
 {'_axes_class': axes_class})

关注"Python草堂",完全掌握matplotlib。

(This end.)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐