38 plotly
Uncomment the following line to install leafmap if needed.
# !pip install leafmap
import leafmap.plotlymap as leafmap
If you run into an error saying "FigureWidget - 'mapbox._derived' Value Error" (source), uncomment the following line and run it.
# leafmap.fix_widget_error()
Create an interactive map using default settings.
m = leafmap.Map()
m
Change default setting when creating a map.
Can be one of string from "open-street-map", "carto-positron", "carto-darkmatter", "stamen-terrain", "stamen-toner" or "stamen-watercolor" .
m = leafmap.Map(center=(40, -100), zoom=3, basemap="stamen-terrain", height=500)
m
Set map center and zoom level.
m = leafmap.Map(basemap="stamen-watercolor")
m.set_center(lat=20, lon=0, zoom=2)
m
Print out available basemaps.
leafmap.plotly_basemaps.keys()
dict_keys(['OpenStreetMap', 'ROADMAP', 'SATELLITE', 'TERRAIN', 'HYBRID', 'BasemapAT.basemap', 'BasemapAT.grau', 'BasemapAT.highdpi', 'BasemapAT.orthofoto', 'BasemapAT.overlay', 'BasemapAT.surface', 'BasemapAT.terrain', 'CartoDB.DarkMatter', 'CartoDB.DarkMatterNoLabels', 'CartoDB.DarkMatterOnlyLabels', 'CartoDB.Positron', 'CartoDB.PositronNoLabels', 'CartoDB.PositronOnlyLabels', 'CartoDB.Voyager', 'CartoDB.VoyagerLabelsUnder', 'CartoDB.VoyagerNoLabels', 'CartoDB.VoyagerOnlyLabels', 'CyclOSM', 'Esri.AntarcticBasemap', 'Esri.ArcticOceanBase', 'Esri.ArcticOceanReference', 'Esri.DeLorme', 'Esri.NatGeoWorldMap', 'Esri.OceanBasemap', 'Esri.WorldGrayCanvas', 'Esri.WorldImagery', 'Esri.WorldPhysical', 'Esri.WorldShadedRelief', 'Esri.WorldStreetMap', 'Esri.WorldTerrain', 'Esri.WorldTopoMap', 'FreeMapSK', 'Gaode.Normal', 'Gaode.Satellite', 'GeoportailFrance.orthos', 'GeoportailFrance.parcels', 'GeoportailFrance.plan', 'HikeBike.HikeBike', 'HikeBike.HillShading', 'Hydda.Base', 'Hydda.Full', 'Hydda.RoadsAndLabels', 'JusticeMap.americanIndian', 'JusticeMap.asian', 'JusticeMap.black', 'JusticeMap.hispanic', 'JusticeMap.income', 'JusticeMap.multi', 'JusticeMap.nonWhite', 'JusticeMap.plurality', 'JusticeMap.white', 'MtbMap', 'NASAGIBS.BlueMarble', 'NASAGIBS.BlueMarble3031', 'NASAGIBS.BlueMarble3413', 'NASAGIBS.ModisAquaBands721CR', 'NASAGIBS.ModisAquaTrueColorCR', 'NASAGIBS.ModisTerraAOD', 'NASAGIBS.ModisTerraBands367CR', 'NASAGIBS.ModisTerraBands721CR', 'NASAGIBS.ModisTerraChlorophyll', 'NASAGIBS.ModisTerraLSTDay', 'NASAGIBS.ModisTerraSnowCover', 'NASAGIBS.ModisTerraTrueColorCR', 'NASAGIBS.ViirsEarthAtNight2012', 'NASAGIBS.ViirsTrueColorCR', 'NLS', 'OPNVKarte', 'OneMapSG.Default', 'OneMapSG.Grey', 'OneMapSG.LandLot', 'OneMapSG.Night', 'OneMapSG.Original', 'OpenAIP', 'OpenFireMap', 'OpenRailwayMap', 'OpenSeaMap', 'OpenSnowMap.pistes', 'OpenStreetMap.BZH', 'OpenStreetMap.BlackAndWhite', 'OpenStreetMap.CH', 'OpenStreetMap.DE', 'OpenStreetMap.France', 'OpenStreetMap.HOT', 'OpenStreetMap.Mapnik', 'OpenTopoMap', 'SafeCast', 'Stadia.AlidadeSmooth', 'Stadia.AlidadeSmoothDark', 'Stadia.OSMBright', 'Stadia.Outdoors', 'Stamen.Terrain', 'Stamen.TerrainBackground', 'Stamen.TerrainLabels', 'Stamen.Toner', 'Stamen.TonerBackground', 'Stamen.TonerHybrid', 'Stamen.TonerLabels', 'Stamen.TonerLines', 'Stamen.TonerLite', 'Stamen.TopOSMFeatures', 'Stamen.TopOSMRelief', 'Stamen.Watercolor', 'Strava.All', 'Strava.Ride', 'Strava.Run', 'Strava.Water', 'Strava.Winter', 'SwissFederalGeoportal.JourneyThroughTime', 'SwissFederalGeoportal.NationalMapColor', 'SwissFederalGeoportal.NationalMapGrey', 'SwissFederalGeoportal.SWISSIMAGE', 'USGS.USImagery', 'USGS.USImageryTopo', 'USGS.USTopo', 'WaymarkedTrails.cycling', 'WaymarkedTrails.hiking', 'WaymarkedTrails.mtb', 'WaymarkedTrails.riding', 'WaymarkedTrails.skating', 'WaymarkedTrails.slopes', 'nlmaps.grijs', 'nlmaps.luchtfoto', 'nlmaps.pastel', 'nlmaps.standaard', 'nlmaps.water'])
Add a basemap.
m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m
Add XYZ tile layer.
m = leafmap.Map()
tile_url = "https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}"
m.add_tile_layer(tile_url, name="Google Satellite", attribution="Google", opacity=1.0)
m
Add a mapbox tile layer. You will need a mapbox token. The map style can be Can be "basic", "streets", "outdoors", "light", "dark", "satellite", or "satellite-streets".
import os
# os.environ["MAPBOX_TOKEN"] = "your-mapbox-token"
m = leafmap.Map()
m.add_mapbox_layer(style="streets")
m
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Input In [12], in <cell line: 2>() 1 m = leafmap.Map() ----> 2 m.add_mapbox_layer(style="streets") 3 m File ~/.local/lib/python3.9/site-packages/leafmap/plotlymap.py:215, in Map.add_mapbox_layer(self, style, access_token) 212 if access_token is None: 213 access_token = os.environ.get("MAPBOX_TOKEN") --> 215 self.update_layout( 216 mapbox_style=style, mapbox_layers=[], mapbox_accesstoken=access_token 217 ) File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:1403, in BaseFigure.update_layout(self, dict1, overwrite, **kwargs) 1379 def update_layout(self, dict1=None, overwrite=False, **kwargs): 1380 """ 1381 Update the properties of the figure's layout with a dict and/or with 1382 keyword arguments. (...) 1401 The Figure object that the update_layout method was called on 1402 """ -> 1403 self.layout.update(dict1, overwrite=overwrite, **kwargs) 1404 return self File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:5090, in BasePlotlyType.update(self, dict1, overwrite, **kwargs) 5088 with self.figure.batch_update(): 5089 BaseFigure._perform_update(self, dict1, overwrite=overwrite) -> 5090 BaseFigure._perform_update(self, kwargs, overwrite=overwrite) 5091 else: 5092 BaseFigure._perform_update(self, dict1, overwrite=overwrite) File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:3929, in BaseFigure._perform_update(plotly_obj, update_obj, overwrite) 3926 plotly_obj[key] = val 3927 else: 3928 # Assign non-compound value -> 3929 plotly_obj[key] = val 3931 elif isinstance(plotly_obj, tuple): 3933 if len(update_obj) == 0: 3934 # Nothing to do File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:5818, in BaseLayoutType.__setitem__(self, prop, value) 5815 prop_tuple = BaseFigure._str_to_dict_path(prop) 5816 if len(prop_tuple) != 1 or not isinstance(prop_tuple[0], string_types): 5817 # Let parent handle non-scalar non-string cases -> 5818 super(BaseLayoutHierarchyType, self).__setitem__(prop, value) 5819 return 5820 else: 5821 # Unwrap prop tuple File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:4867, in BasePlotlyType.__setitem__(self, prop, value) 4863 res = res[p] 4865 res._validate = self._validate -> 4867 res[prop[-1]] = value File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:4827, in BasePlotlyType.__setitem__(self, prop, value) 4823 self._set_array_prop(prop, value) 4825 # ### Handle simple property ### 4826 else: -> 4827 self._set_prop(prop, value) 4828 else: 4829 # Make sure properties dict is initialized 4830 self._init_props() File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:5171, in BasePlotlyType._set_prop(self, prop, val) 5169 return 5170 else: -> 5171 raise err 5173 # val is None 5174 # ----------- 5175 if val is None: 5176 # Check if we should send null update File ~/.local/lib/python3.9/site-packages/plotly/basedatatypes.py:5166, in BasePlotlyType._set_prop(self, prop, val) 5163 validator = self._get_validator(prop) 5165 try: -> 5166 val = validator.validate_coerce(val) 5167 except ValueError as err: 5168 if self._skip_invalid: File ~/.local/lib/python3.9/site-packages/_plotly_utils/basevalidators.py:1106, in StringValidator.validate_coerce(self, v) 1103 self.raise_invalid_val(v) 1105 if self.no_blank and len(v) == 0: -> 1106 self.raise_invalid_val(v) 1108 if self.values and v not in self.values: 1109 self.raise_invalid_val(v) File ~/.local/lib/python3.9/site-packages/_plotly_utils/basevalidators.py:289, in BaseValidator.raise_invalid_val(self, v, inds) 286 for i in inds: 287 name += "[" + str(i) + "]" --> 289 raise ValueError( 290 """ 291 Invalid value of type {typ} received for the '{name}' property of {pname} 292 Received value: {v} 293 294 {valid_clr_desc}""".format( 295 name=name, 296 pname=self.parent_name, 297 typ=type_str(v), 298 v=repr(v), 299 valid_clr_desc=self.description(), 300 ) 301 ) ValueError: Invalid value of type 'builtins.str' received for the 'accesstoken' property of layout.mapbox Received value: '' The 'accesstoken' property is a string and must be specified as: - A non-empty string
Remove the modebar in the upper-right corner.
m = leafmap.Map(basemap="stamen-toner")
m
m.clear_controls()
Add more buttons to the modebar.
m = leafmap.Map(basemap="carto-positron")
controls = [
'drawline',
'drawopenpath',
'drawclosedpath',
'drawcircle',
'drawrect',
'eraseshape',
]
m.add_controls(controls)
m
Add Cloud Optimized GeoTIFF.
m = leafmap.Map()
url = 'https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif'
m.add_cog_layer(url, name="Fire (pre-event)")
m
Add a STAC item via HTTP URL.
m = leafmap.Map()
url = 'https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json'
m.add_stac_layer(url, bands=['B3', 'B2', 'B1'], name='False color')
m
Add a STAC item from Microsoft Planetary Computer.
collection = "landsat-8-c2-l2"
item = "LC08_L2SP_047027_20201204_02_T1"
m = leafmap.Map()
m.add_stac_layer(
collection=collection,
item=item,
bands=["SR_B7", "SR_B5", "SR_B4"],
titiler_endpoint="pc",
)
m
--------------------------------------------------------------------------- error Traceback (most recent call last) File ~/.local/lib/python3.9/site-packages/urllib3/response.py:401, in HTTPResponse._decode(self, data, decode_content, flush_decoder) 400 if self._decoder: --> 401 data = self._decoder.decompress(data) 402 except self.DECODER_ERROR_CLASSES as e: error: BrotliDecoderDecompressStream failed while processing the stream During handling of the above exception, another exception occurred: DecodeError Traceback (most recent call last) File ~/.local/lib/python3.9/site-packages/requests/models.py:760, in Response.iter_content.<locals>.generate() 759 try: --> 760 for chunk in self.raw.stream(chunk_size, decode_content=True): 761 yield chunk File ~/.local/lib/python3.9/site-packages/urllib3/response.py:572, in HTTPResponse.stream(self, amt, decode_content) 571 if self.chunked and self.supports_chunked_reads(): --> 572 for line in self.read_chunked(amt, decode_content=decode_content): 573 yield line File ~/.local/lib/python3.9/site-packages/urllib3/response.py:768, in HTTPResponse.read_chunked(self, amt, decode_content) 767 chunk = self._handle_chunk(amt) --> 768 decoded = self._decode( 769 chunk, decode_content=decode_content, flush_decoder=False 770 ) 771 if decoded: File ~/.local/lib/python3.9/site-packages/urllib3/response.py:404, in HTTPResponse._decode(self, data, decode_content, flush_decoder) 403 content_encoding = self.headers.get("content-encoding", "").lower() --> 404 raise DecodeError( 405 "Received response with content-encoding: %s, but " 406 "failed to decode it." % content_encoding, 407 e, 408 ) 409 if flush_decoder: DecodeError: ('Received response with content-encoding: br, but failed to decode it.', error('BrotliDecoderDecompressStream failed while processing the stream')) During handling of the above exception, another exception occurred: ContentDecodingError Traceback (most recent call last) Input In [19], in <cell line: 2>() 1 m = leafmap.Map() ----> 2 m.add_stac_layer( 3 collection=collection, 4 item=item, 5 bands=["SR_B7", "SR_B5", "SR_B4"], 6 titiler_endpoint="pc", 7 ) 8 m File ~/.local/lib/python3.9/site-packages/leafmap/plotlymap.py:439, in Map.add_stac_layer(self, url, collection, item, assets, bands, titiler_endpoint, name, attribution, opacity, **kwargs) 413 def add_stac_layer( 414 self, 415 url=None, (...) 424 **kwargs, 425 ): 426 """Adds a STAC TileLayer to the map. 427 428 Args: (...) 437 opacity (float, optional): The opacity of the layer. Defaults to 1. 438 """ --> 439 tile_url = stac_tile( 440 url, collection, item, assets, bands, titiler_endpoint, **kwargs 441 ) 442 center = stac_center(url, collection, item, titiler_endpoint) 443 self.add_tile_layer(tile_url, name, attribution, opacity) File ~/.local/lib/python3.9/site-packages/leafmap/common.py:1387, in stac_tile(url, collection, item, assets, bands, titiler_endpoint, **kwargs) 1359 # if ("expression" in kwargs) and ("rescale" not in kwargs): 1360 # stats = stac_stats( 1361 # collection=collection, (...) 1378 # "rescale" 1379 # ] = f"{stats[0]['percentile_2']},{stats[0]['percentile_98']}" 1381 if ( 1382 (assets is not None) 1383 and ("asset_expression" not in kwargs) 1384 and ("expression" not in kwargs) 1385 and ("rescale" not in kwargs) 1386 ): -> 1387 stats = stac_stats( 1388 collection=collection, 1389 item=item, 1390 assets=assets, 1391 titiler_endpoint=titiler_endpoint, 1392 ) 1393 if 'detail' not in stats: 1395 percentile_2 = min( 1396 [stats[s][list(stats[s].keys())[0]]["percentile_2"] for s in stats] 1397 ) File ~/.local/lib/python3.9/site-packages/leafmap/common.py:1556, in stac_stats(url, collection, item, assets, titiler_endpoint, **kwargs) 1554 r = requests.get(f"{titiler_endpoint}/stac/statistics", params=kwargs).json() 1555 else: -> 1556 r = requests.get( 1557 titiler_endpoint.url_for_stac_statistics(), params=kwargs 1558 ).json() 1560 return r File ~/.local/lib/python3.9/site-packages/requests/api.py:75, in get(url, params, **kwargs) 64 def get(url, params=None, **kwargs): 65 r"""Sends a GET request. 66 67 :param url: URL for the new :class:`Request` object. (...) 72 :rtype: requests.Response 73 """ ---> 75 return request('get', url, params=params, **kwargs) File ~/.local/lib/python3.9/site-packages/requests/api.py:61, in request(method, url, **kwargs) 57 # By using the 'with' statement we are sure the session is closed, thus we 58 # avoid leaving sockets open which can trigger a ResourceWarning in some 59 # cases, and look like a memory leak in others. 60 with sessions.Session() as session: ---> 61 return session.request(method=method, url=url, **kwargs) File ~/.local/lib/python3.9/site-packages/requests/sessions.py:529, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json) 524 send_kwargs = { 525 'timeout': timeout, 526 'allow_redirects': allow_redirects, 527 } 528 send_kwargs.update(settings) --> 529 resp = self.send(prep, **send_kwargs) 531 return resp File ~/.local/lib/python3.9/site-packages/requests/sessions.py:687, in Session.send(self, request, **kwargs) 684 pass 686 if not stream: --> 687 r.content 689 return r File ~/.local/lib/python3.9/site-packages/requests/models.py:838, in Response.content(self) 836 self._content = None 837 else: --> 838 self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b'' 840 self._content_consumed = True 841 # don't need to release the connection; that's been handled by urllib3 842 # since we exhausted the data. File ~/.local/lib/python3.9/site-packages/requests/models.py:765, in Response.iter_content.<locals>.generate() 763 raise ChunkedEncodingError(e) 764 except DecodeError as e: --> 765 raise ContentDecodingError(e) 766 except ReadTimeoutError as e: 767 raise ConnectionError(e) ContentDecodingError: ('Received response with content-encoding: br, but failed to decode it.', error('BrotliDecoderDecompressStream failed while processing the stream'))
Add a heat map.
url = 'https://raw.githubusercontent.com/plotly/datasets/master/earthquakes-23k.csv'
m = leafmap.Map(basemap="stamen-terrain")
m.add_heatmap(
url, latitude="Latitude", longitude="Longitude", z="Magnitude", name="Earthquake"
)
m
Add a choropleth map.
url = "https://raw.githubusercontent.com/giswqs/leafmap/master/examples/data/countries.geojson"
m = leafmap.Map(basemap="stamen-terrain")
m.add_choropleth_map(url, name="Pop", z="POP_EST", colorscale="Viridis")
m