如何调整添加Basemap的xarray分面图列间距
xarray分面图叠加Basemap底图列间距过大解决方案
问题根源
列间距无法通过subplots_adjust、tight_layout调整的核心原因有两个:
- Basemap初始化绑定子图时,会强制将坐标轴设置为固定等宽高比(
aspect='equal'),和xarray FacetGrid默认的自适应布局逻辑冲突,matplotlib会自动为等比轴补充留白,覆盖手动设置的wspace参数 - 手动添加的独立colorbar轴会干扰tight_layout的自动排版计算,导致系统为了给colorbar腾位置主动拉开子图列间距
修复步骤
- 提前计算研究区的经纬度宽高比,在创建xarray分面图时就通过
aspect、subplot_kws参数锁定子图宽高比,避免Basemap初始化时修改轴属性撑乱布局 - 在创建分面网格的阶段就通过
gridspec_kw传入间距参数,这个参数的优先级高于事后调用subplots_adjust,不会被固定aspect的轴覆盖 - 调用
tight_layout时传入rect参数,提前给右侧colorbar预留固定位置,告诉排版系统不要调整该区域内的子图布局 - 清空子图默认的经纬度刻度,避免刻度标签占用额外空间产生不必要的留白
修正后代码
import pickle import numpy as np from matplotlib import pyplot as plt from matplotlib import colors from mpl_toolkits.basemap import Basemap import xarray as xr # 读取本地测试数据 with open('/data/direcotory/test_data.pkl', "rb") as f: ds_sub = pickle.load(f) plt.close("all") # 提前提取研究区边界,计算地图实际宽高比 lon_min, lon_max = ds_sub['lon'].min().item(), ds_sub['lon'].max().item() lat_min, lat_max = ds_sub['lat'].min().item(), ds_sub['lat'].max().item() map_aspect = (lon_max - lon_min) / (lat_max - lat_min) lon_0 = ds_sub['lon'].mean().item() lat_0 = ds_sub['lat'].mean().item() # 计算色标分级 levels = np.arange(0, ds_sub['sum'].quantile(0.99), (ds_sub['sum'].quantile(0.99) / 10)).tolist() norm = colors.BoundaryNorm(levels, len(levels)) # 创建分面图时直接锁定布局参数 p = ds_sub['sum'].loc[[0, 3, 6, 9], :, :].plot( add_colorbar=False, row='time', cmap='OrRd', col_wrap=2, norm=norm, aspect=map_aspect, figsize=(8, 10), subplot_kws={"aspect": map_aspect}, gridspec_kw={"hspace": 0.05, "wspace": 0.02} # 网格初始化时直接设间距 ) # 添加独立色标 mappable = p.axes.flat[0].collections[0] cax = p.fig.add_axes([0.88, 0.2, 0.03, 0.6]) cbar = plt.colorbar( mappable, ticks=levels, values=levels, cax=cax, orientation='vertical' ) cbar.ax.tick_params(labelsize=14) # 逐子图叠加Basemap底图 for ax in p.axes.flatten(): # 清空默认轴标签和刻度,避免额外留白 ax.set_xlabel('') ax.set_ylabel('') ax.set_xticks([]) ax.set_yticks([]) ax.margins(0, 0) m = Basemap( resolution='f', lat_ts=20, lat_0=lat_0, lon_0=lon_0, llcrnrlon=lon_min, llcrnrlat=lat_min, urcrnrlon=lon_max, urcrnrlat=lat_max, ax=ax, fix_aspect=True # 锁定宽高比不自动调整 ) m.drawmapboundary(linewidth=0.5) m.drawrivers(linewidth=0.3) m.drawcoastlines(linewidth=0.5) m.drawcountries(linewidth=0.5) m.drawstates(linewidth=0.3) point_lon, point_lat = m(51.534817, 25.286106) # 最后微调布局,rect参数指定子图排版区域为画布左0到右85%的位置,给色标留空间 plt.tight_layout(rect=[0, 0, 0.85, 1], pad=0.1) plt.show()
效果说明
调整后子图列间距可以稳定控制在wspace设定的数值,不会被Basemap或者colorbar挤开,行间距也可以通过hspace参数按需调整。如果需要更紧凑的效果,直接把gridspec_kw里的wspace设为0即可。
内容的提问来源于stack exchange,提问作者Seyed Omid Nabavi
相关产品推荐
相关产品推荐

