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

Python plt.contourf绘制地图0°纬度处出现白线问题求解

问题描述

我正在使用如下代码绘制气溶胶地图:

region = Box(
    Box_name="Focus",
    lonmin = -136,
    lonmax = 20,
    latmin = 20,
    latmax = 70
)

Box1 = Box(
    Box_name="Box 1",
    lonmin = -124,
    lonmax = -114,
    latmin = 35,
    latmax = 42
)
Box2 =  Box(
        Box_name="Box 2",
        lonmin=-124,
        lonmax=-114,
        latmin=43,
        latmax=50
)
Box3 =  Box(
        Box_name="Box 3",
        lonmin=-104,
        lonmax=-94,
        latmin=42,
        latmax=49
)
Box4 =  Box(
        Box_name="Box 4",
        lonmin=-88,
        lonmax=-78,
        latmin=40,
        latmax=47
)
Box5 =  Box(
        Box_name="Box 5",
        lonmin=-65,
        lonmax=-55,
        latmin=43,
        latmax=50
)

def plot_geog_location(region, lakes=False, borders=False, rivers=False):
    """ use cartopy to plot the region (defined as a namedtuple object)

    Arguments:
    ---------
    : region (Region namedtuple)
        region of interest bounding box defined in engineering/regions.py
    : lakes (bool)
        show lake features
    : borders (bool)
        show lake features
    : rivers (bool)
        show river features (@10m scale from NaturalEarth)
    """
    lonmin,lonmax,latmin,latmax = region.lonmin,region.lonmax,region.latmin,region.latmax
    ax = plt.figure().gca(projection=cartopy.crs.PlateCarree())
    CS = plt.contourf(lons, lats, AOD[:,:],levels=level, extend='both',cmap=plt.cm.Oranges, norm=norm)
    plt.title('AOD mean over North America 13 to 17 Sep 2020 (Inj25)',fontsize=16)
    plt.gcf().set_size_inches(15, 11)
    cbar = plt.colorbar(CS, shrink=0.45,ticks=[0,0.25,0.5])
    cbar.ax.set_yticklabels(['0','0.25', '0.5'])
    ax.add_feature(cpf.COASTLINE)
    ax.add_feature(cfeature.STATES, zorder=1, linewidth=1, edgecolor='k',linestyle=':')
    if borders:
        ax.add_feature(cpf.BORDERS, linestyle='--')

    ax.set_extent([lonmin, lonmax, latmin, latmax])

    # plot the lat lon labels
    xticks = np.linspace(lonmin, lonmax, 5)
    yticks = np.linspace(latmin, latmax, 5)

    ax.set_xticks(xticks, crs=cartopy.crs.PlateCarree())
    ax.set_yticks(yticks, crs=cartopy.crs.PlateCarree())
    lon_formatter = LongitudeFormatter(zero_direction_label=True)
    lat_formatter = LatitudeFormatter()
    ax.xaxis.set_major_formatter(lon_formatter)
    ax.yaxis.set_major_formatter(lat_formatter)

    fig = plt.gcf()

    return fig, ax


def plot_polygon(ax, Box1, Box2, Box3, Box4, Box5):
    """
    Note:
    ----
    order is important:
        lower-left, upper-left, upper-right, lower-right
        2 -- 3
        |    |
        1 -- 4
    """
    ax = fig.axes[0]
    lons = [Box1.latmin, Box1.latmin, Box1.latmax, Box1.latmax]
    lats = [Box1.lonmin, Box1.lonmax, Box1.lonmax, Box1.lonmin]
    ring = LinearRing(list(zip(lons, lats)))
    lons2 = [Box2.latmin, Box2.latmin, Box2.latmax, Box2.latmax]
    lats2 = [Box2.lonmin, Box2.lonmax, Box2.lonmax, Box2.lonmin]
    ring2 = LinearRing(list(zip(lons2, lats2)))
    lons3 = [Box3.latmin, Box3.latmin, Box3.latmax, Box3.latmax]
    lats3 = [Box3.lonmin, Box3.lonmax, Box3.lonmax, Box3.lonmin]
    ring3 = LinearRing(list(zip(lons3, lats3)))
    lons4 = [Box4.latmin, Box4.latmin, Box4.latmax, Box4.latmax]
    lats4 = [Box4.lonmin, Box4.lonmax, Box4.lonmax, Box4.lonmin]
    ring4 = LinearRing(list(zip(lons4, lats4)))
    lons5 = [Box5.latmin, Box5.latmin, Box5.latmax, Box5.latmax]
    lats5 = [Box5.lonmin, Box5.lonmax, Box5.lonmax, Box5.lonmin]
    ring5 = LinearRing(list(zip(lons5, lats5)))
    ax.add_geometries([ring], cartopy.crs.PlateCarree(), facecolor='b', edgecolor='black', alpha=0.5)
    return ax


