Matplotlib is hiring a Research Software Engineering Fellow! See discourse for details. Apply by January 3, 2020
如何使用受约束的布局使图形中的绘图清晰匹配。
constrained_layout 自动调整子批次和装饰,如图例和颜色栏,以便它们适合图形窗口,同时尽可能保留用户请求的逻辑布局。
constrained_layout 类似于 tight_layout ,但使用约束解算器来确定允许它们匹配的轴的大小。
constrained_layout 需要在将任何轴添加到图形之前激活。有两种方法可以做到这一点
使用各自的参数 subplots()
或 figure()
,例如:
plt.subplots(constrained_layout=True)
通过激活它 rcParams ,比如:
plt.rcParams['figure.constrained_layout.use'] = True
以下各节将详细介绍这些内容。
警告
当前受约束的布局为 实验的 . 行为和API可能会发生变化,或者整个功能可能会在没有折旧期的情况下被删除。如果你 要求 您的绘图是绝对可复制的,在运行受约束的布局和使用后获取轴位置 ax.set_position()
在您的代码中 constrained_layout=False
.
在Matplotlib中,轴(包括子图)的位置以标准化图形坐标指定。轴标签或标题(有时甚至勾选标签)可能会超出图形区域,因此会被剪切。
# sphinx_gallery_thumbnail_number = 18
#import matplotlib
#matplotlib.use('Qt5Agg')
import warnings
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as mcolors
import matplotlib.gridspec as gridspec
import matplotlib._layoutbox as layoutbox
plt.rcParams['savefig.facecolor'] = "0.8"
plt.rcParams['figure.figsize'] = 4.5, 4.
def example_plot(ax, fontsize=12, nodec=False):
ax.plot([1, 2])
ax.locator_params(nbins=3)
if not nodec:
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)
ax.set_title('Title', fontsize=fontsize)
else:
ax.set_xticklabels('')
ax.set_yticklabels('')
fig, ax = plt.subplots(constrained_layout=False)
example_plot(ax, fontsize=24)
为了防止这种情况发生,需要调整轴的位置。对于子批次,这可以通过调整子批次参数来完成。 (移动轴的边缘,为刻度标签留出空间 )但是,使用 constrained_layout=True
Kwarg将自动进行调整。
fig, ax = plt.subplots(constrained_layout=True)
example_plot(ax, fontsize=24)
当有多个子批次时,通常会看到不同轴的标签相互重叠。
fig, axs = plt.subplots(2, 2, constrained_layout=False)
for ax in axs.flatten():
example_plot(ax)
指定 constrained_layout=True
在召唤 plt.subplots
使布局受到适当的约束。
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flatten():
example_plot(ax)
如果用 colorbar()
命令,你需要为它腾出空间。 constrained_layout
自动执行此操作。请注意,如果您指定 use_gridspec=True
它将被忽略,因为此选项用于通过 tight_layout
.
注解
对于 pcolormesh
关键字参数 (pc_kwargs
)我们用字典。下面我们将为多个轴指定一个颜色条,每个轴包含 ScalarMappable
;指定norm和colormap可确保颜色栏对于所有轴都是精确的。
arr = np.arange(100).reshape((10, 10))
norm = mcolors.Normalize(vmin=0., vmax=100.)
# see note above: this makes all pcolormesh calls consistent:
pc_kwargs = {'rasterized': True, 'cmap': 'viridis', 'norm': norm}
fig, ax = plt.subplots(figsize=(4, 4), constrained_layout=True)
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=ax, shrink=0.6)
如果将轴(或其他可ITerable容器)列表指定给 ax
的参数 colorbar
,受约束的布局将占用指定轴的空间。
fig, axs = plt.subplots(2, 2, figsize=(4, 4), constrained_layout=True)
for ax in axs.flatten():
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs, shrink=0.6)
如果从轴网格内指定轴列表,颜色栏将适当地窃取空间并留有间隙,但所有子图的大小仍然相同。
fig, axs = plt.subplots(3, 3, figsize=(4, 4), constrained_layout=True)
for ax in axs.flatten():
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs[1:, ][:, 1], shrink=0.8)
fig.colorbar(im, ax=axs[:, -1], shrink=0.6)
请注意,将单个轴指定为父轴时有一点微妙。在下面的内容中,颜色条可能需要并期望对齐,但它们不是这样的,因为与底轴配对的颜色条与轴的子产品规格绑定,因此在添加网格规格级别的颜色条时会收缩。
fig, axs = plt.subplots(3, 1, figsize=(4, 4), constrained_layout=True)
for ax in axs[:2]:
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs[:2], shrink=0.6)
im = axs[2].pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs[2], shrink=0.6)
使单个轴的行为类似于轴列表的API将其指定为列表(或其他可ITerable容器),如下所示:
fig, axs = plt.subplots(3, 1, figsize=(4, 4), constrained_layout=True)
for ax in axs[:2]:
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs[:2], shrink=0.6)
im = axs[2].pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=[axs[2]], shrink=0.6)
constrained_layout
也可以为 suptitle
.
fig, axs = plt.subplots(2, 2, figsize=(4, 4), constrained_layout=True)
for ax in axs.flatten():
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs, shrink=0.6)
fig.suptitle('Big Suptitle')
图例可以放置在其父轴之外。受约束的布局设计用于处理 Axes.legend()
. 但是,受约束的布局确实 not 处理通过创建的图例 Figure.legend()
(然而)
fig, ax = plt.subplots(constrained_layout=True)
ax.plot(np.arange(10), label='This is a plot')
ax.legend(loc='center left', bbox_to_anchor=(0.8, 0.5))
但是,这将从子地块布局中窃取空间:
fig, axs = plt.subplots(1, 2, figsize=(4, 2), constrained_layout=True)
axs[0].plot(np.arange(10))
axs[1].plot(np.arange(10), label='This is a plot')
axs[1].legend(loc='center left', bbox_to_anchor=(0.8, 0.5))
为了让传奇人物或其他艺术家 not 从子地块布局中窃取空间,我们可以 leg.set_in_layout(False)
. 当然,这可能意味着这个传说最终会出现,但如果随后用 fig.savefig('outname.png', bbox_inches='tight')
. 但是,请注意,传说 get_in_layout
必须再次切换状态才能使保存的文件正常工作,如果希望在打印前通过受约束的布局调整轴的大小,则必须手动触发绘图。
fig, axs = plt.subplots(1, 2, figsize=(4, 2), constrained_layout=True)
axs[0].plot(np.arange(10))
axs[1].plot(np.arange(10), label='This is a plot')
leg = axs[1].legend(loc='center 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_inches='tight' calcs.
leg.set_in_layout(True)
# we don't want the layout to change at this point.
fig.set_constrained_layout(False)
fig.savefig('CL01.png', bbox_inches='tight', dpi=100)
保存的文件如下:
解决这种尴尬的更好方法是简单地使用 Figure.legend
:
fig, axs = plt.subplots(1, 2, figsize=(4, 2), constrained_layout=True)
axs[0].plot(np.arange(10))
lines = axs[1].plot(np.arange(10), label='This is a plot')
labels = [l.get_label() for l in lines]
leg = fig.legend(lines, labels, loc='center left',
bbox_to_anchor=(0.8, 0.5), bbox_transform=axs[1].transAxes)
fig.savefig('CL02.png', bbox_inches='tight', dpi=100)
保存的文件如下:
对于受约束的布局,我们在每个轴的边缘实现了填充。此填充设置距绘图边缘的距离,以及相邻绘图之间的最小距离。它由关键字参数以英寸为单位指定 w_pad
和 h_pad
对函数 set_constrained_layout_pads
:
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flatten():
example_plot(ax, nodec=True)
ax.set_xticklabels('')
ax.set_yticklabels('')
fig.set_constrained_layout_pads(w_pad=4./72., h_pad=4./72.,
hspace=0., wspace=0.)
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flatten():
example_plot(ax, nodec=True)
ax.set_xticklabels('')
ax.set_yticklabels('')
fig.set_constrained_layout_pads(w_pad=2./72., h_pad=2./72.,
hspace=0., wspace=0.)
子批次之间的间距由 wspace
和 hspace
. 指定为整个子批次组大小的一部分。如果图形的大小发生了变化,则这些空间将按比例变化。请注意,在吹制过程中,边缘的空间与上面的空间没有变化,但是子批次之间的空间会变化。
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flatten():
example_plot(ax, nodec=True)
ax.set_xticklabels('')
ax.set_yticklabels('')
fig.set_constrained_layout_pads(w_pad=2./72., h_pad=2./72.,
hspace=0.2, wspace=0.2)
将放置色带 wspace
和 hsapce
除了其他子批次。颜色条和它所连接的轴之间的填充永远不会小于 w_pad
(对于垂直颜色条)或 h_pad
(对于水平颜色条)。注意使用 pad
克瓦格在这里 colorbar
打电话。它默认为它所连接的轴的大小的0.02。
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flatten():
pc = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(pc, ax=ax, shrink=0.6, pad=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
fig.set_constrained_layout_pads(w_pad=2./72., h_pad=2./72.,
hspace=0.2, wspace=0.2)
在上面的示例中,颜色条与绘图之间的距离永远不会超过2个点,但是如果我们希望它离得远一点,我们可以指定它的值 pad
非零。
fig, axs = plt.subplots(2, 2, constrained_layout=True)
for ax in axs.flatten():
pc = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=ax, shrink=0.6, pad=0.05)
ax.set_xticklabels('')
ax.set_yticklabels('')
fig.set_constrained_layout_pads(w_pad=2./72., h_pad=2./72.,
hspace=0.2, wspace=0.2)
有五个 rcParams 可以在脚本或 matplotlibrc
文件。它们都有前缀 figure.constrained_layout
:
use
:是否使用受约束的布局。默认值为假w_pad
, h_pad
:在轴对象周围填充。wspace
, hspace
:子批次组之间的空间。plt.rcParams['figure.constrained_layout.use'] = True
fig, axs = plt.subplots(2, 2, figsize=(3, 3))
for ax in axs.flatten():
example_plot(ax)
约束布局用于 subplots()
或 GridSpec()
和 add_subplot()
.
注意以下内容 constrained_layout=True
fig = plt.figure()
gs1 = gridspec.GridSpec(2, 1, figure=fig)
ax1 = fig.add_subplot(gs1[0])
ax2 = fig.add_subplot(gs1[1])
example_plot(ax1)
example_plot(ax2)
更复杂的网格规格布局是可能的。注意这里我们使用方便函数 add_gridspec
和 subgridspec
fig = plt.figure()
gs0 = fig.