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语句前添加瓦片尺寸适配代码:
需提前安装Pillow库: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]))pip install pillow - 切换瓦片服务:若Stamen的问题持续,可替换为其他稳定的瓦片源,比如OpenStreetMap:
from cartopy.io.img_tiles import OSM tiles = OSM()
内容的提问来源于stack exchange,提问作者Alex Thompson
相关产品推荐
相关产品推荐

