You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用constrained_layout后,如何禁用布局并调整Matplotlib子图轴位置

解决Matplotlib constrained_layout后统一子图间距的问题

问题背景

使用Matplotlib的constrained_layout生成包含主散点图、顶部直方图、左侧直方图的子图布局时,会出现水平间距大于垂直间距的情况——这是因为布局算法为顶部子图的刻度和轴标签预留了额外空间。直接手动调整主图轴位置会导致constrained_layout完全失效,无法达到预期效果。需要实现:先让constrained_layout完成初始布局,再禁用它,最后手动调整轴位置来统一水平和垂直间距。

解决方案

核心思路是:先触发constrained_layout完成布局计算,关闭自动布局功能后,以垂直间距为基准调整水平方向的子图位置,确保两类间距一致。

完整实现代码

import matplotlib.pyplot as plt
import numpy as np

N = 200
var_xx = 1**2  # var x = std x squared
var_yy = 1**2
cov_xy = 0.5
cov = np.array([[var_xx, cov_xy], [cov_xy, var_yy]])

rng = np.random.default_rng()
pairs = rng.multivariate_normal([0, 0], cov, size=N, check_valid="raise")

# 1. 用constrained_layout生成初始布局
mosaic = [[".", "top"], ["left", "main"]]
fig, axarr = plt.subplot_mosaic(
    mosaic, 
    constrained_layout=True, 
    width_ratios=[0.5, 1], 
    height_ratios=[0.5, 1]
)

# 绘制图形
axarr["main"].scatter(pairs[:, 0], pairs[:, 1], alpha=0.5)
axarr["top"].hist(pairs[:, 0], bins=20)
axarr["left"].hist(pairs[:, 1], bins=20, orientation="horizontal")

# 共享轴保证刻度对齐
axarr["left"].sharey(axarr["main"])
axarr["top"].sharex(axarr["main"])

# 隐藏冗余刻度标签
axarr["top"].tick_params(labelbottom=False)
axarr["main"].tick_params(labelleft=False)

# 设置轴标签
axarr["main"].set_xlabel("x")
axarr["left"].set_ylabel("y")
axarr["left"].set_xlabel("PDF")
axarr["top"].set_ylabel("PDF")

# 2. 触发布局计算后禁用constrained_layout
fig.set_constrained_layout(False)

# 3. 获取子图位置(转换为像素坐标方便计算)
trans = fig.dpi_scale_trans
pos_main = axarr["main"].get_position().transformed(trans)
pos_top = axarr["top"].get_position().transformed(trans)
pos_left = axarr["left"].get_position().transformed(trans)

# 计算垂直间距(顶部子图底部到主图顶部的距离)
vertical_space = pos_top.ymin - pos_main.ymax

# 4. 调整主图和顶部子图的水平位置,让水平间距等于垂直间距
new_main_x0 = pos_left.xmax + vertical_space
new_main_x1 = new_main_x0 + (pos_main.x1 - pos_main.x0)
pos_main.x0, pos_main.x1 = new_main_x0, new_main_x1

# 顶部子图与主图x范围保持同步(共享轴要求)
pos_top.x0, pos_top.x1 = new_main_x0, new_main_x1

# 5. 将像素坐标转换回Matplotlib归一化坐标并设置
axarr["main"].set_position(pos_main.transformed(trans.inverted()))
axarr["top"].set_position(pos_top.transformed(trans.inverted()))

plt.show()

关键步骤说明

  • 初始布局:先通过constrained_layout=True让Matplotlib自动处理轴标签、刻度的空间预留,避免手动计算复杂的空间需求。
  • 禁用自动布局:调用fig.set_constrained_layout(False)关闭自动布局,确保后续手动调整的位置不会被覆盖。
  • 间距对齐:以垂直间距为基准,调整主图和顶部子图的水平起始位置,保证水平、垂直间距完全一致;同时保持顶部子图与主图的x范围同步,避免共享轴错位。
  • 坐标转换:使用fig.dpi_scale_trans将归一化坐标转换为像素坐标,计算更直观,调整后再转换回归一化坐标应用到子图。

内容的提问来源于stack exchange,提问作者Liris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 06:21:00