强基初中数学&学Python——第270课 数字和数学第三方模块Matplotlib之七:封装端-在图表中排列多个图表域(4)

低级和高等网格方法

  在内部,通过创建GridSpecSublotSpec的实例来控制图表域(Axes)网格的排列。GridSpec定义了一个(可能是非均匀的)单元格网格。当索引到GridSpec时,会返回覆盖一个或多个网格单元的SublotSpec,并可用于指定图表域的位置。

  以下示例显示如何使用低级方法利用GridSpec对象排列图表域。

基本2x2网格

  我们可以以与plt.subplots(2, 2)相同的方式完成2x2网格:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

ipython%matplotlib tkimport matplotlib.pyplot as plt
def annotate_axes(ax, text, fontsize=18):    ax.text(0.5, 0.5, text, transform=ax.transAxes,            ha="center", va="center", fontsize=fontsize, color="darkgrey")
fig = plt.figure(figsize=(5.5, 3.5), layout="constrained")spec = fig.add_gridspec(ncols=2, nrows=2)
ax0 = fig.add_subplot(spec[0, 0])annotate_axes(ax0, 'ax0')
ax1 = fig.add_subplot(spec[0, 1])annotate_axes(ax1, 'ax1')
ax2 = fig.add_subplot(spec[1, 0])annotate_axes(ax2, 'ax2')
ax3 = fig.add_subplot(spec[1, 1])annotate_axes(ax3, 'ax3')
fig.suptitle('Manually added subplots using add_gridspec')

 

 

跨越网格中的行或列的图表域

  我们可以使用NumPy切片语法对spec数组进行索引,新的图表域(Axes)将跨越切片。这与fig, axd = plt.subplot_mosaic([['ax0', 'ax0'], ['ax1', 'ax2']], ...)相同:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

ipython%matplotlib tkimport matplotlib.pyplot as plt
def annotate_axes(ax, text, fontsize=18):    ax.text(0.5, 0.5, text, transform=ax.transAxes,            ha="center", va="center", fontsize=fontsize, color="darkgrey")
fig = plt.figure(figsize=(5.5, 3.5), layout="constrained")spec = fig.add_gridspec(2, 2)
ax0 = fig.add_subplot(spec[0, :])annotate_axes(ax0, 'ax0')
ax10 = fig.add_subplot(spec[1, 0])annotate_axes(ax10, 'ax10')
ax11 = fig.add_subplot(spec[1, 1])annotate_axes(ax11, 'ax11')
fig.suptitle('Manually added subplots, spanning a column')

 

 

GridSpec布局的手动调整

  显式使用GridSpec时,可以调整GridSpec创建的子图表(subplots)的布局参数。请注意,此选项与constrained_layout或Figure.tight_layout不兼容,后者都会忽略左侧和右侧,并调整子图表大小以填充图形。通常,这种手动放置需要迭代,以使图表域刻度标签不与图表域重叠。

  这些间距参数也可以作为gridspec_kw(键值对)参数传递给subplotssubplot_mosaic

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

ipython%matplotlib tkimport matplotlib.pyplot as plt
def annotate_axes(ax, text, fontsize=18):    ax.text(0.5, 0.5, text, transform=ax.transAxes,            ha="center", va="center", fontsize=fontsize, color="darkgrey")
fig = plt.figure(layout=None, facecolor='0.9')gs = fig.add_gridspec(nrows=3, ncols=3, left=0.05, right=0.75,                      hspace=0.1, wspace=0.05)ax0 = fig.add_subplot(gs[:-1, :])annotate_axes(ax0, 'ax0')ax1 = fig.add_subplot(gs[-1, :-1])annotate_axes(ax1, 'ax1')ax2 = fig.add_subplot(gs[-1, -1])annotate_axes(ax2, 'ax2')fig.suptitle('Manual gridspec with right=0.75')

 

 

SubplotSpec的嵌套布局

  可以使用subgridspec创建类似于subfigures的嵌套布局。在这里,图表域(Axes)的框架是对齐的。

  请注意,这也可以从更详细的gridspec.GridSpecFromSubplotSpec中获得。

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

ipython%matplotlib tkimport matplotlib.pyplot as plt
def annotate_axes(ax, text, fontsize=18):    ax.text(0.5, 0.5, text, transform=ax.transAxes,            ha="center", va="center", fontsize=fontsize, color="darkgrey")
fig = plt.figure(layout="constrained")gs0 = fig.add_gridspec(1, 2)
gs00 = gs0[0].subgridspec(2, 2)gs01 = gs0[1].subgridspec(3, 1)
for a in range(2):    for b in range(2):        ax = fig.add_subplot(gs00[a, b])        annotate_axes(ax, f'axLeft[{a}, {b}]', fontsize=10)        if a == 1 and b == 1:            ax.set_xlabel('xlabel')for a in range(3):    ax = fig.add_subplot(gs01[a])    annotate_axes(ax, f'axRight[{a}, {b}]')    if a == 2:        ax.set_ylabel('ylabel')
fig.suptitle('nested gridspecs')

 

  下面是嵌套GridSpec的一个更复杂的例子:我们创建了一个外部4x4网格,每个单元格都包含一个内部3x3网格的图表域(Axes)。我们通过在每个内部3x3网格中隐藏适当的框架线来呈现4x4网格的轮廓。

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

ipython%matplotlib tkimport matplotlib.pyplot as pltimport numpy as np
def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)):    return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d)
fig = plt.figure(figsize=(8, 8), constrained_layout=False)outer_grid = fig.add_gridspec(4, 4, wspace=0, hspace=0)
for a in range(4):    for b in range(4):        # gridspec inside gridspec        inner_grid = outer_grid[a, b].subgridspec(3, 3, wspace=0, hspace=0)        axs = inner_grid.subplots()  # Create all subplots for the inner grid.        for (c, d), ax in np.ndenumerate(axs):            ax.plot(*squiggle_xy(a + 1, b + 1, c + 1, d + 1))            ax.set(xticks=[], yticks=[])
# show only the outside spinesfor ax in fig.get_axes():    ss = ax.get_subplotspec()    ax.spines.top.set_visible(ss.is_first_row())    ax.spines.bottom.set_visible(ss.is_last_row())    ax.spines.left.set_visible(ss.is_first_col())    ax.spines.right.set_visible(ss.is_last_col())

 

 

 

拓展阅读

● 关于subplot mosaic的更多细节。https://matplotlib.org/stable/gallery/subplots_axes_and_figures/mosaic.html● 关于受约束布局(constrained layout)的更多详细信息,在大多数示例中用于对齐间距。https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html参考
本例使用了以下函数、方法、类和模块:
● matplotlib.pyplot.subplotshttps://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots.html#matplotlib.pyplot.subplots● matplotlib.pyplot.subplot_mosaichttps://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplot_mosaic.html#matplotlib.pyplot.subplot_mosaic● matplotlib.figure.Figure.add_gridspechttps://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.add_gridspec● matplotlib.figure.Figure.add_subplothttps://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.add_subplot

● matplotlib.gridspec.GridSpec

https://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec● matplotlib.gridspec.SubplotSpec.subgridspechttps://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.SubplotSpec.html#matplotlib.gridspec.SubplotSpec.subgridspec● matplotlib.gridspec.GridSpecFromSubplotSpechttps://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.GridSpecFromSubplotSpec.html#matplotlib.gridspec.GridSpecFromSubplotSpec