You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用经纬度绘制海洋数据地图时,避免插值致陆地显数据的方法

解决CMIP6海洋数据绘图时陆地区域被插值填充的问题

这是CMIP6海洋数据绘图的典型坑——多数海洋模式采用不规则的二维海洋网格(不是咱们熟悉的规则经纬度网格),当你用x='lon', y='lat'调用xarray的plot方法时,matplotlib会默认把这些二维坐标当成规则网格处理,自动插值填充了本该是NaN的陆地区域。结合你的代码,给你几个针对性的解决方案:


1. 先确认数据里的陆地确实是NaN

CMIP6海洋数据一般默认把陆地区域设为NaN,但个别情况可能用了其他填充值(比如0),先检查一下:

# 看看有多少NaN值(对应陆地)
print(sub2.isnull().sum())

# 如果发现有非NaN的填充值,替换成NaN(比如填充值是0的话)
sub2 = sub2.where(sub2 != 0)

2. 用pcolormesh直接传入二维坐标,关闭插值

这是最有效的解决办法,核心是让绘图函数知道这是不规则网格,别瞎插值。修改你的绘图代码:

ax = plt.axes(projection=ccrs.Robinson())
# 直接用matplotlib的pcolormesh,传入二维的lon、lat和数据
q = ax.pcolormesh(
    ds.lon, ds.lat, sub2,
    transform=ccrs.PlateCarree(),
    vmin=0, vmax=0.4
)
# 也可以用xarray的plot.pcolormesh,注意直接传二维数组而非字符串
# q = sub2.plot.pcolormesh(
#     ax=ax, x=ds.lon, y=ds.lat,
#     transform=ccrs.PlateCarree(),
#     vmin=0, vmax=0.4,
#     cbar_kwargs={'shrink': 0.5},
#     shading='flat'  # 关闭插值
# )
# 添加颜色条
plt.colorbar(q, shrink=0.5)
ax.set_global(); ax.coastlines();

这里的关键是别用'lon'/'lat'字符串当x/y参数,直接传二维的ds.londs.lat,这样matplotlib就不会把它当成规则网格插值了。


3. 处理跨0度经线的经度(可选)

如果你的经度范围是0-360度,可能会在0度经线附近出现奇怪的断裂,建议转成-180到180度的范围:

# 转换经度范围
ds['lon'] = xr.where(ds.lon > 180, ds.lon - 360, ds.lon)
# 重新提取需要的数据
sub2 = ds.o2.sel(member_id=ds.member_id.values[0], time=ds.time.values[0]).sel(lev=100, method='nearest')

4. 用contour/contourf的话,记得屏蔽NaN区域

如果非要用等高线绘图,得给contourf加个mask参数,让它跳过NaN区域:

ax = plt.axes(projection=ccrs.Robinson())
q = ax.contourf(
    ds.lon, ds.lat, sub2,
    transform=ccrs.PlateCarree(),
    vmin=0, vmax=0.4,
    mask=sub2.isnull()  # 告诉它别画NaN的区域
)
ax.set_global(); ax.coastlines();
plt.colorbar(q, shrink=0.5)

这样等高线就只会在海洋区域绘制,陆地部分保持空白,配合cartopy的海岸线就对了。


内容的提问来源于stack exchange,提问作者FunkySheep

火山引擎 最新活动