Matplotlib图像结构

本文简要梳理Matplotlib中的元素;如何使用Subplot和Axes控制子图,以及调整子图之间的间距;最后简要说明了Matplotlib的数据输入和图像输出的控制

一、元素

54ea9d5031394848b86c7a76dfa890f7

标题 - Title:图像的名字

图例 - Legend:展示每个数据图像对应的名称

边界 - spines:图四周的框的边界(注意 tick 刻度和所在的线是分离的)

标记 - Marker:图线的标记类型

标签 - Label:一些细节的标识

  • X 轴标签
  • Y 轴标签
  • 主刻度标签
  • 副刻度标签

刻度 - tick:标识对应位置的数值

  • 主刻度
  • 副刻度

字体 - font:文字的类型

颜色 - color:线条、文字

二、结构

Matplotlib 创建的主体称为 Figure,再 Figure 中可以创建子图,子图中就是一些标签元素和数值元素了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 import matplotlib.pyplot as plt
 
 # 新建画板
 fig = plt.figure()
 
 # 新建画布
 ax = fig.add_subplot()
 # or
 ax = fig.add_axes()
 
 # 接下来就可以在ax上绘制图像,或者设置标签等
 # 画板与画布:画板是固定的,画布则可以有多个并且位置可以调整
 
 # 可以对fig做画板的控制(设置画板标题、保存画板图像等)

在子图控制中可以通过 plt 添加子图,也可以通过 fig 来添加子图,这两者的区别是 plt 底层还是用的 fig 对象,在源码中有一个 gcf() 函数,会获取当前活跃的 figure(Get the current figure.)

2.1 子图控制

对于子图的控制,Matplotlib 中有 Axes 和 Subplot 两种控制方式。

Subplot

标准网格布局

1
2
3
4
 import matplotlib.pyplot as plt
 
 fig = plt.figure(figsize=(20, 10), dpi=1000) # 新建画板
 ax = fig.add_subplot(2, 3, idx)              # 新建画布

add_subplot 方法里面传入三个数字,前两个数字代表要生成几行几列的子图矩阵,第三个数字代表选中的子图位置。因此 add_subplot 适合排布规范的多子图形式。

另外也可以通过 plt 直接设置网格,并获取到网格轴域 ax

1
2
3
4
5
6
7
8
9
 import matplotlib.pyplot as plt
 
 # 两行一列的图
 #(但是这种方式已经准备弃用了
 # Support for FigureCanvases without a required_interactive_framework attribute was deprecated
 # in Matplotlib 3.6 and will be removed two minor releases later.)
 fig, (ax1, ax2) = plt.subplots(2,1)
 ax1.plot(X, Y1, color="C1")
 ax2.plot(X, Y2, color="C0")

自定义网格布局

使用 add_gridspec 做更复杂的网格布局(占用多个网格作为一个图)

设置网格的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 import matplotlib.pyplot as plt
 
 fig3 = plt.figure(constrained_layout=True)
 gs = fig3.add_gridspec(3, 3)
 f3_ax1 = fig3.add_subplot(gs[0, :])
 f3_ax1.set_title('gs[0, :]')
 f3_ax2 = fig3.add_subplot(gs[1, :-1])
 f3_ax2.set_title('gs[1, :-1]')
 f3_ax3 = fig3.add_subplot(gs[1:, -1])
 f3_ax3.set_title('gs[1:, -1]')
 f3_ax4 = fig3.add_subplot(gs[-1, 0])
 f3_ax4.set_title('gs[-1, 0]')
 f3_ax5 = fig3.add_subplot(gs[-1, -2])
 f3_ax5.set_title('gs[-1, -2]')

b4956923db74477abbfa76eaa07043ed

设置比例的方式:

1
2
3
4
5
6
7
8
9
10
11
 fig5 = plt.figure(constrained_layout=True)
 widths = [2, 3, 1.5]
 heights = [1, 3, 2]
 spec5 = fig5.add_gridspec(
     ncols=3,
     nrows=3,
     width_ratios=widths,
     height_ratios=heights)
 for row in range(3):
     for col in range(3):
         ax = fig5.add_subplot(spec5[row, col])

edc553a4b3114cd096cad33d5422383d

Axes

画板上新增轴子图

1
2
3
4
5
 import matplotlib.pyplot as plt
 
 fig = plt.figure()                     # 新建画板
 ax1 = fig.add_axes([0.1,0.1,0.8,0.8])  # 新建画布
 ax2 = fig.add_axes([0.2,0.5,0.4,0.3])

