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

设置统一y轴范围后,Matplotlib子图图例无法最优放置

问题描述

我用Matplotlib绘制了包含两个子图的图表,想要让它们使用相同的y轴刻度范围,相关代码如下:

fig, ax = plt.subplots(1, 2,figsize=(10,6))

ax[0].set_title('Over Global region, {} points'.format(len(df)))
ax[0].plot(df.groupby('type')['thickness'].mean(),label='Cloud mean thickness',color='red')
ax[0].set_xlabel('Cloud Type',fontsize=13)
ax[0].set_ylabel('(in km)',fontsize=15)
#Put xticks with labels at the bottom of the plot
ax[0].set_xticks(cloudlabel,cloudtype_dict.values(),rotation=50)

lon_left, lon_right, lat_bot, lat_top = 60, 100, 0, 40
dfcopy = df.copy()
dfcopy_aoi = dfcopy[(dfcopy['lon']>=lon_left) & (dfcopy['lon']<=lon_right) & (dfcopy['lat']>=lat_bot) & (dfcopy['lat']<=lat_top)]
ax[1].set_title('Over Indian subcontinent region, {} points'.format(len(dfcopy_aoi)))
ax[1].plot(dfcopy_aoi.groupby('type')['thickness'].mean(),label='Cloud mean thickness',color='red')
ax[1].set_xlabel('Cloud Type',fontsize=13)
ax[1].set_ylabel('(in km)',fontsize=15)
ax[1].set_xticks(cloudlabel,cloudtype_dict.values(),rotation=50);


#Shared y-axis
y_lim=[0,0]
y_lim = [min(ax[0].get_ylim()[0], ax[1].get_ylim()[0]), max(ax[0].get_ylim()[1], ax[1].get_ylim()[1])]
for i in range(2):
    ax[i].set_ylim(y_lim)
ax[0].legend(loc='best');
ax[1].legend(loc='best');

我已经把图例设置代码放在所有操作之后,但第一个子图(ax[0])的图例还是错位,没有找到最优放置位置,图例跑到了子图外部区域。

解决方案

核心原因

问题出在:你先绘制图表,Matplotlib自动算出初始y轴范围并记录了绘图区域;之后手动修改了y轴范围,但调用legend(loc='best')时,它还是基于修改y轴范围之前的区域计算最优位置,导致图例错位。

修复方案

有两种简单解决办法:

  1. 先确定统一y轴范围,再绘制图表
    先提前计算两组数据的均值,得出统一的y轴上下限,再依次绘制子图:
# 提前计算两组数据的均值,确定统一y轴范围
global_mean = df.groupby('type')['thickness'].mean()
aoi_mean = dfcopy_aoi.groupby('type')['thickness'].mean()
y_lim = [min(global_mean.min(), aoi_mean.min()), max(global_mean.max(), aoi_mean.max())]

fig, ax = plt.subplots(1, 2,figsize=(10,6))

# 绘制第一个子图
ax[0].set_title(f'Over Global region, {len(df)} points')
ax[0].plot(global_mean, label='Cloud mean thickness', color='red')
ax[0].set_xlabel('Cloud Type', fontsize=13)
ax[0].set_ylabel('(in km)', fontsize=15)
ax[0].set_xticks(cloudlabel, cloudtype_dict.values(), rotation=50)
ax[0].set_ylim(y_lim)
ax[0].legend(loc='best')

# 绘制第二个子图
ax[1].set_title(f'Over Indian subcontinent region, {len(dfcopy_aoi)} points')
ax[1].plot(aoi_mean, label='Cloud mean thickness', color='red')
ax[1].set_xlabel('Cloud Type', fontsize=13)
ax[1].set_ylabel('(in km)', fontsize=15)
ax[1].set_xticks(cloudlabel, cloudtype_dict.values(), rotation=50)
ax[1].set_ylim(y_lim)
ax[1].legend(loc='best')
  1. 修改y轴范围后,强制更新图例位置计算
    如果不想调整代码顺序,可以在设置完y轴范围后,给legend加上bbox_transform参数,让它基于当前子图的轴区域计算位置:
# 设置完y轴范围后
for i in range(2):
    ax[i].set_ylim(y_lim)
# 重新基于当前轴区域计算图例位置
ax[0].legend(loc='best', bbox_transform=ax[0].transAxes)
ax[1].legend(loc='best', bbox_transform=ax[1].transAxes)

或者直接手动指定一个可靠的位置(比如upper right),避免自动计算的误差:

ax[0].legend(loc='upper right')
ax[1].legend(loc='upper right')

额外优化建议

可以直接用Matplotlib自带的共享轴功能,不用手动计算y范围,代码更简洁:

# 创建子图时指定sharey=True,自动同步两个子图的y轴范围
fig, ax = plt.subplots(1, 2, figsize=(10,6), sharey=True)
# 后续绘制代码无需再手动设置ylim

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:25:19