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

Cartopy中Stamen地形地图加载异常问题求助

问题

使用Cartopy(v0.21.1)结合matplotlib(v3.7.1),通过cartopy.io.img_tiles.Stamen('terrain-background')绘制地图插图,此前运行正常,但近期偶尔出现以下错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/anaconda3/envs/xuscd/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
    246 
    247     if 'png' in formats:
--> 248         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
    249     if 'retina' in formats or 'png2x' in formats:
    250         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
    130         FigureCanvasBase(fig)
    131 
--> 132     fig.canvas.print_figure(bytes_io, **kw)
    133     data = bytes_io.getvalue()
    134     if fmt == 'svg':

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2340                 )
   2341                 with getattr(renderer, "_draw_disabled", nullcontext)():
--> 2342                     self.figure.draw(renderer)
   2343 
   2344             if bbox_inches:

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     93     @wraps(draw)
     94     def draw_wrapper(artist, renderer, *args, **kwargs):
--> 95         result = draw(artist, renderer, *args, **kwargs)
     96         if renderer._rasterizing:
     97             renderer.stop_rasterizing()

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     70                 renderer.start_filter()
     71 
--> 72             return draw(artist, renderer)
     73         finally:
     74             if artist.get_agg_filter() is not None:

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/matplotlib/figure.py in draw(self, renderer)
   3138 
   3139             self.patch.draw(renderer)
--> 3140             mimage._draw_list_compositing_images(
   3141                 renderer, self, artists, self.suppressComposite)
   3142 

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129     if not_composite or not has_images:
    130         for a in artists:
--> 131             a.draw(renderer)
    132     else:
    133         # Composite any adjacent images together

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     70                 renderer.start_filter()
     71 
--> 72             return draw(artist, renderer)
     73         finally:
     74             if artist.get_agg_filter() is not None:

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/cartopy/mpl/geoaxes.py in draw(self, renderer, **kwargs)
    529         if not self._done_img_factory:
    530             for factory, factory_args, factory_kwargs in self.img_factories:
--> 531                 img, extent, origin = factory.image_for_domain(
    532                     self._get_extent_geom(factory.crs), factory_args[0])
    533                 self.imshow(img, extent=extent, origin=origin,

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/cartopy/io/img_tiles.py in image_for_domain(self, target_domain, target_z)
     97 
     98         print(f'img shape = {img.shape}')
--> 99         img, extent, origin = _merge_tiles(tiles)
    100         return img, extent, origin
    101 

~/anaconda3/envs/xuscd/lib/python3.8/site-packages/cartopy/io/img_tiles.py in _merge_tiles(tiles)
    652         print(img_slice)
    653 
--> 654         img[img_slice] = tile_img
    655 
    656     return img, [min(xs), max(xs), min(ys), max(ys)], 'lower'

ValueError: could not broadcast input array from shape (512,512,3) into shape (766,766,3)
分析与解决方案

该错误确实和Stamen地图的瓦片规格变更有关。Stamen传统瓦片尺寸为512×512,近期部分边缘区域的瓦片尺寸出现变动,导致Cartopy v0.21.1的_merge_tiles函数在合并瓦片时,无法将512×512的瓦片数据匹配到计算出的766×766切片区域,从而触发广播错误。

可通过以下方式解决:

  • 升级Cartopy版本:Cartopy v0.22及后续版本已修复瓦片尺寸兼容问题,直接升级到最新稳定版即可解决。执行命令:
    pip install --upgrade cartopy
    
  • 临时修改兼容逻辑:若无法升级,可修改Cartopy的img_tiles.py文件,在_merge_tiles函数的img[img_slice] = tile_img语句前添加瓦片尺寸适配代码:
    from PIL import Image
    import numpy as np
    # 将瓦片resize到目标切片尺寸
    target_shape = (img_slice[0].stop - img_slice[0].start, img_slice[1].stop - img_slice[1].start)
    tile_img = np.array(Image.fromarray(tile_img).resize(target_shape[::-1]))
    
    需提前安装Pillow库:pip install pillow
  • 切换瓦片服务:若Stamen的问题持续,可替换为其他稳定的瓦片源,比如OpenStreetMap:
    from cartopy.io.img_tiles import OSM
    tiles = OSM()
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:26:03