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.