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

如何缓存或复用Cartopy的GSHHSFeature以优化多子图绘图效率?

复用Cartopy GSHHS海岸线底图优化多子图绘制

问题背景

我使用Cartopy在多个Matplotlib子图中展示GSHHSFeature海岸线,并叠加不同数据。当前代码每次循环都会重新创建海岸线特征,使用full尺度时耗时特别明显。由于所有子图的底图完全一致,希望找到仅创建一次底图、循环复用的方法,比如实现类似ax[i][j].plot_my_basemap(map_ax)或复制轴的逻辑,但不想使用Basemap(已被Cartopy替代,且与Matplotlib 3.8存在兼容性问题)。

当前实现代码

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np

xss = np.linspace(-21, 36, 36)
extent = [-21, 36, 33, 64]  # west,east,south,north
rows=3
cols=2

fig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(13, 15), 
                       subplot_kw={'projection': ccrs.PlateCarree()})

for i in range(rows):
    for j in range(cols):
        ax[i][j].set_extent(extent)
        ax[i][j].add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f"))

        # 叠加子图专属数据
        ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
        
        # 设置子图标题
        ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))

plt.tight_layout()
plt.show()

尝试过的无效方法

  1. 预创建底图轴复用(FeatureArtist无法像瓦片图直接复用):
# 预创建底图轴
map_ax = plt.axes(projection=ccrs.PlateCarree())
map_ax.set_extent(extent)
map_ax.add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f"))

fig, ax = plt.subplots(nrows=3, ncols=2, figsize=(13, 15), 
                       subplot_kw={'projection': ccrs.PlateCarree()})

for i in range(rows):
    for j in range(cols):
        ax[i][j].plot_my_basemap(map_ax)  # 此方法不存在,无法生效

        # 叠加子图专属数据
        ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
        
        ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))

plt.tight_layout()
plt.show()
  1. 直接修改轴属性复用(Matplotlib不支持该逻辑):
for i in range(rows):
    for j in range(cols):
        props = ax[i][j].properties()
        props = dict((k, props[k]) for k in ["position", "subplotspec"])
        ax[i][j] = map_ax.update(props)  # 无法直接替换轴对象

        # 叠加子图专属数据
        ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
        
        ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))

可行解决方案

方案1:预渲染底图为图像复用

将底图一次性渲染为图像,后续子图直接调用该图像,避免重复处理地理数据:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np

xss = np.linspace(-21, 36, 36)
extent = [-21, 36, 33, 64]
rows = 3
cols = 2

# 1. 预渲染底图为图像
fig_blank, ax_blank = plt.subplots(figsize=(13/cols, 15/rows),  # 匹配单个子图尺寸
                                   subplot_kw={'projection': ccrs.PlateCarree()})
ax_blank.set_extent(extent)
ax_blank.add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f"))
ax_blank.set_axis_off()  # 隐藏轴元素,仅保留底图

# 渲染并转为numpy数组
fig_blank.canvas.draw()
width, height = fig_blank.canvas.get_width_height()
basemap_img = np.frombuffer(fig_blank.canvas.tostring_rgb(), dtype=np.uint8).reshape(height, width, 3)
plt.close(fig_blank)  # 关闭临时画布

# 2. 创建子图并复用底图图像
fig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(13, 15), 
                       subplot_kw={'projection': ccrs.PlateCarree()})

for i in range(rows):
    for j in range(cols):
        current_ax = ax[i][j] if rows>1 and cols>1 else ax[j] if cols>1 else ax[i]
        current_ax.set_extent(extent)
        # 加载预渲染的底图
        current_ax.imshow(basemap_img, origin='upper', extent=extent, transform=ccrs.PlateCarree(), zorder=0)
        
        # 叠加子图专属数据
        current_ax.plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), 
                        color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
        
        current_ax.set_title(f"Row:{i}, Col:{j}")

plt.tight_layout()
plt.show()

方案2:缓存GSHHSFeature几何数据

直接提取并缓存GSHHS的几何集合,避免重复读取和处理地理数据:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np

xss = np.linspace(-21, 36, 36)
extent = [-21, 36, 33, 64]
rows = 3
cols = 2

# 1. 缓存GSHHS几何数据
gshhs_feature = cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f")
geometries = list(gshhs_feature.geometries())  # 一次性读取所有几何对象
cached_feature = cfeature.ShapelyFeature(geometries, ccrs.PlateCarree(), 
                                         edgecolor="black", facecolor="#bca89f")

# 2. 创建子图并复用缓存特征
fig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(13, 15), 
                       subplot_kw={'projection': ccrs.PlateCarree()})

for i in range(rows):
    for j in range(cols):
        current_ax = ax[i][j] if rows>1 and cols>1 else ax[j] if cols>1 else ax[i]
        current_ax.set_extent(extent)
        # 添加缓存好的海岸线特征
        current_ax.add_feature(cached_feature)
        
        # 叠加子图专属数据
        current_ax.plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), 
                        color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
        
        current_ax.set_title(f"Row:{i}, Col:{j}")

plt.tight_layout()
plt.show()

方案对比

  • 图像复用方案:速度最快,适合底图样式完全固定的场景;缺点是后续无法修改底图样式,需重新渲染。
  • 几何数据缓存方案:保留特征的可编辑性,可随时修改海岸线颜色、线宽等属性,同时避免重复读取地理数据,性能提升明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 16:34:57