• 密致布局指南
    • 简单的示例
    • 警告
    • GridSpec一起使用
    • AxesGrid1一起使用
    • 颜色条

    密致布局指南

    原文:Tight Layout guide

    译者:飞龙

    协议:CC BY-NC-SA 4.0

    tight_layout会自动调整子图参数,使之填充整个图像区域。这是个实验特性,可能在一些情况下不工作。它仅仅检查坐标轴标签、刻度标签以及标题的部分。

    简单的示例

    在 matplotlib 中,轴域(包括子图)的位置以标准化图形坐标指定。 可能发生的是,你的轴标签或标题(有时甚至是刻度标签)会超出图形区域,因此被截断。

    1. plt.rcParams['savefig.facecolor'] = "0.8"
    2. def example_plot(ax, fontsize=12):
    3. ax.plot([1, 2])
    4. ax.locator_params(nbins=3)
    5. ax.set_xlabel('x-label', fontsize=fontsize)
    6. ax.set_ylabel('y-label', fontsize=fontsize)
    7. ax.set_title('Title', fontsize=fontsize)
    8. plt.close('all')
    9. fig, ax = plt.subplots()
    10. example_plot(ax, fontsize=24)

    密致布局教程 - 图1

    为了避免它,轴域的位置需要调整。对于子图,这可以通过调整子图参数(移动轴域的一条边来给刻度标签腾地方)。Matplotlib v1.1 引入了一个新的命令tight_layout(),自动为你解决这个问题。

    1. plt.tight_layout()

    密致布局教程 - 图2

    当你拥有多个子图时,你会经常看到不同轴域的标签叠在一起。

    1. plt.close('all')
    2. fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
    3. example_plot(ax1)
    4. example_plot(ax2)
    5. example_plot(ax3)
    6. example_plot(ax4)

    密致布局教程 - 图3

    tight_layout()也会调整子图之间的间隔来减少堆叠。

    密致布局教程 - 图4

    tight_layout()可以接受关键字参数padw_pad或者h_pad,这些参数图像边界和子图之间的额外边距。边距以字体大小单位规定。

    1. plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)

    密致布局教程 - 图5

    即使子图大小不同,tight_layout()也能够工作,只要网格的规定的兼容的。在下面的例子中,ax1ax2是 2x2 网格的子图,但是ax3是 1x2 网格。

    1. plt.close('all')
    2. fig = plt.figure()
    3. ax1 = plt.subplot(221)
    4. ax2 = plt.subplot(223)
    5. ax3 = plt.subplot(122)
    6. example_plot(ax1)
    7. example_plot(ax2)
    8. example_plot(ax3)
    9. plt.tight_layout()

    密致布局教程 - 图6

    它适用于使用subplot2grid()创建的子图。 一般来说,从gridspec(使用GridSpec自定义子布局的位置)创建的子图也能正常工作。

    1. plt.close('all')
    2. fig = plt.figure()
    3. ax1 = plt.subplot2grid((3, 3), (0, 0))
    4. ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
    5. ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
    6. ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
    7. example_plot(ax1)
    8. example_plot(ax2)
    9. example_plot(ax3)
    10. example_plot(ax4)
    11. plt.tight_layout()

    密致布局教程 - 图7

    虽然没有彻底测试,它看起来也适用于aspect不为auto的子图(例如带有图像的轴域)。

    1. arr = np.arange(100).reshape((10,10))
    2. plt.close('all')
    3. fig = plt.figure(figsize=(5,4))
    4. ax = plt.subplot(111)
    5. im = ax.imshow(arr, interpolation="none")
    6. plt.tight_layout()

    密致布局教程 - 图8

    警告

    • tight_layout()只考虑刻度标签,轴标签和标题。 因此,其他艺术家可能被截断并且也可能重叠。
    • 它假定刻度标签,轴标签和标题所需的额外空间与轴域的原始位置无关。 这通常是真的,但在罕见的情况下不是。
    • pad = 0将某些文本剪切几个像素。 这可能是当前算法的错误或限制,并且不清楚为什么会发生。 同时,推荐使用至少大于 0.3 的间隔。

    GridSpec一起使用

    GridSpec拥有自己的tight_layout()方法(pyplot API 的tight_layout()也能生效)。

    1. plt.close('all')
    2. fig = plt.figure()
    3. import matplotlib.gridspec as gridspec
    4. gs1 = gridspec.GridSpec(2, 1)
    5. ax1 = fig.add_subplot(gs1[0])
    6. ax2 = fig.add_subplot(gs1[1])
    7. example_plot(ax1)
    8. example_plot(ax2)
    9. gs1.tight_layout(fig)

    密致布局教程 - 图9

    你可以提供一个可选的rect参数,指定子图所填充的边框。 坐标必须为标准化图形坐标,默认值为(0, 0, 1, 1)

    1. gs1.tight_layout(fig, rect=[0, 0, 0.5, 1])

    密致布局教程 - 图10

    例如,这可用于带有多个gridspecs的图形。

    1. gs2 = gridspec.GridSpec(3, 1)
    2. for ss in gs2:
    3. ax = fig.add_subplot(ss)
    4. example_plot(ax)
    5. ax.set_title("")
    6. ax.set_xlabel("")
    7. ax.set_xlabel("x-label", fontsize=12)
    8. gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5)

    密致布局教程 - 图11

    我们可以尝试匹配两个网格的顶部和底部。

    1. top = min(gs1.top, gs2.top)
    2. bottom = max(gs1.bottom, gs2.bottom)
    3. gs1.update(top=top, bottom=bottom)
    4. gs2.update(top=top, bottom=bottom)

    虽然这应该足够好了,调整顶部和底部可能也需要调整hspace。 为了更新hspacevspace,我们再次使用更新后的rect参数调用tight_layout()。 注意,rect参数指定的区域包括刻度标签。因此,我们将底部(正常情况下为 0)增加每个gridspec的底部之差。 顶部也一样。

    1. top = min(gs1.top, gs2.top)
    2. bottom = max(gs1.bottom, gs2.bottom)
    3. gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom),
    4. 0.5, 1 - (gs1.top-top)])
    5. gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom),
    6. None, 1 - (gs2.top-top)],
    7. h_pad=0.5)

    密致布局教程 - 图12

    AxesGrid1一起使用

    虽然受限但也支持axes_grid1工具包

    1. plt.close('all')
    2. fig = plt.figure()
    3. from mpl_toolkits.axes_grid1 import Grid
    4. grid = Grid(fig, rect=111, nrows_ncols=(2,2),
    5. axes_pad=0.25, label_mode='L',
    6. )
    7. for ax in grid:
    8. example_plot(ax)
    9. ax.title.set_visible(False)
    10. plt.tight_layout()

    密致布局教程 - 图13

    颜色条

    如果你使用colorbar命令创建了颜色条,创建的颜色条是Axes而不是Subplot的实例,所以tight_layout没有效果。在 Matplotlib v1.1 中,你可以使用gridspec将颜色条创建为子图。

    1. plt.close('all')
    2. arr = np.arange(100).reshape((10,10))
    3. fig = plt.figure(figsize=(4, 4))
    4. im = plt.imshow(arr, interpolation="none")
    5. plt.colorbar(im, use_gridspec=True)
    6. plt.tight_layout()

    ![])http://matplotlib.org/_images/tight_layout_guide-14.png

    另一个选项是使用AxesGrid1工具包,显式为颜色条创建一个轴域:

    1. plt.close('all')
    2. arr = np.arange(100).reshape((10,10))
    3. fig = plt.figure(figsize=(4, 4))
    4. im = plt.imshow(arr, interpolation="none")
    5. from mpl_toolkits.axes_grid1 import make_axes_locatable
    6. divider = make_axes_locatable(plt.gca())
    7. cax = divider.append_axes("right", "5%", pad="3%")
    8. plt.colorbar(im, cax=cax)
    9. plt.tight_layout()

    密致布局教程 - 图14