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

Matplotlib共享y轴时设置单图等纵横比并保持轴尺寸对齐

Matplotlib双列子图等纵横比+Y轴对齐实现方案

问题背景

需要实现左右排布的双列子图:

  • 左侧子图展示二维剖面数据,要求坐标轴等纵横比(即X/Y方向单位公里的物理显示长度一致)
  • 右侧子图展示二维数据指定位置的垂直切片,两个子图共享Y轴(深度轴),要求深度轴完全对齐

初始实现的最小工作代码如下:

import matplotlib.pyplot as plt
import numpy as np

nz = 66
nx = 130
ny = 230
h  = 70
ensemble_size = 50

x = np.array([ix*h / 1000 for ix in range(nx)])
y = np.array([iy*h / 1000 for iy in range(ny)])
z = np.array([iz*h / 1000 for iz in range(nz)])

Y, Z = np.meshgrid(y, z, indexing='ij')

vp_min = 1400
vp_max = 3350
p_max = 1200

ix = 42
iy = 81

vp = (vp_max - vp_min)*np.random.rand(nz*nx*ny, ensemble_size) + vp_min
vp_mean = np.mean(vp, axis=1).reshape(nz*nx*ny, 1)

########################################################################

fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True)

ax1.pcolor(Y, Z, vp_mean.reshape(nz, nx, ny, order='F')[:,ix,:].T, cmap="jet", vmin=vp_min, vmax=vp_max)
ax1.plot(iy*h*np.ones(nz) / 1000, z, "k--")
ax1.set_ylabel(r'Depth ($km$)')
ax1.set_xlabel(r'Y ($km$)')
ax1.set_aspect('equal')

lines = []
for e in range(ensemble_size):
    lines.append( ax2.plot(vp[:,e].reshape(nz, nx, ny, order='F')[:,ix,iy], z, "b", alpha=0.25, label="models") ) 
lines.append( ax2.plot(vp_mean.reshape(nz, nx, ny, order='F')[:,ix,iy], z, "r", alpha=1.0, label="average model") )
plt.setp(lines[1:ensemble_size], label="_")
ax2.set_xlabel(r'$V_p$ ($m/s$)')
ax2.invert_yaxis()
ax2.legend()

########################################################################

plt.savefig("log_" + str(ix) + "_" + str(iy) + ".pdf", bbox_inches='tight')
plt.show(block=False)
plt.close("all")

现存问题

初始版本左侧子图纵横比显示不协调,尝试通过gridspec_kw手动指定子图宽度比例,同时保留左侧子图等纵横比设置,核心修改如下:

fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, gridspec_kw={'width_ratios':[5, 1]})
# 其余代码不变
ax1.set_aspect(1)

该修改会导致两个子图的深度(Y轴)物理尺寸不对齐,无法满足布局要求。

问题原因

set_aspect('equal')会强制轴的物理尺寸匹配数据坐标的比例,该逻辑会覆盖gridspec_kw预设的子图尺寸规则,自动调整左侧子图的高度,最终和右侧子图的高度产生偏差,即便设置了sharey=True也无法对齐。

解决方案

使用mpl_toolkits.axes_grid1提供的HBoxDivider工具手动控制两个子图的尺寸分配,强制两个子图高度一致,同时保留左侧子图的等纵横比设置,支持自定义两个子图的宽度比例。

修改后完整代码

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1.axes_divider import HBoxDivider
import mpl_toolkits.axes_grid1.axes_size as Size

nz = 66
nx = 130
ny = 230
h  = 70
ensemble_size = 50

x = np.array([ix*h / 1000 for ix in range(nx)])
y = np.array([iy*h / 1000 for iy in range(ny)])
z = np.array([iz*h / 1000 for iz in range(nz)])

Y, Z = np.meshgrid(y, z, indexing='ij')

vp_min = 1400
vp_max = 3350
p_max = 1200

ix = 42
iy = 81

vp = (vp_max - vp_min)*np.random.rand(nz*nx*ny, ensemble_size) + vp_min
vp_mean = np.mean(vp, axis=1).reshape(nz*nx*ny, 1)

########################################################################
# 初始化画布,不提前设置gridspec_kw
fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True)

# 左侧子图绘图
ax1.pcolor(Y, Z, vp_mean.reshape(nz, nx, ny, order='F')[:,ix,:].T, cmap="jet", vmin=vp_min, vmax=vp_max)
ax1.plot(iy*h*np.ones(nz) / 1000, z, "k--")
ax1.set_ylabel(r'Depth ($km$)')
ax1.set_xlabel(r'Y ($km$)')
ax1.set_aspect('equal') # 保留等纵横比设置
ax1.invert_yaxis() # 深度轴反转统一放到左侧设置,共享轴会自动同步

# 右侧子图绘图
lines = []
for e in range(ensemble_size):
    lines.append( ax2.plot(vp[:,e].reshape(nz, nx, ny, order='F')[:,ix,iy], z, "b", alpha=0.25, label="models") ) 
lines.append( ax2.plot(vp_mean.reshape(nz, nx, ny, order='F')[:,ix,iy], z, "r", alpha=1.0, label="average model") )
plt.setp(lines[1:ensemble_size], label="_")
ax2.set_xlabel(r'$V_p$ ($m/s$)')
ax2.legend()

# 手动设置子图尺寸分配,强制Y轴对齐
pad = 0.6 # 两个子图之间的间距,可根据需求调整
divider = HBoxDivider(
    fig, 111,
    horizontal=[Size.AxesX(ax1), Size.Fixed(pad), Size.AxesX(ax2)],
    vertical=[Size.AxesY(ax1), Size.Scaled(1), Size.AxesY(ax2)]
)
ax1.set_axes_locator(divider.new_locator(0))
ax2.set_axes_locator(divider.new_locator(2))

# 如需调整左右宽度比例,可手动修改右侧子图x轴范围实现,例:
# ax2.set_xlim(vp_min-100, vp_max+100)
########################################################################

plt.savefig("log_" + str(ix) + "_" + str(iy) + ".pdf", bbox_inches='tight')
plt.show(block=False)
plt.close("all")

效果说明

  • 左侧子图保留1:1等纵横比,X/Y方向单位公里的显示长度完全一致
  • 两个子图深度轴物理尺寸完全对齐,无高度偏差
  • 可通过调整右侧子图X轴范围、子图间距参数自定义布局比例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:57:20