Week 9 Leafmap
Intorduction of Leafmap¶
Leafmap is a powerful Python package designed for creating, analyzing, and visualizing geospatial data in an interactive way using web maps. Built on top of libraries like folium and ipyleaflet, leafmap simplifies geospatial workflows by integrating with popular Python tools such as pandas and geopandas. It's particularly useful for those who want to visualize geospatial data interactively without needing extensive knowledge of JavaScript.
1. Key features of Leafmap¶
- Creating an interactive map with just one line of code
- Adding XYZ, WMS, and vector tile services
- Displaying vector data
- ...
2. Install leafmap and relevant packages¶
!pip install leafmap rasterio
!pip install git+https://github.com/banesullivan/localtileserver
3. Load basemap¶
import leafmap
import rasterio
# from google.colab import drive
# drive.mount('/content/drive')
3.1 Creating interactive maps¶
- Change basemap without codding
Exercise 1: Customize map's center and zoom level¶
- You can customize maps's center with a tuple or list of latitude and longitude, zoom is an integer
# Set up center level and zoom level
in_map = leafmap.Map(center = , zoom = )
in_map
Adding or Removing Controls¶
By default, the map comes with controls like zoom, fullscreen, scale, attribution, and a toolbar. You can enable or disable these controls by setting parameters such as zoom_control
, fullscreen_control
, scale_control
, attribution_control
, and toolbar_control
to either True or False.
# Set up False to zoom_control
map_control = leafmap.Map(center = [40, -95], zoom = 5, )
map_control
Working with Layers¶
map_lyr = leafmap.Map(center = [40, -95], zoom = 5, zoom_control = False)
map_lyr
map_lyr.layers
Remove layers¶
map_lyr.remove(map_lyr.layers[-1])
map_lyr
Visualizating web-based raster data¶
Adding a WMS Tile Layer and custimized legend to the map¶
Web Map Service (WMS) layers can be added using the add_wms_layer() method. The following code adds a WMS layer from the USGS, centered on the U.S. with a zoom level of 4:
- You can find the layers' information from Layer-name property in WMS
# Get url from USGS WMS Service
# Set up the layers name (Get layers from data)
# Set up format
wms_lyr = leafmap.Map(center=[40, -100], zoom=4)
url = ""
wms_lyr.add_wms_layer(
url=url,
layers="",
name="NLCD_Canopy",
attribution="USGS",
format="",
)
wms_lyr
Add a custom legend¶
Key is the label and value is the color
Each color is represented by a six-digit code that follows this pattern: #RRGGBB, where:
RR is the red component GG is the green component BB is the blue component
# Set up key as classification: Canopy
# Set up value as color: "006400"
legend_dict = {
}
wms_lyr.add_legend(
title="NLCD_Canopy", legend_dict=legend_dict, position = 'bottomleft')
wms_lyr
Adding a WMS Tile Layer and built-in legend to the map¶
legends = leafmap.builtin_legends
for legend in legends:
print(legend)
NLCD:Nation Land Cover Database
# Get URL of NLCD from MRLC
# Set up layers
nlcd_cover = leafmap.Map()
url = ""
nlcd_cover.add_wms_layer(
url,
layers="",
name="NLCD 2016 CONUS Land Cover",
format="image/png",
transparent=True,
)
nlcd_cover.add_legend(builtin_legend="NLCD")
nlcd_cover
Adding a Cloud optimzied GeoTIFF (COG)¶
What is Cloud Optimized GeoTIFFs
Publicly available Cloud Optimized GeoTIFFs:
Get COG link and load in map¶
# Get URL of COG from maxar
cog_lyr = leafmap.Map()
url = ""
cog_lyr.add_cog_layer(url, name="Hurricane Helene")
cog_lyr
Adding second COGs¶
You can add multiple COGS to the same map.
# Get URL of second COG from maxar
url2 = ""
cog_lyr.add_cog_layer(url2, name="")
cog_lyr
Adding multiple COGs¶
urls = [
"https://maxar-opendata.s3.us-west-2.amazonaws.com/events/HurricaneHelene-Oct24/ard/17/031313233023/2024-09-27/1030010105AA2600-visual.tif",
"https://maxar-opendata.s3.us-west-2.amazonaws.com/events/HurricaneHelene-Oct24/ard/17/031313233023/2024-03-29/105001003A08F100-visual.tif",
"https://maxar-opendata.s3.us-west-2.amazonaws.com/events/HurricaneHelene-Oct24/ard/17/031313233022/2024-09-27/1030010105AA2600-visual.tif",
"https://maxar-opendata.s3.us-west-2.amazonaws.com/events/HurricaneHelene-Oct24/ard/17/031313233022/2024-03-29/105001003A08F100-visual.tif",
"https://maxar-opendata.s3.us-west-2.amazonaws.com/events/HurricaneHelene-Oct24/ard/17/031313233021/2024-09-27/1030010105AA2600-visual.tif",
"https://maxar-opendata.s3.us-west-2.amazonaws.com/events/HurricaneHelene-Oct24/ard/17/031313233021/2024-03-29/105001003A08F100-visual.tif"
]
cog_lyr = leafmap.Map()
for i in urls:
cog_lyr.add_cog_layer(i)
cog_lyr
Visualizing Local Raster¶
Download a sample GeoTIFF data
# Check data source: https://open.gishub.org/data/raster/dem.tif to under stand how Github host data
landsat = 'dem.tif'
landsat_url = ""
leafmap.download_file(url=landsat_url, output=landsat, overwrite=True)
raster_lyr = leafmap.Map()
raster_lyr.add_raster(landsat, colormap="terrain", layer_name="DEM")
raster_lyr
Creating a Split Map for Comparison¶
You need to specify left layer and right layer. The layer instance can be the built-in basemap, an HTTP URL to a Cloud Optimized GeoTIFF, or a folium TileLayer instance.
Using basemap¶
leafmap.basemaps.keys()
# Set up left layer as NLCD 2001 CONUS Land Cover
# Set up right layer as NLCD 2021 CONUS Land Cover
split_landcover = leafmap.split_map(
left_layer="",
right_layer="",
left_label="2001",
right_label="2021",
center=[32.78, -96.80],
zoom=9
)
# Get builtin-legend "NLCD"
split_landcover.add_legend( builtin_legend="NLCD")
split_landcover
Using Cloud Optimized GeoTIFF (COG)¶
# url 1: https://github.com/opengeos/data/releases/download/raster/Libya-2023-07-01.tif
# url 2: https://github.com/opengeos/data/releases/download/raster/Libya-2023-09-13.tif
m = leafmap.Map(height=600, center=[39.4948, -108.5492], zoom=12)
url = ""
url2 = ""
m.split_map(url, url2)
m
Using folium TileLayer¶
When using Folium within Leafmap, you can easily access Folium's functionality to display basemaps, add markers, and interact with geospatial data without having to write extensive code.
import folium
import leafmap.foliumap as leafmap_folium
# Set up NLCD 2021 Impervious L48 as left layer
# Set up NLCD 2001 Impervious L48 as left layer
m = leafmap_folium.Map(center=[40, -100], zoom=4)
url1 = ""
url2 = ""
left_layer = folium.WmsTileLayer(
url=url1,
layers="",
name="NLCD 2021",
attr="MRLC",
fmt="image/png",
transparent=True,
)
right_layer = folium.WmsTileLayer(
url=url2,
layers="",
name="NLCD 2001",
attr="MRLC",
fmt="image/png",
transparent=True,
)
left_layer
m.split_map(left_layer, right_layer)
m
3D Visualization¶
MapTiler: MapTiler is a powerful tool designed for creating, hosting, and visualizing maps with custom data.
MapLibre: MapLibre is an open-source mapping library for web and mobile applications, offering an alternative to proprietary platforms. It provides a JavaScript library for rendering interactive maps using vector tiles and WebGL, enabling highly customizable and performant map experiences.
%pip install "leafmap[maplibre]"
import leafmap
import os
import leafmap.maplibregl as leafmap_libre
m = leafmap_libre.Map()
m
m.layer_dict
style = {
"version": 8,
"sources": {
"osm": {
"type": "raster",
"tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"],
"tileSize": 256,
"attribution": "© OpenStreetMap Contributors",
"maxzoom": 19,
},
"terrainSource": {
"type": "raster-dem",
"url": "https://demotiles.maplibre.org/terrain-tiles/tiles.json",
"tileSize": 256,
},
"hillshadeSource": {
"type": "raster-dem",
"url": "https://demotiles.maplibre.org/terrain-tiles/tiles.json",
"tileSize": 256,
},
},
"layers": [
{"id": "osm", "type": "raster", "source": "osm"},
{
"id": "hills",
"type": "hillshade",
"source": "hillshadeSource",
"layout": {"visibility": "visible"},
"paint": {"hillshade-shadow-color": "#473B24"},
},
],
"terrain": {"source": "terrainSource", "exaggeration": 1},
}
m = leafmap_libre.Map(center=[11.39085, 47.27574], zoom=12, pitch=52, style=style)
m.add_layer_control(bg_layers=True)
m
3D Building¶
- Set up account in Maptile
- Get API keys
MAPTILER_KEY = leafmap_libre.get_api_key("maplibre")
MAPTILER_KEY
m = leafmap_libre.Map(
center=[-74.0066, 40.7135], zoom=12, pitch=45, bearing=-17, style="basic-v2"
)
m.add_basemap("Esri.WorldImagery", visible=False)
source = {
"url": f"https://api.maptiler.com/tiles/v3/tiles.json?key={MAPTILER_KEY}",
"type": "vector",
}
layer = {
"id": "3d-buildings",
"source": "openmaptiles",
"source-layer": "building",
"type": "fill-extrusion",
"min-zoom": 15,
"paint": {
"fill-extrusion-color": [
"interpolate",
["linear"],
["get", "render_height"],
0,
"lightgray",
100,
"royalblue",
400,
"lightblue",
],
"fill-extrusion-height": [
"interpolate",
["linear"],
["zoom"],
15,
0,
16,
["get", "render_height"],
],
"fill-extrusion-base": [
"case",
[">=", ["get", "zoom"], 16],
["get", "render_min_height"],
0,
],
},
}
m.add_source("openmaptiles", source)
m.add_layer(layer)
m.add_layer_control()
m
To html¶
3D Building to Html with key¶
m.to_html("3d_building.html", title="Awesome 3D Map", width="100%", height="100%")
m
3D Terrain to Html with restricted key¶
- Set up the allowed HTTP Origins for yoru key
- You can use github domain as the allowed HTTP Origins
# Set MAPTILER_KEY as the private key
# MAPTILER_KEY_PUBLIC as the public key
os.environ["MAPTILER_KEY"] = ""
os.environ["MAPTILER_KEY_PUBLIC"] = ""
m = leafmap_libre.Map(
center=[-122.19861, 46.21168], zoom=13, pitch=60, bearing=150, style="3d-terrain"
)
m.add_layer_control(bg_layers=True)
m.to_html("terrain.html", title="Awesome 3D Map", width="100%", height="100%", replace_key=True)
m