cartopy icon indicating copy to clipboard operation
cartopy copied to clipboard

WMTS failing on KeyError: 'urn:ogc:def:crs:EPSG::4326'

Open paalge opened this issue 6 years ago • 4 comments

Description

Hi. I'm trying to use a wmts map layer as the background for a plot, but when trying to plot it I fail with the trace given below. I'm unsure if it is me using cartopy wrongly or an issue.

Code to reproduce

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.epsg(32632))
ax.add_wmts('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?request=GetCapabilities&service=wmts',
            layer_name='norgeskart_bakgrunn2')
plt.show()

Traceback

Traceback (most recent call last):
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/backends/backend_gtk3.py", line 307, in idle_draw
    self.draw()
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/backends/backend_gtk3agg.py", line 76, in draw
    self._render_figure(allocation.width, allocation.height)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/backends/backend_gtk3agg.py", line 20, in _render_figure
    backend_agg.FigureCanvasAgg.draw(self)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py", line 388, in draw
    self.figure.draw(self.renderer)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/figure.py", line 1709, in draw
    renderer, self, artists, self.suppressComposite)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/image.py", line 135, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/foo/.local/lib/python3.6/site-packages/Cartopy-0.17.1.dev219_-py3.6-linux-x86_64.egg/cartopy/mpl/geoaxes.py", line 434, in draw
    inframe=inframe)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/axes/_base.py", line 2647, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/image.py", line 135, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/foo/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/foo/.local/lib/python3.6/site-packages/Cartopy-0.17.1.dev219_-py3.6-linux-x86_64.egg/cartopy/mpl/slippy_image_artist.py", line 69, in draw
    target_resolution=(window_extent.width, window_extent.height))
  File "/home/foo/.local/lib/python3.6/site-packages/Cartopy-0.17.1.dev219_-py3.6-linux-x86_64.egg/cartopy/io/ogc_clients.py", line 484, in fetch_raster
    max_pixel_span=max_pixel_span)
  File "/home/foo/.local/lib/python3.6/site-packages/Cartopy-0.17.1.dev219_-py3.6-linux-x86_64.egg/cartopy/io/ogc_clients.py", line 578, in _wmts_images
    meters_per_unit = METERS_PER_UNIT[tile_matrix_set.crs]
KeyError: 'urn:ogc:def:crs:EPSG::4326'
Full environment definition

Operating system

Linus Mint

Cartopy version

'0.17.1.dev219+' a9192f8dde5a2ec36c398dfbea2da0e1dc7f012c

paalge avatar Dec 18 '19 10:12 paalge

Looks like that value is just missing from the internal dictionary:

https://github.com/SciTools/cartopy/blob/bd4b90c4bfec99afd97e8acd29bc05bde29070d8/lib/cartopy/io/ogc_clients.py#L77-L84

I'm not sure if that just hadn't been encountered before or what. Also not entirely sure what the correct value is--I guess matching the existing WGS84?

dopplershift avatar Dec 19 '19 03:12 dopplershift

I would guess it should match WGS84

paalge avatar Dec 20 '19 17:12 paalge

I am having the same issue and am unable to find a solution. Would appreciate any help / pointers if this has been solved somewhere.

Code to reproduce:

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.PlateCarree())
ax.add_wmts('https://tiles.emodnet-bathymetry.eu/wmts/1.0.0/WMTSCapabilities.xml',
            layer_name='baselayer')
plt.show()

Traceback

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/.pyenv/versions/scoot_venv_v2/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)

~/.pyenv/versions/scoot_venv_v2/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))

~/.pyenv/versions/scoot_venv_v2/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':

~/.pyenv/versions/scoot_venv_v2/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)
   2228                        else suppress())
   2229                 with ctx:
-> 2230                     self.figure.draw(renderer)
   2231 
   2232             if bbox_inches:

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     72     @wraps(draw)
     73     def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74         result = draw(artist, renderer, *args, **kwargs)
     75         if renderer._rasterizing:
     76             renderer.stop_rasterizing()

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     49                 renderer.start_filter()
     50 