def add_sub_region_box(ax, box1, box2, box3, box4, box5):
    """ """
    geom = geometry.box(minx=Box1.lonmin,maxx=Box1.lonmax,miny=Box1.latmin,maxy=Box1.latmax)
    geom2 = geometry.box(minx=Box2.lonmin,maxx=Box2.lonmax,miny=Box2.latmin,maxy=Box2.latmax)
    geom3 = geometry.box(minx=Box3.lonmin,maxx=Box3.lonmax,miny=Box3.latmin,maxy=Box3.latmax)
    geom4 = geometry.box(minx=Box4.lonmin,maxx=Box4.lonmax,miny=Box4.latmin,maxy=Box4.latmax)
    geom5 = geometry.box(minx=Box5.lonmin,maxx=Box5.lonmax,miny=Box5.latmin,maxy=Box5.latmax)
    ax.add_geometries([geom], crs=cartopy.crs.PlateCarree(), alpha=0.3)
    ax.add_geometries([geom2], crs=cartopy.crs.PlateCarree(), alpha=0.3)
    ax.add_geometries([geom3], crs=cartopy.crs.PlateCarree(), alpha=0.3)
    ax.add_geometries([geom4], crs=cartopy.crs.PlateCarree(), alpha=0.3)
    ax.add_geometries([geom5], crs=cartopy.crs.PlateCarree(), alpha=0.3)
    return ax


fig, ax = plot_geog_location(region,borders=True, lakes=False, rivers=False)
add_sub_region_box(ax, Box1, Box2, Box3, Box4, Box5)

绘图时经常发现图面出现白色线条,该白线大多位于0°纬度附近。已确认该问题并非由数据导致,因为在很多其他场景下使用相同代码绘图不会出现这类白线,问题示例图如下:
问题示例图

问题原因

这是matplotlib.contourf搭配cartopy投影使用时的经典渲染问题:默认开启的抗锯齿效果会让相邻填色多边形的拼接边缘产生半透明缝隙,漏出下方白色画布。白线固定出现在0°纬度附近,是因为你的AOD数据网格刚好在该纬度存在分块/拼接边界,不是数据缺测或逻辑错误导致的。

解决方案

按生效优先级排序,可直接选用以下方案修复:

  • 最快修复:给contourf调用加antialiased=False参数关闭抗锯齿,90%以上的场景可直接消除白线,对图面显示效果几乎无影响:
CS = plt.contourf(lons, lats, AOD[:,:],levels=level, extend='both',cmap=plt.cm.Oranges, norm=norm, antialiased=False)
  • 彻底消除缝隙:如果关闭抗锯齿仍有残留白线,再加edgecolor='face'参数,让每个填色块的描边颜色和自身填充色完全一致,从根源堵死缝隙:
CS = plt.contourf(lons, lats, AOD[:,:],levels=level, extend='both',cmap=plt.cm.Oranges, norm=norm, antialiased=False, edgecolor='face')
  • 替换渲染方式:如果你的AOD是规则网格数据,直接改用pcolormesh代替contourf绘制填色图,pcolormesh对规则网格的渲染稳定性远高于contourf,基本不会出现拼接缝隙问题,调用时注意确认经纬度数组维度和数据维度匹配即可:
CS = plt.pcolormesh(lons, lats, AOD[:,:], vmin=0, vmax=0.5, cmap=plt.cm.Oranges, norm=norm)

额外代码问题提示:你的代码里还存在两个隐藏bug,后续调用相关函数时可能出错:

  1. plot_polygon函数内把经纬度变量写反了,存入lons列表的是纬度值、存入lats列表的是经度值,调用该函数绘制的多边形会出现在错误位置
  2. add_sub_region_box函数的入参是小写的box1~box5,但函数内部调用的是全局大写的Box1~Box5,属于作用域写法不规范,一旦全局变量变动就会报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 04:36:26