tight_layout 会自动调整布局参数来重新调整图形,但这仅是个实验性的方法,有些情况下可能并不能起到很好的效果。而且它只检查 ticklabels,title,axis labels。
简单示例
matplotlib中,axes 的位置(包括 subplot)都被归一化为 figure 坐标。当 axis labels 或 titles 超出 figure 区域被剪切时才会起作用。
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)
为了防止出现这种情况,必须调整 axes 的位置。对于 subplots 来说,可以通过调整子图参数实现 [注1]。自matplotlib 1.1 版本,提供了 tight_layout 函数自动完成子图布局调整。
plt.tight_layout()
当绘制多个子图时,每个图的 ticklabels 可能会和其它图出现重叠
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)
plt.show()
使用 tight_layout 可以自动调整
plt.tight_layout()
tight_layout 也提供 pad, w_pad, h_pad 关键词参数设置 figure 边界和 子图间的间距。
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
即使各子图的尺寸不同也是可以通过 tight_layout 自动调整的。而且对于 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()
使用GridSpec
GridSpec 有自己的 tight_layout 函数,当然 pyplot.tight_layout 也能对其产生影响。
plt.close('all')
fig = plt.figure()
import matplotlib.gridspec as gridspec
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 参数来设置边界框
gs1.tight_layout(fig, rect=[0, 0, 0.5, 1])
例如:
gs2 = gridspec.GridSpec(3, 1)
for ss in gs2:
ax = fig.add_subplot(ss)
example_plot(ax)
ax.set_title("")
ax.set_xlabel("")
ax.set_xlabel("x-label", fontsize=12)
gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5)
也可以匹配两个网格的 top 和 bottom
top = min(gs1.top, gs2.top)
bottom = max(gs1.bottom, gs2.bottom)
gs1.update(top=top, bottom=bottom)
gs2.update(top=top, bottom=bottom)
大多数情况下,虽然这样也可以,但是通常还需要设置 hspace。调用 tight_layout 函数通过 rect 参数更新 hspace 和 vspace。注意:rect 参数确定的区域包括 ticklabels。因此,bottom 将加上上面图的 bottom 和 每一个 gridspec 的 bottom 之差, top 同理。
top = min(gs1.top, gs2.top)
bottom = max(gs1.bottom, gs2.bottom)
gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom),
0.5, 1 - (gs1.top-top)])
gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom),
None, 1 - (gs2.top-top)],
h_pad=0.5)
AxesGrid1
虽然支持有限,但也能产生些许效果。
plt.close('all')
fig = plt.figure()
from mpl_toolkits.axes_grid1 import Grid
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()
Colorbar
如果使用 colorbar 命令创建一个 colorbar,那么 colorbar 将是 Axes 实例,而不是 subplot,因此 tight_layout 不会生效。V1.1 开始,可以像使用 gridspec 创建 subplot 一样,创建 colorbar。
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, use_gridspec=True)
plt.tight_layout()
另一种方法时使用 AxesGrid1 为 colorbar 创建一个 axes
plt.close('all')
arr = np.arange(100).reshape((10,10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")
from mpl_toolkits.axes_grid1 import make_axes_locatable
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "5%", pad="3%")
plt.colorbar(im, cax=cax)
plt.tight_layout()
注1:http://matplotlib.org/faq/howto_faq.html#howto-subplots-adjust