You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Matplotlib中单独控制子图尺寸,并解决GridSpec布局下的行间距过大问题?

如何在Matplotlib中单独控制子图尺寸,并解决GridSpec布局下的行间距过大问题?

我完全懂你的困扰——把带地理投影的imshow子图和时序线图放在一起时,要么地图子图因为投影比例限制显得过小、布局不协调;要么用GridSpec调整布局后,两行子图之间的空白间距大得没法看。咱们来一步步解决这两个问题:

首先,理解最初的子图大小问题

你用普通plt.subplot()时,带ccrs.PlateCarree()投影的子图默认会强制等比例缩放aspect='equal'),目的是保证地图不会被拉伸变形,但这就导致它在和旁边没有比例限制的时序图对比时,看起来尺寸偏小。这是地理投影子图的默认特性,不是bug。

解决GridSpec行间距过大的核心问题

你用GridSpec的思路是对的,但问题出在两个地方:

  1. 你同时用了plt.tight_layout()plt.subplots_adjust(),这两个函数会互相冲突——tight_layout()会自动覆盖手动设置的间距参数;
  2. 你的GridSpec行数设置(6行)和高度比例分配,导致中间出现了不必要的空白区域,再加上tight_layout的自动调整,就形成了巨大的行间距。

修正后的解决方案

下面是调整后的代码,既保证地图子图的合适尺寸,又能消除多余的行间距:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import cartopy.crs as ccrs
import pandas as pd

# 假设titles、eofs、pcs这些变量已经定义好

# 创建figure时启用constrained_layout,它比tight_layout更智能,能自动处理间距
fig = plt.figure(figsize=(15, 9), constrained_layout=True)

# 重新定义GridSpec:2行4列,宽度比例控制时序图的宽度,高度比例保持每行一致
gs = gridspec.GridSpec(2, 4, width_ratios=[1, 0.7, 1, 0.7], height_ratios=[1, 1])

# 地图子图:放在每行的第0、2列位置
map_subplots = [
    plt.subplot(gs[0, 0], projection=ccrs.PlateCarree()),
    plt.subplot(gs[0, 2], projection=ccrs.PlateCarree()),
    plt.subplot(gs[1, 0], projection=ccrs.PlateCarree()),
    plt.subplot(gs[1, 2], projection=ccrs.PlateCarree())
]

for i, ax in enumerate(map_subplots):
    ax.set_title(titles[i])
    ax.coastlines(linewidth=0.5)
    ax.imshow(eofs[i], extent=[0, 360, -90, 90], transform=ccrs.PlateCarree(), 
              cmap='RdBu_r', origin='lower', vmin=-0.01, vmax=0.01)

# 时序子图:放在每行的第1、3列位置,和对应地图子图同一行
ts_subplots = [
    plt.subplot(gs[0, 1]),
    plt.subplot(gs[0, 3]),
    plt.subplot(gs[1, 1]),
    plt.subplot(gs[1, 3])
]

for i, ax in enumerate(ts_subplots):
    ax.plot(pcs.time, pcs.sel(pc=i))
    ax.set_ylim(-100, 100)
    ax.set_yticks([])  # 直接去掉yticks,简化冗余判断
    
    ax.set_xticks(pd.date_range("2013-01-01", "2016-01-01", freq='6MS'))
    ax.set_xticklabels(["2013", "Jul", "2014", "Jul", "2015", "Jul", "2016"])

# 如果需要添加公共y轴标签,用fig.text更合适
# fig.text(0.04, 0.5, 'PC value (arb. units)', va='center', rotation='vertical', fontsize=12)

plt.show()

关键调整点说明

  • 启用constrained_layout=True:在创建figure时设置这个参数,它会自动计算子图之间的合理间距,不需要再用tight_layout()subplots_adjust(),避免了参数冲突;
  • 简化GridSpec结构:把原来的6行改成2行,让每个地图子图和对应的时序图在同一行,从根源上消除了中间的空白行;
  • 宽度比例精准控制width_ratios=[1, 0.7, 1, 0.7]让地图子图宽度为1,时序图为0.7,保持你想要的比例关系;
  • 去掉冗余代码:删掉了不必要的if True判断,让代码更简洁。

如果还是需要更精细的间距调整,可以用gs.update(wspace=0.1, hspace=0)来手动微调,constrained_layout会尊重这些设置。

备注:内容来源于stack exchange,提问作者J.Barker

火山引擎 最新活动