Repository: holoviz/holoviews

Issue:
Replace broken Stamen tiles
See https://github.com/holoviz/holoviz/issues/382


Discussion:

Resolving patch:
diff --git a/holoviews/element/tiles.py b/holoviews/element/tiles.py
--- a/holoviews/element/tiles.py
+++ b/holoviews/element/tiles.py
@@ -85,14 +85,14 @@ def easting_northing_to_lon_lat(easting, northing):
         '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, '
         '&copy; <a href="https://cartodb.com/attributions">CartoDB</a>'
     ),
-    ('stamen', 'net/t') : ( # to match both 'toner' and 'terrain'
-        'Map tiles by <a href="https://stamen.com">Stamen Design</a>, '
+    ('stamen', 'png') : ( # to match both 'toner' and 'terrain'
+        'Map tiles by <a href="https://stamen.com">Stamen Design</a> / <a href="https://stadiamaps.com">Stadia Maps</a>, '
         'under <a href="https://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
         'Data by <a href="https://openstreetmap.org">OpenStreetMap</a>, '
         'under <a href="https://www.openstreetmap.org/copyright">ODbL</a>.'
     ),
-    ('stamen', 'watercolor') : (
-        'Map tiles by <a href="https://stamen.com">Stamen Design</a>, '
+    ('stamen', 'jpg') : (  # watercolor
+        'Map tiles by <a href="https://stamen.com">Stamen Design</a> / <a href="https://stadiamaps.com">Stadia Maps</a>, '
         'under <a href="https://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
         'Data by <a href="https://openstreetmap.org">OpenStreetMap</a>, '
         'under <a href="https://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.'
@@ -132,15 +132,15 @@ def easting_northing_to_lon_lat(easting, northing):
 
 
 # Stamen basemaps
-StamenTerrain = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/terrain/{Z}/{X}/{Y}.png', name="StamenTerrain")
-StamenTerrainRetina = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/terrain/{Z}/{X}/{Y}@2x.png', name="StamenTerrainRetina")
-StamenWatercolor = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/watercolor/{Z}/{X}/{Y}.jpg', name="StamenWatercolor")
-StamenToner = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/toner/{Z}/{X}/{Y}.png', name="StamenToner")
-StamenTonerRetina = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/toner/{Z}/{X}/{Y}@2x.png', name="StamenTonerRetina")
-StamenTonerBackground = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/toner-background/{Z}/{X}/{Y}.png', name="StamenTonerBackground")
-StamenTonerBackgroundRetina = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/toner-background/{Z}/{X}/{Y}@2x.png', name="StamenTonerBackgroundRetina")
-StamenLabels = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/toner-labels/{Z}/{X}/{Y}.png', name="StamenLabels")
-StamenLabelsRetina = lambda: Tiles('https://stamen-tiles.a.ssl.fastly.net/toner-labels/{Z}/{X}/{Y}@2x.png', name="StamenLabelsRetina")
+StamenTerrain = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_terrain/{Z}/{X}/{Y}.png', name="StamenTerrain")
+StamenTerrainRetina = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_terrain/{Z}/{X}/{Y}@2x.png', name="StamenTerrainRetina")
+StamenWatercolor = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_watercolor/{Z}/{X}/{Y}.jpg', name="StamenWatercolor")
+StamenToner = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_toner/{Z}/{X}/{Y}.png', name="StamenToner")
+StamenTonerRetina = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_toner/{Z}/{X}/{Y}@2x.png', name="StamenTonerRetina")
+StamenTonerBackground = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_toner_background/{Z}/{X}/{Y}.png', name="StamenTonerBackground")
+StamenTonerBackgroundRetina = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_toner_background/{Z}/{X}/{Y}@2x.png', name="StamenTonerBackgroundRetina")
+StamenLabels = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_toner_labels/{Z}/{X}/{Y}.png', name="StamenLabels")
+StamenLabelsRetina = lambda: Tiles('https://tiles.stadiamaps.com/tiles/stamen_toner_labels/{Z}/{X}/{Y}@2x.png', name="StamenLabelsRetina")
 
 # Esri maps (see https://server.arcgisonline.com/arcgis/rest/services for the full list)
 EsriImagery = lambda: Tiles('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}.jpg', name="EsriImagery")
@@ -160,4 +160,5 @@ def easting_northing_to_lon_lat(easting, northing):
                 ['ESRI', 'lon_lat_to_easting_northing', 'easting_northing_to_lon_lat',
                  'deprecation_warning', 'wikimedia_replacement']}
 
-tile_sources = {k: v for k, v in _all_tile_sources.items()}
+tile_sources = {k: v for k, v in _all_tile_sources.items() if "Stamen" not in k}
+stamen_sources = {k: v for k, v in _all_tile_sources.items() if "Stamen" in k}


Test patch:
diff --git a/holoviews/tests/plotting/plotly/test_tiles.py b/holoviews/tests/plotting/plotly/test_tiles.py
--- a/holoviews/tests/plotting/plotly/test_tiles.py
+++ b/holoviews/tests/plotting/plotly/test_tiles.py
@@ -102,7 +102,7 @@ def test_raster_layer(self):
         self.assertEqual(layer["sourcetype"], "raster")
         self.assertEqual(layer["minzoom"], 3)
         self.assertEqual(layer["maxzoom"], 7)
-        self.assertEqual(layer["sourceattribution"], _ATTRIBUTIONS[('stamen', 'net/t')])
+        self.assertEqual(layer["sourceattribution"], _ATTRIBUTIONS[('stamen', 'png')])
 
     # xyzservices input
     def test_xyzservices_tileprovider(self):