You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cartopy中set_bad函数异常:无效值颜色设置问题求助

在Cartopy中正确设置无效值(Bad Values)颜色的解决方案

问题场景

使用Cartopy结合Matplotlib绘制带NaN(无效值)的地理数据时,遇到两个异常:

  1. 直接通过cm.set_bad("gray")设置无效值为灰色时,地图大面积显示灰色且触发UserWarning
  2. 按提示设置cm.set_bad("gray", alpha=0.0)后,无效值区域完全不显示颜色

使用模块版本

模块名称版本号
PYTHON3.10.6
numpy1.23.4
cartopy0.21.0
matplotlib3.6.2
xarray2022.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:50:45