From 5a269d880c9590b1558e572d3edfea34b39862c4 Mon Sep 17 00:00:00 2001 From: Greg Lucas Date: Wed, 11 Oct 2023 19:38:39 -0600 Subject: [PATCH] ENH: Add Stadia Maps image tile server class The Stamen tiles are now being served by Stadia Maps. Stadia Maps requires an API key, and has different naming convention for their tiles, so create a new class to interact with the new server. --- docs/source/reference/io.rst | 1 + lib/cartopy/io/img_tiles.py | 63 +++++++++++++++++++++++++++++ lib/cartopy/tests/test_img_tiles.py | 16 ++++++++ 3 files changed, 80 insertions(+) diff --git a/docs/source/reference/io.rst b/docs/source/reference/io.rst index 1eebec5d7..72b69b756 100644 --- a/docs/source/reference/io.rst +++ b/docs/source/reference/io.rst @@ -63,6 +63,7 @@ automatically load the proper tile and resolution depending on the desired domai MapboxTiles OrdnanceSurvey QuadtreeTiles + StadiaMapsTiles Stamen Open Geospatial Consortium (OGC) diff --git a/lib/cartopy/io/img_tiles.py b/lib/cartopy/io/img_tiles.py index 76b939d65..9e82edd32 100644 --- a/lib/cartopy/io/img_tiles.py +++ b/lib/cartopy/io/img_tiles.py @@ -320,6 +320,66 @@ def _image_url(self, tile): return f'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png' +class StadiaMapsTiles(GoogleWTS): + """ + Retrieves tiles from stadiamaps.com. + + For a full reference on the styles available please see + https://docs.stadiamaps.com/themes/. A few of the specific styles + that are made available are ``alidade_smooth``, ``stamen_terrain`` and + ``osm_bright``. + + Using the Stadia Maps API requires including an attribution. Please see + https://docs.stadiamaps.com/attribution/ for details. + + For most styles that means including the following attribution: + + `© Stadia Maps `_ + `© OpenMapTiles `_ + `© OpenStreetMap contributors `_ + + with Stamen styles *additionally* requiring the following attribution: + + `© Stamen Design `_ + + Parameters + ---------- + apikey : str, required + The authentication key provided by Stadia Maps to query their APIs + style : str, optional + Name of the desired style. Defaults to ``alidade_smooth``. + See https://docs.stadiamaps.com/themes/ for a full list of styles. + resolution : str, optional + Resolution of the images to return. Defaults to an empty string, + standard resolution (256x256). You can also specify "@2x" for high + resolution (512x512) tiles. + cache : bool or str, optional + If True, the default cache directory is used. If False, no cache is + used. If a string, the string is used as the path to the cache. + """ + + def __init__(self, + apikey, + style="alidade_smooth", + resolution="", + cache=False): + super().__init__(cache=cache, desired_tile_form="RGBA") + self.apikey = apikey + self.style = style + self.resolution = resolution + if style == "stamen_watercolor": + # Known style that has the jpg extension + self.extension = "jpg" + else: + self.extension = "png" + + def _image_url(self, tile): + x, y, z = tile + return ("http://tiles.stadiamaps.com/tiles/" + f"{self.style}/{z}/{x}/{y}{self.resolution}.{self.extension}" + f"?api_key={self.apikey}") + + class Stamen(GoogleWTS): """ Retrieves tiles from maps.stamen.com. Styles include @@ -351,6 +411,9 @@ class Stamen(GoogleWTS): def __init__(self, style='toner', desired_tile_form=None, cache=False): + warnings.warn("The Stamen styles are no longer served by Stamen and " + "are now served by Stadia Maps. Please use the " + "StadiaMapsTiles class instead.") # preset layer configuration layer_config = { diff --git a/lib/cartopy/tests/test_img_tiles.py b/lib/cartopy/tests/test_img_tiles.py index a7d4f0cd4..792a7be76 100644 --- a/lib/cartopy/tests/test_img_tiles.py +++ b/lib/cartopy/tests/test_img_tiles.py @@ -214,6 +214,22 @@ def test_mapbox_style_tiles_api_url(): assert url_str == exp_url +@pytest.mark.parametrize("style,extension,resolution", [ + ("alidade_smooth", "png", ""), + ("alidade_smooth", "png", "@2x"), + ("stamen_watercolor", "jpg", "")]) +def test_stadia_maps_tiles_api_url(style, extension, resolution): + apikey = 'foo' + tile = [0, 1, 2] + exp_url = ('http://tiles.stadiamaps.com/tiles/' + f'{style}/2/0/1{resolution}.{extension}' + '?api_key=foo') + + sample = cimgt.StadiaMapsTiles(apikey, style=style, resolution=resolution) + url_str = sample._image_url(tile) + assert url_str == exp_url + + def test_ordnance_survey_tile_styles(): """ Tests that setting the Ordnance Survey tile style works as expected.