使用Python Basemap绘图时子图排列混乱的问题排查
嘿,我帮你揪出了几个导致子图显示异常的核心问题,咱们一步步来解决:
问题1:子图编号逻辑完全错误
你用plt.subplot(621+L)来指定子图位置,但这个计算方式完全不符合matplotlib的subplot索引规则:
- matplotlib的subplot三位数编码是
行数+列数+索引(仅当行数、列数、索引都是个位数时可用),但当索引超过9时(比如第10个及以后的子图),这种拼接方式会彻底混乱(比如621+10=631会被解析成6行3列的第1个子图,完全偏离了你要的6行2列布局)。 - 正确的做法是用逗号分隔的参数
plt.subplot(nrows, ncols, index),其中index是从1开始的行优先序号。对你的6行2列布局来说,L从0到11,对应的索引就是L+1,所以应该写plt.subplot(6, 2, L+1)。
问题2:未显式创建独立的Figure
虽然plt.show()会清空当前画布,但为了避免绘图残留和混乱,最好在每个N的循环开头显式创建一个新的Figure,比如设置合适的尺寸来容纳12个子图。
问题3:色条关联不明确
当前代码里plt.colorbar()默认绑定最后一个绘图对象,最好把m.pcolor()的返回值存下来,显式传递给色条函数,确保色条和数据匹配。
修正后的完整代码
我还补全了测试所需的未定义变量,你可以直接运行测试:
# Imports import matplotlib.cm as cm import matplotlib as mpl import matplotlib.pyplot as plt from mpl_toolkits.basemap import Basemap import numpy.ma as ma import numpy as np # Parameter Set-Up N = ['A', 'B', 'C'] LAYER = ['1', '2', '3', '4', '5', '6'] # 补全测试用的变量定义 Lat_1x1 = 60 Lon_1x1 = 70 llc_LON = 139.5 urc_LON = 280.5 llc_LAT = -29.5 urc_LAT = 29.5 lon = np.linspace(llc_LON, urc_LON, Lon_1x1) lat = np.linspace(llc_LAT, urc_LAT, Lat_1x1) data = np.random.randint(101, size=(len(N),2*len(LAYER),Lat_1x1,Lon_1x1)) # Basemap Set-Up # Colorbar Boundary Definitions cmap_data = cm.rainbow_r cmap_data.set_bad(color='white') data_plot = np.ma.array(data, mask=np.isnan(data)) # Mask NaN bounds_data = np.arange(0, 102, 2) norm_data = mpl.colors.BoundaryNorm(bounds_data, cmap_data.N) for n in np.arange(len(N)): # 为每个N创建独立的Figure,设置合适的尺寸 plt.figure(figsize=(12, 18)) for L in np.arange(2*len(LAYER)): # 正确指定6行2列的子图位置 ax = plt.subplot(6, 2, L+1) m = Basemap(projection='cyl', llcrnrlon=llc_LON, urcrnrlon=urc_LON, llcrnrlat=llc_LAT, urcrnrlat=urc_LAT, resolution='c', ax=ax) m.drawcoastlines(color='k') m.fillcontinents(color='white') # mask land mass lons, lats = np.meshgrid(lon,lat) x, y = m(lons,lats) # 保存pcolor的返回值,用于色条关联 im = m.pcolor(x, y, data_plot[n,L], cmap=cmap_data, norm=norm_data) plt.xlim(llc_LON, urc_LON) plt.xticks([150, 180, 210, 240, 270], ['150E', 'D', '150', '120', '90W']) # 140W to 80E plt.ylim(llc_LAT, urcr_LAT) plt.yticks([-30, -15, 0, 15, 30], ['30S', '15S', '0', '15N', '30N']) # 30S to 30N # 给最后一行的子图添加坐标轴标签 if L >= 10: # 第11、12个子图(索引11和12,对应L=10和11) plt.xlabel('Longitude') plt.ylabel('Latitude') plt.grid() # 调整子图布局,留出色条位置 plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9, hspace=0.3, wspace=0.2) # 创建色条轴 cax = plt.axes([0.82, 0.1, 0.03, 0.8]) # 显式传入im对象,确保色条和数据匹配 plt.colorbar(im, cax=cax, label='%') plt.suptitle(f'Test for {N[n]}', fontsize=16) plt.show()
额外优化点
- 我添加了
hspace和wspace参数来调整子图之间的间距,避免标签重叠; - 把色条的宽度调小了一点,避免挤占子图空间;
- 用f-string让标题更简洁;
- 给Basemap指定了
ax=ax,确保它画在对应的子图轴上,避免潜在的轴混乱。
这样修改后,每个N对应的图都会显示完整的12个子图,位置也完全正确啦!
内容的提问来源于stack exchange,提问作者kirerik
相关产品推荐
相关产品推荐

