matplotlib中GridSpec搭配constrained_layout警告的解决方法
问题背景
在PyCharm开发环境下使用Python的matplotlib库绘制自定义网格布局的可视化图表,目标为3行3列网格的自定义子图排布,初始实现代码如下:
import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec def format_axes(fig): for i, ax in enumerate(fig.axes): ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") ax.tick_params(labelbottom=False, labelleft=False) fig = plt.figure(constrained_layout=True) gs = GridSpec(3, 3, figure=fig) ax1 = fig.add_subplot(gs[:2, 0]) ax2 = fig.add_subplot(gs[:2, 1:]) ax3 = fig.add_subplot(gs[-1, 1:]) fig.suptitle("GridSpec") format_axes(fig) plt.show()
运行代码时抛出警告:
UserWarning: constrained_layout not applied. At least one axes collapsed to zero width or height.
无法正常得到预期布局效果。
问题原因
警告触发的核心原因是:定义的3行3列GridSpec网格中,第三行第0列(索引为(2,0))的网格单元没有分配任何子图,开启constrained_layout自动布局时,算法会将无内容关联的网格单元宽高计算为0,导致布局计算失败抛出警告。
解决方法
两种方案均可消除警告,得到预期布局:
方案1:替换自动布局方案
移除figure创建时的constrained_layout=True参数,在所有子图创建完成后调用tight_layout()完成布局调整,通过rect参数为顶部总标题预留显示空间,修改后可直接运行的代码如下:
import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec def format_axes(fig): for i, ax in enumerate(fig.axes): ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") ax.tick_params(labelbottom=False, labelleft=False) # 移除constrained_layout参数,可按需设置画布尺寸 fig = plt.figure(figsize=(8, 6)) gs = GridSpec(3, 3, figure=fig) ax1 = fig.add_subplot(gs[:2, 0]) ax2 = fig.add_subplot(gs[:2, 1:]) ax3 = fig.add_subplot(gs[-1, 1:]) fig.suptitle("GridSpec") format_axes(fig) # rect参数格式为[左边界, 下边界, 右边界, 上边界],留出顶部4%空间放标题 plt.tight_layout(rect=[0, 0, 1, 0.96]) plt.show()
方案2:保留constrained_layout,添加占位轴
如果需要使用constrained_layout的布局特性,可以给未分配的空网格单元创建一个隐藏的占位轴,让布局算法可以正常计算所有网格单元的尺寸,修改后代码如下:
import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec def format_axes(fig): for i, ax in enumerate(fig.axes): # 跳过隐藏的占位轴,不做文本标注 if not ax.get_visible(): continue ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") ax.tick_params(labelbottom=False, labelleft=False) # 保留constrained_layout配置 fig = plt.figure(constrained_layout=True, figsize=(8, 6)) gs = GridSpec(3, 3, figure=fig) ax1 = fig.add_subplot(gs[:2, 0]) ax2 = fig.add_subplot(gs[:2, 1:]) ax3 = fig.add_subplot(gs[-1, 1:]) # 创建空位置的占位轴并设置为不可见 ax_placeholder = fig.add_subplot(gs[-1, 0]) ax_placeholder.set_visible(False) fig.suptitle("GridSpec") format_axes(fig) plt.show()
内容的提问来源于stack exchange,提问作者ab3001
相关产品推荐
相关产品推荐

