紧凑布局指南#

如何使用紧凑布局使绘图整齐地适应您的图形。

tight_layout 会自动调整子图参数,使子图(s) 适应图形区域。这是一个实验性功能,可能不适用于某些情况。它只检查刻度标签、轴标签和标题的范围。

tight_layout 的替代方法是 constrained_layout

简单示例#

使用默认的 Axes 定位,轴标题、轴标签或刻度标签有时会超出图形区域,从而被裁剪。

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['savefig.facecolor'] = "0.8"


def example_plot(ax, fontsize=12):
    ax.plot([1, 2])

    ax.locator_params(nbins=3)
    ax.set_xlabel('x-label', fontsize=fontsize)
    ax.set_ylabel('y-label', fontsize=fontsize)
    ax.set_title('Title', fontsize=fontsize)

plt.close('all')
fig, ax = plt.subplots()
example_plot(ax, fontsize=24)
Title

为了防止这种情况,需要调整 Axes 的位置。对于子图,可以通过使用 Figure.subplots_adjust 手动调整子图参数来实现。 Figure.tight_layout 会自动执行此操作。

fig, ax = plt.subplots()
example_plot(ax, fontsize=24)
plt.tight_layout()
Title

请注意,matplotlib.pyplot.tight_layout() 仅在调用时才会调整子图参数。为了在每次重新绘制图形时执行此调整,您可以调用 fig.set_tight_layout(True),或者等效地将 rcParams["figure.autolayout"] (默认值:False) 设置为 True

当您有多个子图时,您经常会看到不同 Axes 的标签相互重叠。

plt.close('all')

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
Title, Title, Title, Title

tight_layout() 还会调整子图之间的间距,以最大程度地减少重叠。

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
plt.tight_layout()
Title, Title, Title, Title

tight_layout() 可以接受关键字参数 padw_padh_pad。这些参数控制图形边框和子图之间的额外填充。填充以字体大小的比例指定。

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
Title, Title, Title, Title

tight_layout() 即使子图的大小不同,只要它们的网格规范兼容,它也能正常工作。在下面的示例中,ax1ax2 是 2x2 网格的子图,而 ax3 是 1x2 网格的子图。

plt.close('all')
fig = plt.figure()

ax1 = plt.subplot(221)
ax2 = plt.subplot(223)
ax3 = plt.subplot(122)

example_plot(ax1)
example_plot(ax2)
example_plot(ax3)

plt.tight_layout()
Title, Title, Title

它与使用 subplot2grid() 创建的子图一起使用。一般来说,从网格规范 (在图形中排列多个坐标轴) 创建的子图将起作用。

plt.close('all')
fig = plt.figure()

ax1 = plt.subplot2grid((3, 3), (0, 0))
ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)

example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)

plt.tight_layout()
Title, Title, Title, Title

虽然没有经过彻底测试,但它似乎适用于 aspect != "auto" 的子图(例如,包含图像的坐标轴)。

arr = np.arange(100).reshape((10, 10))

plt.close('all')
fig = plt.figure(figsize=(5, 4))

ax = plt.subplot()
im = ax.imshow(arr, interpolation="none")

plt.tight_layout()
tight layout guide

注意事项#

  • tight_layout 默认情况下会考虑坐标轴上的所有图形。要从布局计算中移除图形,可以调用 Artist.set_in_layout.

  • tight_layout 假设图形所需的额外空间与坐标轴的原始位置无关。这通常是正确的,但也有极少数情况并非如此。

  • pad=0 可能会将一些文本裁剪掉几个像素。这可能是当前算法的错误或限制,目前尚不清楚原因。同时,建议使用大于 0.3 的填充。

与 GridSpec 一起使用#

GridSpec 有自己的 GridSpec.tight_layout 方法(pyplot api 的 pyplot.tight_layout 也适用)。

import matplotlib.gridspec as gridspec

plt.close('all')
fig = plt.figure()

gs1 = gridspec.GridSpec(2, 1)
ax1 = fig.add_subplot(gs1[0])
ax2 = fig.add_subplot(gs1[1])

example_plot(ax1)
example_plot(ax2)

gs1.tight_layout(fig)
Title, Title

您可以提供一个可选的 rect 参数,它指定子图将被拟合的边界框。坐标使用归一化图形坐标,默认值为 (0, 0, 1, 1)(整个图形)。

fig = plt.figure()

gs1 = gridspec.GridSpec(2, 1)
ax1 = fig.add_subplot(gs1[0])
ax2 = fig.add_subplot(gs1[1])

example_plot(ax1)
example_plot(ax2)

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

但是,我们不建议使用它来手动构建更复杂的布局,例如在图形的左侧和右侧各有一个 GridSpec。对于这些用例,应该利用 嵌套 Gridspecs图形子图

图例和注释#

在 Matplotlib 2.2 之前,图例和注释被排除在决定布局的边界框计算之外。随后,这些艺术家被添加到计算中,但有时不希望包含它们。例如,在这种情况下,让 Axes 稍微缩小以腾出空间给图例可能是一个好主意。

fig, ax = plt.subplots(figsize=(4, 3))
lines = ax.plot(range(10), label='A simple plot')
ax.legend(bbox_to_anchor=(0.7, 0.5), loc='center left',)
fig.tight_layout()
plt.show()
tight layout guide

但是,有时不希望这样做(在使用 fig.savefig('outname.png', bbox_inches='tight') 时经常如此)。为了从边界框计算中移除图例,我们只需设置其边界 leg.set_in_layout(False),图例将被忽略。

fig, ax = plt.subplots(figsize=(4, 3))
lines = ax.plot(range(10), label='B simple plot')
leg = ax.legend(bbox_to_anchor=(0.7, 0.5), loc='center left',)
leg.set_in_layout(False)
fig.tight_layout()
plt.show()
tight layout guide

与 AxesGrid1 一起使用#

mpl_toolkits.axes_grid1 的支持有限。

from mpl_toolkits.axes_grid1 import Grid

plt.close('all')
fig = plt.figure()
grid = Grid(fig, rect=111, nrows_ncols=(2, 2),
            axes_pad=0.25, label_mode='L',
            )

for ax in grid:
    example_plot(ax)
ax.title.set_visible(False)

plt.tight_layout()
Title, Title, Title, Title

颜色条#

如果您使用 Figure.colorbar 创建颜色条,只要父 Axes 也是一个 Subplot,创建的颜色条就会绘制在一个 Subplot 中,因此 Figure.tight_layout 将起作用。

plt.close('all')
arr = np.arange(100).reshape((10, 10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")

plt.colorbar(im)

plt.tight_layout()
tight layout guide

另一种选择是使用 AxesGrid1 工具包显式地为颜色条创建一个 Axes。

from mpl_toolkits.axes_grid1 import make_axes_locatable

plt.close('all')
arr = np.arange(100).reshape((10, 10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")

divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "5%", pad="3%")
plt.colorbar(im, cax=cax)

plt.tight_layout()
tight layout guide

脚本总运行时间: (0 分钟 6.346 秒)

由 Sphinx-Gallery 生成的图库