求助:将Cartopy代码从Orthographic投影改为Robinson投影时出现ValueError的原因及解决方法
Robinson投影报错的原因分析与修复方案
我来帮你拆解这个问题,你遇到的错误本质是投影类型对数据格式的要求差异导致的,咱们一步步来理清楚:
错误原因
你看到的ValueError核心信息是:Robinson投影下,使用shading='nearest'时要求输入的数据是二维规则网格(形状类似(200,360)这样的二维数组),但你的dia_depth_smooth数据是一维的(形状(263,)),完全不匹配网格渲染的要求。
为什么Orthographic投影能正常运行?因为正射投影是局部视角的投影,它对数据的兼容性更强,即使是一维散点数据,也能通过shading参数做简单处理;而Robinson是全局投影,底层渲染逻辑强制要求数据必须是二维网格结构,否则无法完成全局投影的坐标转换和着色计算。
可行解决方案
根据你的数据类型,分两种情况处理:
情况1:你的数据是不规则散点(非规则网格)
如果dia_depth_smooth是零散的经纬度点数据,需要先把它插值到规则网格上,再用Robinson投影绘制:
from matplotlib.ticker import AutoMinorLocator from scipy.interpolate import griddata import numpy as np # 1. 提取原始散点数据 lon = dia_depth_smooth['geolon_t'].values lat = dia_depth_smooth['geolat_t'].values depth = dia_depth_smooth.values # 替换成你的深度列名称,比如dia_depth_smooth['depth'].values # 2. 创建规则网格(可根据数据范围调整网格密度) grid_lon = np.linspace(lon.min(), lon.max(), 360) grid_lat = np.linspace(lat.min(), lat.max(), 200) grid_lon, grid_lat = np.meshgrid(grid_lon, grid_lat) # 3. 用最近邻插值将散点转换为网格数据 grid_depth = griddata((lon, lat), depth, (grid_lon, grid_lat), method='nearest') # 4. 绘制Robinson投影地图 fig, (ax) = plt.subplots(nrows=1, ncols=1, figsize=fig_size_single_golden, constrained_layout=True, subplot_kw=dict(projection=ccrs.Robinson(central_longitude=-118.0)) ) # 改用pcolormesh绘制网格数据 cb = ax.pcolormesh(grid_lon, grid_lat, grid_depth, robust=True, cmap=cm.cm.deep, vmin=0, vmax=2500, transform=ccrs.PlateCarree(), shading='nearest') # 后续的colorbar和地图装饰代码保持不变 cb.colorbar.ax.yaxis.set_minor_locator(AutoMinorLocator()) ax.coastlines(linewidth=0.5) ax.add_feature(cartopy.feature.LAND, zorder=1, facecolor='gray', edgecolor='black', linewidth=0.5) ax.set_title('') plt.savefig('Figure1b.png', format='png', dpi=600, bbox_inches="tight", pad_inches=0)
情况2:你的数据本来是规则网格,但被展平成了一维
如果dia_depth_smooth是从二维网格展平来的(比如原始是201×361的网格),只需要把数据reshape回二维即可:
from matplotlib.ticker import AutoMinorLocator import numpy as np # 1. 将一维数据reshape为二维网格 depth_2d = dia_depth_smooth.values.reshape(201, 361) # 替换成你原始网格的维度 # 2. 生成对应的二维经纬度网格 lon_1d = dia_depth_smooth['geolon_t'].unique() lat_1d = dia_depth_smooth['geolat_t'].unique() lon_2d, lat_2d = np.meshgrid(lon_1d, lat_1d) # 3. 绘制Robinson投影地图 fig, (ax) = plt.subplots(nrows=1, ncols=1, figsize=fig_size_single_golden, constrained_layout=True, subplot_kw=dict(projection=ccrs.Robinson(central_longitude=-118.0)) ) cb = ax.pcolormesh(lon_2d, lat_2d, depth_2d, robust=True, cmap=cm.cm.deep, vmin=0, vmax=2500, transform=ccrs.PlateCarree(), shading='nearest') # 后续代码保持不变 cb.colorbar.ax.yaxis.set_minor_locator(AutoMinorLocator()) ax.coastlines(linewidth=0.5) ax.add_feature(cartopy.feature.LAND, zorder=1, facecolor='gray', edgecolor='black', linewidth=0.5) ax.set_title('') plt.savefig('Figure1b.png', format='png', dpi=600, bbox_inches="tight", pad_inches=0)
备选方案:直接绘制散点图(无需插值)
如果不需要网格渲染效果,也可以改用scatter函数直接绘制散点,这样Robinson投影也能正常运行:
from matplotlib.ticker import AutoMinorLocator fig, (ax) = plt.subplots(nrows=1, ncols=1, figsize=fig_size_single_golden, constrained_layout=True, subplot_kw=dict(projection=ccrs.Robinson(central_longitude=-118.0)) ) # 改用scatter绘制散点 sc = ax.scatter(dia_depth_smooth['geolon_t'], dia_depth_smooth['geolat_t'], c=dia_depth_smooth.values, cmap=cm.cm.deep, vmin=0, vmax=2500, transform=ccrs.PlateCarree()) # 调整colorbar的创建方式 cb = fig.colorbar(sc, shrink=0.8, aspect=40, pad=0.04, orientation="horizontal", label="Diapause Depth (metres)") cb.ax.yaxis.set_minor_locator(AutoMinorLocator()) ax.coastlines(linewidth=0.5) ax.add_feature(cartopy.feature.LAND, zorder=1, facecolor='gray', edgecolor='black', linewidth=0.5) ax.set_title('') plt.savefig('Figure1b.png', format='png', dpi=600, bbox_inches="tight", pad_inches=0)
内容的提问来源于stack exchange,提问作者Si Chen
相关产品推荐
相关产品推荐