---> 51             return draw(artist, renderer, *args, **kwargs)
     52         finally:
     53             if artist.get_agg_filter() is not None:

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/figure.py in draw(self, renderer)
   2735 
   2736             self.patch.draw(renderer)
-> 2737             mimage._draw_list_compositing_images(
   2738                 renderer, self, artists, self.suppressComposite)
   2739 

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

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     49                 renderer.start_filter()
     50 
---> 51             return draw(artist, renderer, *args, **kwargs)
     52         finally:
     53             if artist.get_agg_filter() is not None:

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/cartopy/mpl/geoaxes.py in draw(self, renderer, **kwargs)
    556         self._done_img_factory = True
    557 
--> 558         return matplotlib.axes.Axes.draw(self, renderer=renderer, **kwargs)
    559 
    560     def _update_title_position(self, renderer):

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     49                 renderer.start_filter()
     50 
---> 51             return draw(artist, renderer, *args, **kwargs)
     52         finally:
     53             if artist.get_agg_filter() is not None:

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/_api/deprecation.py in wrapper(*inner_args, **inner_kwargs)
    429                          else deprecation_addendum,
    430                 **kwargs)
--> 431         return func(*inner_args, **inner_kwargs)
    432 
    433     return wrapper

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/axes/_base.py in draw(self, renderer, inframe)
   2923             renderer.stop_rasterizing()
   2924 
-> 2925         mimage._draw_list_compositing_images(renderer, self, artists)
   2926 
   2927         renderer.close_group('axes')

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

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     49                 renderer.start_filter()
     50 
---> 51             return draw(artist, renderer, *args, **kwargs)
     52         finally:
     53             if artist.get_agg_filter() is not None:

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/cartopy/mpl/slippy_image_artist.py in draw(self, renderer, *args, **kwargs)
     56         [x1, y1], [x2, y2] = ax.viewLim.get_points()
     57         if not self.user_is_interacting:
---> 58             located_images = self.raster_source.fetch_raster(
     59                 ax.projection, extent=[x1, x2, y1, y2],
     60                 target_resolution=(window_extent.width, window_extent.height))

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/cartopy/io/ogc_clients.py in fetch_raster(self, projection, extent, target_resolution)
    455 
    456             # Fetch a suitable image and its actual extent.
--> 457             wmts_image, wmts_actual_extent = self._wmts_images(
    458                 self.wmts, self.layer, matrix_set_name,
    459                 extent=wmts_desired_extent,

~/.pyenv/versions/scoot_venv_v2/lib/python3.8/site-packages/cartopy/io/ogc_clients.py in _wmts_images(self, wmts, layer, matrix_set_name, extent, max_pixel_span)
    552         tile_matrix_set = wmts.tilematrixsets[matrix_set_name]
    553         tile_matrices = tile_matrix_set.tilematrix.values()
--> 554         meters_per_unit = METERS_PER_UNIT[tile_matrix_set.crs]
    555         tile_matrix = self._choose_matrix(tile_matrices, meters_per_unit,
    556                                           max_pixel_span)

KeyError: 'urn:ogc:def:crs:EPSG::4326'

Operating system Mac OS 12.2 cartopy-0.20.2

mrcape avatar Feb 03 '22 17:02 mrcape

If you know the scaling, something like this will at least set the key for you locally.

from cartopy.io import ogc_clients
ogc_clients.METERS_PER_UNIT['urn:ogc:def:crs:EPSG::4326'] = 1
# or perhaps it needs to equal: METERS_PER_UNIT["urn:ogc:def:crs:OGC:1.3:CRS84"]

PRs to update these values are welcome! It looks like that code hasn't been touched in ~8 years now.

greglucas avatar Feb 03 '22 19:02 greglucas