add_axes 方法传入一个位置列表,列表中有四个值,格式如 [left, bottom, width, height]。其中 left 和 bottom 分别表示距离左侧和下边占整张图的比例(0-1 的取值范围),width 和 height 分别表示宽度和高度占整张图的比例(0-1 的取值范围),也就是起始位置是从左下角开始计算的(坐标系原点)。因此 add_axes 方法可以在图上的任意一个位置建立坐标轴并绘制曲线。

子图中新增轴子图

可以用来放大某一个指定区域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 # Implementation of matplotlib function
 import matplotlib.pyplot as plt

 fig, ax = plt.subplots()
 ax.plot(range(10))
 axin1 = ax.inset_axes(
         # 相对坐标,由 transform 决定
        [0.8, 0.1, 0.15, 0.15])
         # transform 默认是 transAxes
 axin2 = ax.inset_axes(
         # 数据坐标,由 transform 决定
         [5, 7, 2.3, 2.3],
         transform = ax.transData)
 
 ax.set_title(
     'matplotlib.axes.Axes.inset_axes() Example',
     fontsize = 14,
     fontweight ='bold')
 fig.show() # 会闪退,但是可以savefig
 # or
 plt.show()

4778e0ef4913417a90039d5d0d4bd08d

双轴图

可以在同一块区域使用不同的坐标,场景为多种曲线或者图形需要配置对应的坐标

1
2
3
4
5
6
7
8
 # 共用x轴,双纵轴图
 new_ax = ax.twinx()
 
 # 公用y轴,双横轴图
 new_ax = ax.twiny()
 
 # 新建两个轴(新画布是右边和上边的轴)
 new_ax = ax..twinx().twiny()

141b56d20e024b23b9f0f900a9a15cf6

附加轴子图(colorbar)

make_axes_locatable 是 Matplotlib 库中的一个函数,它用于创建一个新的 Axes 对象,并将其放置在主图 Axes 对象旁边的位置,以容纳 colorbar。这个函数通常用于在 Matplotlib 绘图中创建 colorbar。

1
2
3
4
5
6
7
8
9
10
11
12
13
 from mpl_toolkits.axes_grid1 import make_axes_locatable
 import matplotlib.pyplot as plt
 
 fig, ax = plt.subplots()
 
 # ... 画图 ...
 
 # 创建附加轴位置、大小、间距
 divider = make_axes_locatable(ax)
 cax = divider.append_axes('right', size='5%', pad=0.05)
 
 # 在新的 Axes 对象上创建 colorbar
 plt.colorbar(cax=cax)

44be687a323747fda9e9c6fab2139f7b

Axes 和 Subplot 总结

  • 两种对象确实是“你中有我,我中有你”的关系,生成子图(subplot)的时候,必然带着所谓的一套轴域(Axes)。而用轴域(Axes)方法,客观上就是生成了一个可以画图的子图。
  • add_subplot 方法在生成子图过程,简单明了;而用 add_axes 方法,则生成子图的灵活性更强,完全可以实现 add_subplot 方法的功能,可以控制子图显示位置,甚至实现相互重叠的效果。

通过新增子图获取到轴域就可以对其新增数据,增加图像的细节了。

2.2 间距调整

给子图添加标题和坐标轴标签后,子图可能会发生重叠,可以通过如下接口来调整:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 # 调整图位置和间距
 plt.subplots_adjust(
         left=None,
         bottom=None,
         right=None,
         top=None,
         wspace=None,
         hspace=None)
 # 整张图位置
 # left : 子图在画板上的左位置(position),默认0.125
 # right : 子图在画板上的右位置(position),默认0.9
 # bottom : 子图在画板上的下位置(position),默认0.1
 # top: 子图在画板上的上位置(position),默认0.9
 # 间距
 # wspace:子图之间的横向间距(padding),默认0.2
 # hspace:子图之间的纵向间距(padding),默认0.2

ffeb5c5223af477e9e463e2d78692005

三、数据

3.1 输入

Matplotlib 只能接收 np.array 格式或者 np.ma.masked_array 格式的数据。不接受类似数组的数据例如 pandasnp.matrix 类型的,最好将其转换成 np.array 类型。

pandas 类型转换:

1
2
 a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde'))
 a_asarray = a.values

np.matrix 类型转换:

1
2
 b = np.matrix([[1,2],[3,4]])
 b_asarray = np.asarray(b)

3.2 输出

保存图像到本地文件:

1
 plt.savefig('pic_name.png')

参考

python matplotlib 中 axes 与 axis 的区别是什么?