Cartopy子图垂直间距过大:tight_layout无效及色条适配问题
Cartopy子图垂直空白与色条尺寸优化方案
以下代码用于绘制3列2行共6幅Cartopy地图,每列子图对应一个色条,但即使使用
fig.tight_layout(),子图间仍存在大量垂直空白,同时色条尺寸需要调整:
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from matplotlib import colorbar, colors import cartopy.crs as ccrs import cartopy.feature as cf X = [9.9576, 11.0621, 12.1844, 9.1307, 8.409, 11.0108, 11.0549, 9.8648, 12.5024, 7.8343, 10.9308, 11.8134, 10.0792, 8.5584, 10.2759, 12.1019, 9.2235, 10.3348, 7.828, 10.9206] Y = [49.7704, 47.483, 49.6662, 47.6952, 48.4538, 47.8009, 49.503, 48.6656, 48.279, 48.0232, 49.0115, 48.3477, 50.224, 49.5063, 47.3984, 49.0425, 48.6883, 47.7233, 48.3647, 49.8743] Z = [2.3337733, -0.52256856, 0.97157093, -0.50601561, 0.21645241, 0.4011776, -1.69798815, 1.3751253, -1.79249769, -0.09767434, 0.96454293, 0.12713469, -0.03112513, 1.36738838, -0.37373591, 0.40124358, 0.77141455, 0.62646425, 0.52960763, -1.16011285] fig,ax = plt.subplots(ncols=3,nrows=2,figsize=(10,7), subplot_kw={'projection': ccrs.PlateCarree()}) fig.tight_layout() vmin=min(Z) vmax=max(Z) for col in range(3): for row in range(2): ax[row,col].set_extent([7.5377, 14.0065, 47.221, 50.7131]) ax[row,col].add_feature(cf.BORDERS) ax[row,col].add_feature(cf.STATES,linewidth=0.5) ax[row,col].coastlines() ax[row,col].set_aspect('equal') #fig.tight_layout() ax[row,col].scatter(X, Y, c=Z, cmap="YlOrRd", edgecolors='black', transform=ccrs.PlateCarree(),vmin=vmin,vmax=vmax) norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap="YlOrRd"), ax=ax[:, col], shrink=0.5) plt.savefig('stackoverflow.png', format='png',dpi=600)
解决方案
- 移除强制等宽高比设置:删除
ax[row,col].set_aspect('equal')。Cartopy在设置set_extent后会自动根据地图范围适配子图比例,强制锁定等比例会导致垂直方向出现多余空白。 - 改用动态布局机制:在创建子图时设置
constrained_layout=True,替代tight_layout()。该机制能动态识别色条等额外元素的空间占用,自动调整子图位置与间距,布局效果更稳定。 - 优化色条尺寸与间距:调整
fig.colorbar的shrink参数(例如改为0.8)让色条高度匹配子图,同时用pad参数(例如设为0.05)控制色条与子图的间距,避免留白过多。
修改后的完整代码
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl import cartopy.crs as ccrs import cartopy.feature as cf X = [9.9576, 11.0621, 12.1844, 9.1307, 8.409, 11.0108, 11.0549, 9.8648, 12.5024, 7.8343, 10.9308, 11.8134, 10.0792, 8.5584, 10.2759, 12.1019, 9.2235, 10.3348, 7.828, 10.9206] Y = [49.7704, 47.483, 49.6662, 47.6952, 48.4538, 47.8009, 49.503, 48.6656, 48.279, 48.0232, 49.0115, 48.3477, 50.224, 49.5063, 47.3984, 49.0425, 48.6883, 47.7233, 48.3647, 49.8743] Z = [2.3337733, -0.52256856, 0.97157093, -0.50601561, 0.21645241, 0.4011776, -1.69798815, 1.3751253, -1.79249769, -0.09767434, 0.96454293, 0.12713469, -0.03112513, 1.36738838, -0.37373591, 0.40124358, 0.77141455, 0.62646425, 0.52960763, -1.16011285] # 启用constrained_layout自动处理布局 fig, ax = plt.subplots(ncols=3, nrows=2, figsize=(10,7), subplot_kw={'projection': ccrs.PlateCarree()}, constrained_layout=True) vmin = min(Z) vmax = max(Z) for col in range(3): for row in range(2): ax[row,col].set_extent([7.5377, 14.0065, 47.221, 50.7131]) ax[row,col].add_feature(cf.BORDERS) ax[row,col].add_feature(cf.STATES, linewidth=0.5) ax[row,col].coastlines() ax[row,col].scatter(X, Y, c=Z, cmap="YlOrRd", edgecolors='black', transform=ccrs.PlateCarree(), vmin=vmin, vmax=vmax) norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) # 调整色条尺寸与间距 fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap="YlOrRd"), ax=ax[:, col], shrink=0.8, pad=0.05) plt.savefig('stackoverflow.png', format='png', dpi=600) plt.show()
内容的提问来源于stack exchange,提问作者AlexLee
相关产品推荐
相关产品推荐

