matplotlib gridspec_kw报错AttributeError,求子图轴对齐解决方案
问题解决:AttributeError: GeoAxesSubplot.set() got an unexpected keyword argument 'gridspec_kw'
错误原因
gridspec_kw 不是 figure.add_subplot() 的合法参数,这个参数仅能用于 plt.subplots() 或 matplotlib.gridspec.GridSpec 的初始化环节。你直接将其传给 add_subplot(),会被当作轴对象的配置参数,而GeoAxesSubplot并不支持该参数,因此触发报错。
解决方案
针对你需要偏移子图轴以对齐直边的需求,提供两种可行实现方式:
方法1:使用 plt.subplots() 配合 gridspec_kw
通过 plt.subplots() 直接创建带GridSpec配置的子图网格,同时指定地理投影:
import matplotlib.pyplot as plt import numpy as np import cartopy.crs as ccrs import cartopy.feature as cf from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter # 创建3行3列子图网格,指定列宽度比例(示例:前两列宽度为2,第三列为1) f, axs = plt.subplots(3, 3, figsize=(12,9), dpi=300, tight_layout=False, subplot_kw={'projection': ccrs.PlateCarree()}, gridspec_kw={'width_ratios': [2,2,1]}) # 提取需要的5个子图 ax1, ax2, ax3, ax4, ax5 = axs[0,0], axs[0,1], axs[1,0], axs[1,1], axs[2,0] # 隐藏未使用的子图 for ax in axs[0,2], axs[1,2], axs[2,1], axs[2,2]: ax.set_visible(False) # 后续处理ax1的代码保持原有逻辑 inter = np.linspace(-5,5, num=11, endpoint=True) lat = f222['xlat'] lon = f222['xlon'] pr = ax1.contourf(lon, lat, f222.tmp.mean('time'), inter, transform=ccrs.PlateCarree(), cmap='RdGy_r', extend='both') ax1.coastlines(resolution='50m', color='black', lw=0.5) x_lons = np.arange(-20,20,10) y_lats = np.arange(5,25,5) ax1.tick_params(labelsize=7) lon_formatter = LongitudeFormatter(zero_direction_label=True, number_format='.0f') lat_formatter = LatitudeFormatter() ax1.xaxis.set_major_formatter(lon_formatter) ax1.yaxis.set_major_formatter(lat_formatter) ax1.set_xticks(x_lons, minor=False, crs=ccrs.PlateCarree()) ax1.set_yticks(y_lats, minor=False, crs=ccrs.PlateCarree()) ax1.text(-23., 5.5, r'(a)', fontsize=7, fontweight="bold") ax1.text(-15., 25, r'CRU - Grell', fontsize=10, fontweight="bold") ax1.add_feature(cf.BORDERS, lw=0.5) ax1.add_feature(cf.COASTLINE, lw=0.5) # 其他子图按相同逻辑处理即可
方法2:手动创建GridSpec添加子图
如果需要更灵活的子图位置控制,可手动初始化GridSpec后逐个添加子图:
import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec import numpy as np import cartopy.crs as ccrs import cartopy.feature as cf from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter f = plt.figure(figsize=(12,9), dpi=300, tight_layout=False) # 创建3行3列的GridSpec,指定列宽度比例 gs = GridSpec(3, 3, width_ratios=[2,2,1]) # 逐个添加子图,指定GridSpec位置和地理投影 ax1 = f.add_subplot(gs[0,0], projection=ccrs.PlateCarree()) ax2 = f.add_subplot(gs[0,1], projection=ccrs.PlateCarree()) ax3 = f.add_subplot(gs[1,0], projection=ccrs.PlateCarree()) ax4 = f.add_subplot(gs[1,1], projection=ccrs.PlateCarree()) ax5 = f.add_subplot(gs[2,0], projection=ccrs.PlateCarree()) # 隐藏未使用的子图 for ax in [f.add_subplot(gs[0,2]), f.add_subplot(gs[1,2]), f.add_subplot(gs[2,1]), f.add_subplot(gs[2,2])]: ax.set_visible(False) # 后续ax1的处理代码保持原有逻辑 inter = np.linspace(-5,5, num=11, endpoint=True) lat = f222['xlat'] lon = f222['xlon'] pr = ax1.contourf(lon, lat, f222.tmp.mean('time'), inter, transform=ccrs.PlateCarree(), cmap='RdGy_r', extend='both') ax1.coastlines(resolution='50m', color='black', lw=0.5) x_lons = np.arange(-20,20,10) y_lats = np.arange(5,25,5) ax1.tick_params(labelsize=7) lon_formatter = LongitudeFormatter(zero_direction_label=True, number_format='.0f') lat_formatter = LatitudeFormatter() ax1.xaxis.set_major_formatter(lon_formatter) ax1.yaxis.set_major_formatter(lat_formatter) ax1.set_xticks(x_lons, minor=False, crs=ccrs.PlateCarree()) ax1.set_yticks(y_lats, minor=False, crs=ccrs.PlateCarree()) ax1.text(-23., 5.5, r'(a)', fontsize=7, fontweight="bold") ax1.text(-15., 25, r'CRU - Grell', fontsize=10, fontweight="bold") ax1.add_feature(cf.BORDERS, lw=0.5) ax1.add_feature(cf.COASTLINE, lw=0.5) # 其他子图按相同逻辑处理即可
关键说明
width_ratios是GridSpec的核心参数,用于控制列的宽度比例,你可根据实际需求调整数值,实现子图轴的偏移对齐。- 两种方法均适配你使用的matplotlib 3.6.2版本,且完全兼容cartopy的地理投影轴。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

