网站建设宗旨是指,最新闻头条新闻,企业工商查询,公司网站建设合同使用受约束的绘图干净整洁地将图形合适排列。
受约束的布局会自动调整子图#xff0c;以便刻度标签、图例和颜色条等装饰不会重叠#xff0c;同时仍保留用户请求的逻辑布局。
受约束布局类似于“紧密布局”#xff0c;但它要更灵活。它处理放置在多个轴上的Axes(放置颜色条…使用受约束的绘图干净整洁地将图形合适排列。
受约束的布局会自动调整子图以便刻度标签、图例和颜色条等装饰不会重叠同时仍保留用户请求的逻辑布局。
受约束布局类似于“紧密布局”但它要更灵活。它处理放置在多个轴上的Axes(放置颜色条)嵌套布局子图和跨越行或列的Axes(子图拼接)努力将Axes中的脊对齐在同一行或同一列中。此外压缩布局将尝试将固定纵横比Axes移动得更近。本文档介绍了这些功能并在最后讨论了一些实现的细节。
在将任何Axes添加到图窗之前通常需要激活受约束的布局有两种方法可以做到这一点。
使用相应的参数进行子绘图、图形的子图拼接例如
plt.subplots(layoutconstrained)通过rcParams激活它例如
plt.rcParams[figure.constrained_layout.use] True以下各节将详细介绍这些内容。 注意 调用plt.tight_layout()会关闭掉受约束布局 1. 简单的例子
在matplotlib中Axes(包括子图的位置以归一化的图形坐标指定。轴标签或标题有时甚至是刻度标签可能会超出图窗区域从而遭到剪裁
import matplotlib.pyplot as plt
import numpy as npimport matplotlib.colors as mcolors
import matplotlib.gridspec as gridspecplt.rcParams[savefig.facecolor] 0.8
plt.rcParams[figure.figsize] 4.5, 4.
plt.rcParams[figure.max_open_warning] 50def example_plot(ax, fontsize12, hide_labelsFalse):ax.plot([1, 2])ax.locator_params(nbins3)if hide_labels:ax.set_xticklabels([])ax.set_yticklabels([])else:ax.set_xlabel(x-label, fontsizefontsize)ax.set_ylabel(y-label, fontsizefontsize)ax.set_title(Title, fontsizefontsize)fig, ax plt.subplots(layoutNone)
example_plot(ax, fontsize24)为了避免遭到这种问题需要调整图像Axes的位置。对于子图可以通过使用Figure.subplots_adjust调整子图参数来手动完成但是使用layoutconstrained关键字参数指定图形将自动进行调整。
fig, ax plt.subplots(layoutconstrained)
example_plot(ax, fontsize24)当有多幅子图需要绘制时经常会发现它们之间出现互相遮盖的问题。
fig, axs plt.subplots(2, 2, layoutNone)
for ax in axs.flat:example_plot(ax)在对plt.subplots的调用中指定layoutconstrained会使得布局受到适当的约束。
fig, axs plt.subplots(2, 2, layoutconstrained)
for ax in axs.flat:example_plot(ax)2. 颜色条
如果使用Figure.colorbar创建颜色条则需要为其腾出空间。受约束的布局会自动执行此操作。请注意如果指定use_gridspecTrue它将被忽略因为此选项用于通过tight_layout来改进布局。 注意 对于pcolormesh关键字参数pc_kwargs)我们使用字典来保持本文档中调用的一致性。 arr np.arange(100).reshape((10, 10))
norm mcolors.Normalize(vmin0., vmax100.)
# 参看上面的注意下面的设置可以保持样式的一致性:
pc_kwargs {rasterized: True, cmap: viridis, norm: norm}
fig, ax plt.subplots(figsize(4, 4), layoutconstrained)
im ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, axax, shrink0.6)如果将Axes或其他可迭代容器列表指定到colorbar的ax参数则受约束的布局将从指定的Axis轴中占用空间。
fig, axs plt.subplots(2, 2, figsize(4, 4), layoutconstrained)
for ax in axs.flat:im ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, axaxs, shrink0.6)如果从Axes网格内指定Axes列表则颜色条将适当地窃取空间并留出间隙但所有子图的大小仍将相同。
fig, axs plt.subplots(3, 3, figsize(4, 4), layoutconstrained)
for ax in axs.flat:im ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, axaxs[1:, 1], shrink0.8)
fig.colorbar(im, axaxs[:, -1], shrink0.6)3. 总标题
受约束的布局也可以为总标题腾出空间。
fig, axs plt.subplots(2, 2, figsize(4, 4), layoutconstrained)
for ax in axs.flat:im ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, axaxs, shrink0.6)
fig.suptitle(Big Suptitle)4. 图例
图像可以放在其父轴之外Constrained layout旨在为Axes.legend()处理此问题。但是受约束的布局还不能处理通过Figure.legend()创建的图例。
fig, ax plt.subplots(layoutconstrained)
ax.plot(np.arange(10), labelThis is a plot)
ax.legend(loccenter left, bbox_to_anchor(0.8, 0.5))但是这将从子图布局中窃取空间
fig, axs plt.subplots(1, 2, figsize(4, 2), layoutconstrained)
axs[0].plot(np.arange(10))
axs[1].plot(np.arange(10), labelThis is a plot)
axs[1].legend(loccenter left, bbox_to_anchor(0.8, 0.5))为了让图例或其他的artist对象不从子布局中窃取空间我们可以让leg.set_in_layout(False)。当然这可能意味着图例最终会被裁剪但如果随后使用fig.savefig(outname.png,bbox_inchestight)调用图则图例会很有用。但是请注意必须再次切换图例的get_in_layout状态才能使保存的文件正常工作如果我们希望受约束的布局在打印前调整Axes的大小则必须手动触发绘制。
fig, axs plt.subplots(1, 2, figsize(4, 2), layoutconstrained)axs[0].plot(np.arange(10))
axs[1].plot(np.arange(10), labelThis is a plot)
leg axs[1].legend(loccenter left, bbox_to_anchor(0.8, 0.5))
leg.set_in_layout(False)
# trigger a draw so that constrained layout is executed once
# before we turn it off when printing....
fig.canvas.draw()
# we want the legend included in the bbox_inchestight calcs.
leg.set_in_layout(True)
# we dont want the layout to change at this point.
fig.set_layout_engine(none)
try:fig.savefig(../../../doc/_static/constrained_layout_1b.png,bbox_inchestight, dpi100)
except FileNotFoundError:# this allows the script to keep going if run interactively and# the directory above doesnt existpass保存的文件如下所示
5. 填充和空间
Axes之间的填充在水平方向上由w_pad和wspace控制垂直方向由h_pad和hspace控制。这些可以通过设置进行编辑。w/h_pad是Axes周围的最小空间以英寸为单位
fig, axs plt.subplots(2, 2, layoutconstrained)
for ax in axs.flat:example_plot(ax, hide_labelsTrue)
fig.get_layout_engine().set(w_pad4 / 72, h_pad4 / 72, hspace0,wspace0)子图之间的间距由wspace和hspace进一步设置。这些值被指定为整个子图组大小的一小部分。如果这些值小于w_pad或h_pad则改用固定焊盘。请注意在下面的环境中边缘的空间与上面的空间没有变化但子图之间的空间却发生了变化。
fig, axs plt.subplots(2, 2, layoutconstrained)
for ax in axs.flat:example_plot(ax, hide_labelsTrue)
fig.get_layout_engine().set(w_pad4 / 72, h_pad4 / 72, hspace0.2,wspace0.2)如果有两列以上则wspace在它们之间共享因此这里wspace一分为二每列之间的wspace为0.1
fig, axs plt.subplots(2, 3, layoutconstrained)
for ax in axs.flat:example_plot(ax, hide_labelsTrue)
fig.get_layout_engine().set(w_pad4 / 72, h_pad4 / 72, hspace0.2,wspace0.2)GridSpecs还具有可选的hspace和wspace关键字参数这些参数将用于代替受约束布局设置的填充
fig, axs plt.subplots(2, 2, layoutconstrained,gridspec_kw{wspace: 0.3, hspace: 0.2})
for ax in axs.flat:example_plot(ax, hide_labelsTrue)
# this has no effect because the space set in the gridspec trumps the
# space set in *constrained layout*.
fig.get_layout_engine().set(w_pad4 / 72, h_pad4 / 72, hspace0.0,wspace0.0)带有颜色条的空间
颜色条放置在与其父项的距离填充上其中填充是父项宽度的一小部分。然后下一个子图的间距由w/hspace给出。
fig, axs plt.subplots(2, 2, layoutconstrained)
pads [0, 0.05, 0.1, 0.2]
for pad, ax in zip(pads, axs.flat):pc ax.pcolormesh(arr, **pc_kwargs)fig.colorbar(pc, axax, shrink0.6, padpad)ax.set_xticklabels([])ax.set_yticklabels([])ax.set_title(fpad: {pad})
fig.get_layout_engine().set(w_pad2 / 72, h_pad2 / 72, hspace0.2,wspace0.2)6. rcParams
可以在脚本或matplotlibrc文件中设置五个rcParams。它们都具有前缀figure.constrained_layout
use: 是否使用受约束的布局。默认值为Falsew_pad,h_pad: 围绕Axes对象进行填充。表示英寸的浮点数。默认值为3./72.英寸(3pts);wspace,hspace子图组之间的间距。浮点数表示要分隔的子图宽度的一小部分。默认值为0.02。
plt.rcParams[figure.constrained_layout.use] True
fig, axs plt.subplots(2, 2, figsize(3, 3))
for ax in axs.flat:example_plot(ax)7. 使用GridSpec
约束布局旨在与subplots()、subplot_mosaic()或带有add_subplot()的GridSpec()一起使用。
注意到这些是跟在layoutconstrained
plt.rcParams[figure.constrained_layout.use] False
fig plt.figure(layoutconstrained)gs1 gridspec.GridSpec(2, 1, figurefig)
ax1 fig.add_subplot(gs1[0])
ax2 fig.add_subplot(gs1[1])example_plot(ax1)
example_plot(ax2)可以进行更复杂的网格规范布局。请清廉这里我们使用便利函数add_gridspec和subgridspec。
fig plt.figure(layoutconstrained)gs0 fig.add_gridspec(1, 2)gs1 gs0[0].subgridspec(2, 1)
ax1 fig.add_subplot(gs1[0])
ax2 fig.add_subplot(gs1[1])example_plot(ax1)
example_plot(ax2)gs2 gs0[1].subgridspec(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, fontsize12)请注意在上面的列中左列和右列的垂直范围不同。如果我们希望两个网格的顶部和底部对齐那么它们需要位于同一个网格规范中。我们还需要使这个数字变大以便Axes不会折叠到零高度
fig plt.figure(figsize(4, 6), layoutconstrained)gs0 fig.add_gridspec(6, 2)ax1 fig.add_subplot(gs0[:3, 0])
ax2 fig.add_subplot(gs0[3:, 0])example_plot(ax1)
example_plot(ax2)ax fig.add_subplot(gs0[0:2, 1])
example_plot(ax, hide_labelsTrue)
ax fig.add_subplot(gs0[2:4, 1])
example_plot(ax, hide_labelsTrue)
ax fig.add_subplot(gs0[4:, 1])
example_plot(ax, hide_labelsTrue)
fig.suptitle(Overlapping Gridspecs)此示例使用两个gridspec使颜色条仅与一组pcolor相关。请注意由于这个原因左边的列比右边的两列宽。当然如果你希望子图的大小相同则只需要一个网格规范。请注意使用子图可以达到相同的效果。
fig plt.figure(layoutconstrained)
gs0 fig.add_gridspec(1, 2, figurefig, width_ratios[1, 2])
gs_left gs0[0].subgridspec(2, 1)
gs_right gs0[1].subgridspec(2, 2)for gs in gs_left:ax fig.add_subplot(gs)example_plot(ax)
axs []
for gs in gs_right:ax fig.add_subplot(gs)pcm ax.pcolormesh(arr, **pc_kwargs)ax.set_xlabel(x-label)ax.set_ylabel(y-label)ax.set_title(title)axs [ax]
fig.suptitle(Nested plots using subgridspec)
fig.colorbar(pcm, axaxs)Matplotlib现在不再使用subgridspecs而是提供了子图形这些子图形也适用于受约束的布局
fig plt.figure(layoutconstrained)
sfigs fig.subfigures(1, 2, width_ratios[1, 2])axs_left sfigs[0].subplots(2, 1)
for ax in axs_left.flat:example_plot(ax)axs_right sfigs[1].subplots(2, 2)
for ax in axs_right.flat:pcm ax.pcolormesh(arr, **pc_kwargs)ax.set_xlabel(x-label)ax.set_ylabel(y-label)ax.set_title(title)
fig.colorbar(pcm, axaxs_right)
fig.suptitle(Nested plots using subfigures)8. 手动设置Axes位置
手动设置Axes位置可能是有充分理由的。手动调用set_position将设置Axes因此受约束的布局不再对其产生影响。请注意受约束的布局仍会为移动的Axes留出空间。
fig, axs plt.subplots(1, 2, layoutconstrained)
example_plot(axs[0], fontsize12)
axs[1].set_position([0.2, 0.2, 0.4, 0.4])9. 固定纵横比的网格压缩布局
受约束的布局在Axes的原始位置网格上运行。但是当轴具有固定的纵横比时一侧通常会变短并在缩短的方向上留下较大的间隙。在下图中Axes是正方形的但图形很宽因此存在水平间隙
fig, axs plt.subplots(2, 2, figsize(5, 3),sharexTrue, shareyTrue, layoutconstrained)
for ax in axs.flat:ax.imshow(arr)
fig.suptitle(fixed-aspect plots, layoutconstrained)解决这个问题的一个明显方法是使图形大小更方形但是缩小差距完全需要反复试验。对于简单的轴网格我们可以使用layoutcompressed为我们完成这项工作
fig, axs plt.subplots(2, 2, figsize(5, 3),sharexTrue, shareyTrue, layoutcompressed)
for ax in axs.flat:ax.imshow(arr)
fig.suptitle(fixed-aspect plots, layoutcompressed)10. 手动关闭受约束的布局
受约束的布局通常会调整图形每次绘制时的Axes位置。如果要获取受约束布局提供的间距但不对其进行更新请执行初始绘制然后调用fig.set_layout_engine(none)。这对于刻度标签可能更改长度的动画可能很有用。
请注意对于使用工具栏的后端ZOOM和PAN GUI事件的约束布处于关闭状态。这样可以防止Axes在缩放和平移期间改变位置。
11. 限制
不兼容的功能
受约束的布局将适用于pyplot.subplot但前提是每次调用的行数和列数相同。原因是如果几何形状不同且布局受约束则每次调用pyplot.subplot都会创建一个新的GridSpec实例。因此以下工作正常
fig plt.figure(layoutconstrained)ax1 plt.subplot(2, 2, 1)
ax2 plt.subplot(2, 2, 3)
# third Axes that spans both rows in second column:
ax3 plt.subplot(2, 2, (2, 4))example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
plt.suptitle(Homogenous nrows, ncols)但以下情况会导致布局不佳
fig plt.figure(layoutconstrained)ax1 plt.subplot(2, 2, 1)
ax2 plt.subplot(2, 2, 3)
ax3 plt.subplot(1, 2, 2)example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
plt.suptitle(Mixed nrows, ncols)类似地subplot2gird的工作限制与nrows和ncols无法更改以使布局看起来不错相同的限制。
fig plt.figure(layoutconstrained)ax1 plt.subplot2grid((3, 3), (0, 0))
ax2 plt.subplot2grid((3, 3), (0, 1), colspan2)
ax3 plt.subplot2grid((3, 3), (1, 0), colspan2, rowspan2)
ax4 plt.subplot2grid((3, 3), (1, 2), rowspan2)example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
fig.suptitle(subplot2grid)其他注意事项
受约束的布局仅考虑刻度标签、轴标签、标题和图例。因此其他artist对象可能会被剪裁也可能重叠。它假定刻度标签、轴标签和标题所需的额外空间与轴的原始位置无关。这通常是正确的但在极少数情况下并非如此。后端处理呈现字体的方式存在细微差异因此结果不会在像素上完全相同。如果artist对象使用的坐标区坐标超出了坐标区边界则在添加到坐标区时将导致布局异常。通过使用add_artist()将artist对象直接添加到图中可以避免这种情况。有关示例请参阅ConnectionPatch。
12. 调试bug
受约束的布局可能会以某种意想不到的方式失败。由于它使用约束求解器因此求解器可以找到数学上正确的解决方案但这些解决方案根本不是用户想要的。通常的故障模式是所有尺寸都折叠到其最小允许值。如果发生这种情况则有两个原因之一
没有足够的空间来容纳你请求绘制的元素有一个错误-在这种情况下在以下位置打开一个issue:matplotlib/matplotlib#issues.
如果有错误请报告一个独立的示例不需要外部数据或依赖项numpy除外。
13. 关于算法的注意事项
约束的算法相对简单但由于我们可以布置图形的复杂方式因此具有一定的复杂性。
Matplotlib中的布局是通过GridSpec类使用gridspec执行的。网格规范是将图形逻辑划分为行和列这些行和列中轴的相对宽度由width_ratios和height_ratios设置。
在受约束的布局中每个gridspec都会获得一个与之关联的layoutgrid。layoutgrid每列都有一系列左右变量每行都有bottom和top变量此外它还有左、右、下和上各边的边距。在每一行中下边距和上边距被加宽直到容纳该行中的所有修饰器。同样对于列和左边距/右边距。
简单例证一个Axes
对于单个Axes布局是直接的。对于由一列和一行组成的图窗有一个父layoutgird对于包含轴的gridspec有一个子layoutgrid同样由一行和一列组成。Axes的每一侧都有空间用于“装饰”。在代码中这是通过do_constrained_layout()中的条目完成的例如
gridspec._layoutgrid[0, 0].edit_margin_min(left,-bbox.x0 pos.x0 w_pad)其中bbox是Axes的紧密边界框并定位其位置。请注意四个边距如何包含Axes装饰。
from matplotlib._layoutgrid import plot_childrenfig, ax plt.subplots(layoutconstrained)
example_plot(ax, fontsize24)
plot_children(fig)简单例证两个Axes
当有多个Axes时它们的布局以简单的方式绑定。在此示例中左Axes的修饰比右Axes大得多但它们共享一个底部边距该边距足够大以容纳较大的xlabel。与共享的上边距相同。左边距和右边距不共享因此允许不同。
fig, ax plt.subplots(1, 2, layoutconstrained)
example_plot(ax[0], fontsize32)
example_plot(ax[1], fontsize8)
plot_children(fig)两个Axes和颜色条
颜色条只是扩展父layoutgrid单元格边距的另一个项目
fig, ax plt.subplots(1, 2, layoutconstrained)
im ax[0].pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, axax[0], shrink0.6)
im ax[1].pcolormesh(arr, **pc_kwargs)
plot_children(fig)与GridSpec关联的颜色条
如果颜色条属于网格的多个单元格则它为每个单元格创建更大的边距
fig, axs plt.subplots(2, 2, layoutconstrained)
for ax in axs.flat:im ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, axaxs, shrink0.6)
plot_children(fig)尺寸不均匀的Axes
有两种方法可以使Axes在GridSpec布局中具有不均匀的大小一种是指定它们跨GridSpecs行或列另一种是指定宽度和高度比率。
这里使用第一种方法。请注意中间的上边距和下边距不受左侧列的影响。这是算法有意识的决定并导致两个右手轴有相同的高度但不是左手轴高度的1/2。这与gridspec在没有受约束布局的情况下的工作方式是一致的。
fig plt.figure(layoutconstrained)
gs gridspec.GridSpec(2, 2, figurefig)
ax fig.add_subplot(gs[:, 0])
im ax.pcolormesh(arr, **pc_kwargs)
ax fig.add_subplot(gs[0, 1])
im ax.pcolormesh(arr, **pc_kwargs)
ax fig.add_subplot(gs[1, 1])
im ax.pcolormesh(arr, **pc_kwargs)
plot_children(fig)需要调整的一个情况是如果边距没有任何artist对象限制其宽度。在下面的例子中第0列的右边距和第3列的左边距没有边距artist对象来设置其宽度因此我们取有artist的边距宽度的最大宽度。这使得所有Axes都具有相同的大小
fig plt.figure(layoutconstrained)
gs fig.add_gridspec(2, 4)
ax00 fig.add_subplot(gs[0, 0:2])
ax01 fig.add_subplot(gs[0, 2:])
ax10 fig.add_subplot(gs[1, 1:3])
example_plot(ax10, fontsize14)
plot_children(fig)
plt.show()