如何使用紧凑布局清晰地绘制符合要求的图表。
紧凑布局自动调整subplot参数,使subplot(s)适合图表区域。这是一个试验特性,在某些情况下可能不起作用。它只检查刻度标签、轴标签和标题的范围。
紧凑布局的一种替代是约束布局(constrained_layout)。
简单示例
在matplotlib中,图表域(axes,包括子图表subplots)的位置在标准化图表(figure)坐标中指定。轴标签或标题(有时甚至是刻度标签)可能会超出图形区域,从而被剪裁。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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) fig, ax = plt.subplots()example_plot(ax, fontsize=24)
为了防止这种情况,需要调整图表域(axes)的位置。对于子图表(subplots),可以使用Figure.subplots_adjust手动调整它参数。Figure.tight_layout自动执行此操作。
·
·
·
fig, ax = plt.subplots()example_plot(ax, fontsize=24)plt.tight_layout()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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) fig, ax = plt.subplots()example_plot(ax, fontsize=24)plt.tight_layout()
请注意,matplotlib.pyplot.tight_layout()仅在调用时调整subplot参数。为了在每次重新绘制图表时执行此调整,可以调用fig.set_tight_layout(True),或者等效地将rcParams["figure.autolayout"] (默认值:False)设置为True。
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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) fig, ax = plt.subplots()fig.set_tight_layout(True)example_plot(ax, fontsize=24)
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as pltplt.rcParams["figure.autolayout"] = True
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) fig, ax = plt.subplots()example_plot(ax, fontsize=24)
当绘制多个子图表时,通常会看到不同图表域(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)
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)example_plot(ax1)example_plot(ax2)example_plot(ax3)example_plot(ax4)
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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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, ((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()
tight_layout() 可以接受 pad、w_pad和h_pad的关键字参数。这些控件控制图表边界周围和子图表(subplots)之间的额外填充。填充以字体大小的分数指定。
·
·
·
·
·
·
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)
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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, ((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)
即使子图表的大小不同,只要其网格规范兼容,tight_layout()也可以工作。在下面的示例中,ax1和ax2是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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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 = 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()
它适用于使用subplot2grid()创建的子图表(subplots)。通常,从gridspec(在图表中排列多个图表域,Arranging multiple Axes in a Figure)创建的子图表将起作用。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython
%matplotlib tkimport matplotlib.pyplot as plt
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 = 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()
虽然没有经过彻底测试,但它似乎适用于具有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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltimport numpy as np
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)会考虑图表域(axes)上的所有艺术家(artist)。要从布局计算中忽略某个艺术家,可以调用Artist.set_in_layout(True/False)(本文后面有例子)。
● 紧凑布局假设艺术家所需的额外空间独立于图表域(axes)的原始位置。这通常是正确的,但有极少情况不是。
● pad=0可以将一些文本裁剪几个像素。这可能是当前算法的错误或限制,目前尚不清楚为什么会发生这种情况。同时,建议使用大于0.3的pad。
与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)
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltimport matplotlib.gridspec as gridspec
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 = 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(矩形)参数,该参数指定子图表(subplot)将放在其中的边界框。坐标必须为标准化图表(figure)坐标,默认值为(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])
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltimport matplotlib.gridspec as gridspec
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 = 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])
然而,我们不建议将其用于手动构建更复杂的布局,例如在图表的左侧和右侧各有一个GridSpec。对于这些用例,应该使用嵌套的Gridpec(Nested Gridspecs)或图表的子图表(Figure subfigures)。
图例和注释
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()
完整代码:
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltfig, 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()
然而,有时这是不需要这样的(在使用fig.savefig('outname.png',bbox_inches='ight')时经常如此)。为了从边界框计算中忽略图例,只需设置其边界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()
完整代码:
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltfig, 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()
与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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltfrom mpl_toolkits.axes_grid1 import Grid
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 = 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()
色条(Colorbar)
如果使用Figure.colorbar创建了一个色条,则只要父图表域(axes)也是子图表(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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltimport numpy as np
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()
另一个选项是使用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()
完整代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
ipython%matplotlib tkimport matplotlib.pyplot as pltimport numpy as npfrom 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()
constrained_layout:
https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html
Figure.subplots_adjust:
https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.subplots_adjust
Figure.tight_layout:
https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.tight_layout
matplotlib.pyplot.tight_layout():
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.tight_layout.html#matplotlib.pyplot.tight_layout
rcParams["figure.autolayout"]:
https://matplotlib.org/stable/tutorials/introductory/customizing.html?highlight=figure.autolayout#matplotlibrc-sample
tight_layout():
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.tight_layout.html#matplotlib.pyplot.tight_layout
subplot2grid():
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplot2grid.html#matplotlib.pyplot.subplot2grid
Arranging multiple Axes in a Figure:
https://matplotlib.org/stable/tutorials/intermediate/arranging_axes.html
Artist.set_in_layout:
https://matplotlib.org/stable/api/_as_gen/matplotlib.artist.Artist.set_in_layout.html#matplotlib.artist.Artist.set_in_layout
GridSpec.tight_layout:
https://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec.tight_layout
pyplot.tight_layout:
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.tight_layout.html#matplotlib.pyplot.tight_layout
mpl_toolkits.axes_grid1:
https://matplotlib.org/stable/api/toolkits/axes_grid1.html#module-mpl_toolkits.axes_grid1
Figure.colorbar:
https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.colorbar