自定义xarray分面绘图colorbar指定位置的实现方法
xarray结合cartopy自定义分面图colorbar位置
需求说明
使用xarray结合cartopy绘制地理数据分面图时,需要将colorbar水平放置在子图网格的第5行,从第2列开始排布,参考效果如下:
初始可复现代码如下:
import cartopy.crs as ccrs import numpy as np import xarray as xr # 生成随机测试数据 annual=xr.DataArray(np.random.randint(1,100,(41,186,469)), dims=("year","y","x"), coords={"year":np.arange(1981,2022), "y":np.linspace(29,38,186), "x":np.linspace(-10,10,469)}) # 初始绘图代码 proj=ccrs.PlateCarree() fig=annual.plot(col="year",col_wrap=10, cmap="Spectral", vmin=1, vmax=105, subplot_kws={"projection":proj, "aspect":2.5}) # 设置标题样式 years=[f"Year = {i}" for i in range(1981,2022)] for ax, year in zip(fig.axes.flatten(), years): ax.set_title(year,fontsize=15) ax.set_extent([-10, 10, 29, 38]) ax.coastlines(linewidth=0.5) fig.cbar.ax.tick_params(labelsize=30) fig.cbar.set_label(label='Label', size=30, weight='bold')
实现方案
xarray分面绘图默认生成的colorbar位置固定,无法直接通过参数指定到目标网格位置,需要先关闭默认colorbar,再基于子图网格坐标手动创建cbar轴实现自定义布局,修改后的完整代码如下:
import cartopy.crs as ccrs import numpy as np import xarray as xr import matplotlib.pyplot as plt # 生成测试数据 annual=xr.DataArray(np.random.randint(1,100,(41,186,469)), dims=("year","y","x"), coords={"year":np.arange(1981,2022), "y":np.linspace(29,38,186), "x":np.linspace(-10,10,469)}) proj=ccrs.PlateCarree() # 关键参数:add_colorbar=False 关闭默认生成的colorbar g = annual.plot(col="year",col_wrap=10, cmap="Spectral", vmin=1, vmax=105, subplot_kws={"projection":proj, "aspect":2.5}, add_colorbar=False) # 原有子图样式设置 years=[f"Year = {i}" for i in range(1981,2022)] for ax, year in zip(g.axes.flatten(), years): ax.set_title(year,fontsize=15) ax.set_extent([-10, 10, 29, 38]) ax.coastlines(linewidth=0.5) # 调整子图间距,为colorbar预留合适显示空间 plt.subplots_adjust(bottom=0.12, hspace=0.35, wspace=0.05) # 基于已有子图的位置,计算colorbar放置区域的边界坐标 # 子图按行优先从上到下、从左到右排列:第1行索引0-9,第2行10-19,第3行20-29,第4行30-39,第5行(最下方)索引40 x_left = g.axes[31].get_position().x0 # 取第4行第2列的左边界,作为cbar的左起点(和第2列对齐) x_right = g.axes[39].get_position().x1 # 取第4行第10列的右边界,作为cbar的右终点(和第10列对齐) y_bottom = g.axes[40].get_position().y0 # 取第5行的下边界,作为cbar的下边界 y_top = g.axes[40].get_position().y1 # 取第5行的上边界,作为cbar高度参考 # 创建colorbar专属轴,高度设为单张子图高度的70%,避免和子图标题重叠 cbar_ax = g.fig.add_axes([x_left, y_bottom, x_right - x_left, (y_top - y_bottom)*0.7]) # 取第一个子图的绘图映射对象,生成水平colorbar mappable = g.axes[0].collections[0] cbar = g.fig.colorbar(mappable, cax=cbar_ax, orientation='horizontal') # 设置colorbar样式 cbar.ax.tick_params(labelsize=12) cbar.set_label(label='Label', size=15, weight='bold') plt.show()
关键说明
- 必须在调用
plot()时传入add_colorbar=False,否则默认colorbar会占用布局空间,导致自定义位置对齐偏差 - 直接通过已有子图的
get_position()方法获取坐标,不需要手动估算数值,可以保证colorbar和子图网格完美对齐 - 可以根据自己的显示需求,调整
subplots_adjust的间距参数、cbar轴的高度比例、字体大小等样式
内容的提问来源于stack exchange,提问作者Tuyen
相关产品推荐
相关产品推荐

