Cartopy中set_bad函数异常:无效值颜色设置问题求助
在Cartopy中正确设置无效值(Bad Values)颜色的解决方案
问题场景
使用Cartopy结合Matplotlib绘制带NaN(无效值)的地理数据时,遇到两个异常:
- 直接通过
cm.set_bad("gray")设置无效值为灰色时,地图大面积显示灰色且触发UserWarning - 按提示设置
cm.set_bad("gray", alpha=0.0)后,无效值区域完全不显示颜色
使用模块版本
| 模块名称 | 版本号 |
|---|---|
| PYTHON | 3.10.6 |
| numpy | 1.23.4 |
| cartopy | 0.21.0 |
| matplotlib | 3.6.2 |
| xarray | 2022.11.0 |
测试代码
import cartopy import cartopy.crs as ccrs import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import xarray as xr # 设置绘图风格 mpl.style.use("seaborn-v0_8-ticks") # 构造测试数据 sig = np.sin(np.radians(np.linspace(-90, 90, 192))) sig = np.tile(sig, [288, 1]).T darr = xr.DataArray( sig, dims=("lat", "lon"), coords={ "lat": np.linspace(-90, 90, 192), "lon": np.linspace(0, 360, 288), }, ) # 手动设置无效值为NaN darr[100:200, 100:200] = np.nan cm = plt.get_cmap("RdBu_r") # 情况1:设置灰色无效值,出现显示异常 cm.set_bad("gray") fig, ax1 = plt.subplots(figsize=(8, 4)) ax1 = plt.subplot(111, projection=ccrs.PlateCarree(central_longitude=0)) ax1.coastlines() lons, lats = np.meshgrid(darr["lon"], darr["lat"]) ax1.pcolormesh(lons, lats, darr, transform=ccrs.PlateCarree(), cmap=cm) # 情况2:设置完全透明,无效值区域消失 cm.set_bad("gray", alpha=0.0) fig, ax1 = plt.subplots(figsize=(8, 4)) ax1 = plt.subplot(111, projection=ccrs.PlateCarree(central_longitude=0)) ax1.coastlines() lons, lats = np.meshgrid(darr["lon"], darr["lat"]) ax1.pcolormesh(lons, lats, darr, transform=ccrs.PlateCarree(), cmap=cm)
问题根源
核心原因是pcolormesh在跨投影坐标系下处理NaN区域时,会错误填充不连续多边形,加上直接修改全局colormap的方式与Cartopy投影存在兼容性冲突。
正确解决方案
方法1:使用imshow替代pcolormesh(规则网格推荐)
imshow对规则网格的NaN支持更稳定,结合extent参数适配地理范围:
import cartopy.crs as ccrs import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import xarray as xr mpl.style.use("seaborn-v0_8-ticks") # 构造测试数据 sig = np.sin(np.radians(np.linspace(-90, 90, 192))) sig = np.tile(sig, [288, 1]).T darr = xr.DataArray( sig, dims=("lat", "lon"), coords={ "lat": np.linspace(-90, 90, 192), "lon": np.linspace(0, 360, 288), }, ) darr[100:200, 100:200] = np.nan # 创建colormap副本,避免修改全局默认 cm = plt.get_cmap("RdBu_r").copy() cm.set_bad("gray") fig, ax = plt.subplots(figsize=(8, 4), subplot_kw={"projection": ccrs.PlateCarree(central_longitude=0)}) ax.coastlines() # 使用imshow绘制,指定原点和范围 ax.imshow(darr, origin="lower", extent=[darr.lon.min(), darr.lon.max(), darr.lat.min(), darr.lat.max()], transform=ccrs.PlateCarree(), cmap=cm) plt.show()
方法2:修复pcolormesh的NaN处理逻辑
若必须使用pcolormesh,需明确颜色映射范围并使用colormap副本:
import cartopy.crs as ccrs import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import xarray as xr from matplotlib.colors import Normalize mpl.style.use("seaborn-v0_8-ticks") # 构造测试数据 sig = np.sin(np.radians(np.linspace(-90, 90, 192))) sig = np.tile(sig, [288, 1]).T darr = xr.DataArray( sig, dims=("lat", "lon"), coords={ "lat": np.linspace(-90, 90, 192), "lon": np.linspace(0, 360, 288), }, ) darr[100:200, 100:200] = np.nan # 创建独立colormap副本 cm = plt.get_cmap("RdBu_r").copy() cm.set_bad("gray") fig, ax = plt.subplots(figsize=(8, 4), subplot_kw={"projection": ccrs.PlateCarree(central_longitude=0)}) ax.coastlines() lons, lats = np.meshgrid(darr["lon"], darr["lat"]) # 指定颜色映射范围,避免自动缩放导致的异常 norm = Normalize(vmin=darr.min(), vmax=darr.max()) ax.pcolormesh(lons, lats, darr, transform=ccrs.PlateCarree(), cmap=cm, norm=norm) plt.show()
方法3:使用xarray内置绘图接口(最省心)
xarray与Cartopy集成良好,自动处理NaN和投影兼容问题:
import cartopy.crs as ccrs import matplotlib as mpl import numpy as np import xarray as xr mpl.style.use("seaborn-v0_8-ticks") # 构造测试数据 sig = np.sin(np.radians(np.linspace(-90, 90, 192))) sig = np.tile(sig, [288, 1]).T darr = xr.DataArray( sig, dims=("lat", "lon"), coords={ "lat": np.linspace(-90, 90, 192), "lon": np.linspace(0, 360, 288), }, ) darr[100:200, 100:200] = np.nan fig, ax = plt.subplots(figsize=(8, 4), subplot_kw={"projection": ccrs.PlateCarree(central_longitude=0)}) # 直接调用xarray的plot方法,指定无效值颜色 darr.plot(ax=ax, transform=ccrs.PlateCarree(), cmap="RdBu_r", cbar_kwargs={"shrink": 0.8}, bad_color="gray") ax.coastlines() plt.show()
关键注意事项
- 始终创建colormap副本(
.copy()),避免修改全局默认样式影响其他绘图 - 使用
pcolormesh时必须明确颜色映射范围(vmin/vmax或Normalize) - xarray内置绘图接口是处理地理数据NaN的最优选择,无需手动处理投影和掩码逻辑
内容的提问来源于stack exchange,提问作者Mu Qingyu
相关产品推荐
相关产品推荐

