Skip to content

YouthMappers 2021

image image image image

Interactive Mapping and Geospatial Analysis with Leafmap and Jupyter

This notebook was developed for the 90-min leafmap workshop taking place on November 9, 2021. The workshop is hosted by YouthMappers.

  • Author: Qiusheng Wu
  • Slides: https://gishub.org/ym
  • Streamlit web app: https://streamlit.gishub.org

Launch this notebook to execute code interactively using: - Google Colab: https://gishub.org/ym-colab - Pangeo Binder JupyterLab: https://gishub.org/ym-binder - Pangeo Binder Jupyter Notebook: https://gishub.org/ym-binder-nb

Introduction

Workshop description

Leafmap is a Python package for interactive mapping and geospatial analysis with minimal coding in a Jupyter environment. It is built upon a number of open-source packages, such as folium and ipyleaflet (for creating interactive maps), WhiteboxTools and whiteboxgui (for analyzing geospatial data), and ipywidgets (for designing interactive graphical user interface). The WhiteboxTools library currently contains 480+ tools for advanced geospatial analysis. Leafmap provides many convenient functions for loading and visualizing geospatial data with only one line of code. Users can also use the interactive user interface to load geospatial data without coding. Anyone with a web browser and Internet connection can use leafmap to perform geospatial analysis and data visualization in the cloud with minimal coding. The topics that will be covered in this workshop include:

  • A brief introduction to Jupyter and Colab
  • A brief introduction to leafmap and relevant web resources
  • Creating interactive maps using multiple plotting backends
  • Searching and loading basemaps
  • Loading and visualizing vector/raster data
  • Using Cloud Optimized GeoTIFF (COG) and SpatialTemporal Asset Catalog (STAC)
  • Downloading OpenStreetMap data
  • Loading data from a PostGIS database
  • Creating custom legends and colorbars
  • Creating split-panel maps and linked maps
  • Visualizing Planet global monthly/quarterly mosaic
  • Designing and publishing interactive web apps
  • Performing geospatial analysis (e.g., hydrological analysis) using whiteboxgui

This workshop is intended for scientific programmers, data scientists, geospatial analysts, and concerned citizens of Earth. The attendees are expected to have a basic understanding of Python and the Jupyter ecosystem. Familiarity with Earth science and geospatial datasets is useful but not required. More information about leafmap can be found at https://leafmap.org.

Jupyter keyboard shortcuts

  • Shift+Enter: run cell, select below
  • Ctrl+Enter: : run selected cells
  • Alt+Enter: run cell and insert below
  • Tab: code completion or indent
  • Shift+Tab: tooltip
  • Ctrl+/: comment out code

Set up environment

Required Python packages:

  • leafmap - A Python package for interactive mapping and geospatial analysis with minimal coding in a Jupyter environment.
  • keplergl - A high-performance web-based application for visual exploration of large-scale geolocation data sets.
  • pydeck - High-scale spatial rendering in Python, powered by deck.gl.
  • geopandas - An open source project to make working with geospatial data in python easier.
  • xarray-leaflet - An xarray extension for tiled map plotting.

Use Google Colab

Click the button below to open this notebook in Google Colab and execute code interactively.

image image

1
# !pip install leafmap
1
2
3
import os
import subprocess
import sys
1
2
3
import warnings

warnings.filterwarnings("ignore")

A function for installing Python packages.

1
2
def install(package):
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

Install required Python packages in Google Colab.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
pkgs = [
    "leafmap",
    "geopandas",
    "keplergl",
    "pydeck",
    "xarray_leaflet",
    "osmnx",
    "pygeos",
    "imageio",
    "tifffile",
]
if "google.colab" in sys.modules:
    for pkg in pkgs:
        install(pkg)

Use Pangeo Binder

Click the buttons below to open this notebook in JupyterLab (first button) or Jupyter Notebook (second button) and execute code interactively.

image image

  • JupyterLab: https://gishub.org/ym-binder
  • Jupyter Notebook: https://gishub.org/ym-binder-nb

Use Miniconda/Anaconda

If you have Anaconda or Miniconda installed on your computer, you can install leafmap using the following commands. Leafmap has an optional dependency - geopandas, which can be challenging to install on some computers, especially Windows. It is highly recommended that you create a fresh conda environment to install geopandas and leafmap. Follow the commands below to set up a conda env and install geopandas, leafmap, pydeck, keplergl, and xarray_leaflet.

1
2
3
4
5
6
7
conda create -n geo python=3.8
conda activate geo
conda install geopandas
conda install mamba -c conda-forge
mamba install leafmap keplergl pydeck xarray_leaflet -c conda-forge
mamba install osmnx pygeos imageio tifffile -c conda-forge
jupyter lab
1
2
3
4
try:
    import leafmap
except ImportError:
    install("leafmap")

Create an interactive map

Leafmap has five plotting backends: folium, ipyleaflet, here-map, kepler.gl, and pydeck. Note that the backends do not offer equal functionality. Some interactive functionality in ipyleaflet might not be available in other plotting backends. To use a specific plotting backend, use one of the following:

  • import leafmap.leafmap as leafmap
  • import leafmap.foliumap as leafmap
  • import leafmap.heremap as leafmap
  • import leafmap.kepler as leafmap
  • import leafmap.deck as leafmap

Use ipyleaflet

1
2
3
4
import leafmap

m = leafmap.Map()
m

Use folium

1
2
3
4
import leafmap.foliumap as leafmap

m = leafmap.Map()
m

Use kepler.gl

1
2
3
4
import leafmap.kepler as leafmap

m = leafmap.Map()
m

If you encounter an error saying Error displaying widget: model not found when trying to display the map, you can use m.static_map() as a workaround until this kepler.gl bug has been resolved.

1
# m.static_map(width=1280, height=600)

Use pydeck

1
import leafmap.deck as leafmap
1
2
m = leafmap.Map()
m

Customize the default map

Specify map center and zoom level

1
import leafmap
1
2
m = leafmap.Map(center=(40, -100), zoom=4)  # center=[lat, lon]
m
1
2
m = leafmap.Map(center=(51.5, -0.15), zoom=17)
m

Change map size

1
2
m = leafmap.Map(height="400px", width="800px")
m

Set control visibility

When creating a map, set the following controls to either True or False as appropriate.

  • attribution_control
  • draw_control
  • fullscreen_control
  • layers_control
  • measure_control
  • scale_control
  • toolbar_control
1
2
3
4
5
6
7
m = leafmap.Map(
    draw_control=False,
    measure_control=False,
    fullscreen_control=False,
    attribution_control=False,
)
m

Remove all controls from the map.

1
2
3
m = leafmap.Map()
m.clear()
m

Change basemaps

Specify a Google basemap to use, can be one of ["ROADMAP", "TERRAIN", "SATELLITE", "HYBRID"].

1
import leafmap
1
2
m = leafmap.Map(google_map="TERRAIN")  # HYBRID, ROADMAP, SATELLITE, TERRAIN
m

Add a basemap using the add_basemap() function.

1
2
3
m = leafmap.Map()
m.add_basemap("Esri.NatGeoWorldMap")
m

Print out the list of available basemaps.

1
2
for basemap in leafmap.basemaps:
    print(basemap)

1
2
3
4
5
6
7
m = leafmap.Map()
m.add_tile_layer(
    url="https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
    name="Google Satellite",
    attribution="Google",
)
m

Add tile layers

Add XYZ tile layer

1
import leafmap
1
2
3
4
5
6
7
m = leafmap.Map()
m.add_tile_layer(
    url="https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
    name="Google Satellite",
    attribution="Google",
)
m

Add WMS tile layer

More WMS basemaps can be found at the following websites:

  • USGS National Map: https://viewer.nationalmap.gov/services
  • MRLC NLCD Land Cover data: https://www.mrlc.gov/data-services-page
  • FWS NWI Wetlands data: https://www.fws.gov/wetlands/Data/Web-Map-Services.html
1
2
3
4
5
6
m = leafmap.Map()
naip_url = "https://services.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?"
m.add_wms_layer(
    url=naip_url, layers="0", name="NAIP Imagery", format="image/png", shown=True
)
m

Add xyzservices provider

Add a layer from xyzservices provider object.

1
2
import os
import xyzservices.providers as xyz
1
2
basemap = xyz.OpenTopoMap
basemap
1
2
3
m = leafmap.Map()
m.add_basemap(basemap)
m

Add COG/STAC layers

A Cloud Optimized GeoTIFF (COG) is a regular GeoTIFF file, aimed at being hosted on a HTTP file server, with an internal organization that enables more efficient workflows on the cloud. It does this by leveraging the ability of clients issuing HTTP GET range requests to ask for just the parts of a file they need.

More information about COG can be found at https://www.cogeo.org/in-depth.html

Some publicly available Cloud Optimized GeoTIFFs:

  • https://stacindex.org/
  • https://cloud.google.com/storage/docs/public-datasets/landsat
  • https://www.digitalglobe.com/ecosystem/open-data
  • https://earthexplorer.usgs.gov/

For this demo, we will use data from https://www.maxar.com/open-data/california-colorado-fires for mapping California and Colorado fires. A list of COGs can be found here.

Add COG layer

1
import leafmap
1
2
3
4
5
6
7
m = leafmap.Map()
url = "https://github.com/opengeos/data/releases/download/raster/Libya-2023-07-01.tif"
url2 = "https://github.com/opengeos/data/releases/download/raster/Libya-2023-09-13.tif"

m.add_cog_layer(url, name="Fire (pre-event)")
m.add_cog_layer(url2, name="Fire (post-event)")
m

Add STAC layer

The SpatioTemporal Asset Catalog (STAC) specification provides a common language to describe a range of geospatial information, so it can more easily be indexed and discovered. A 'spatiotemporal asset' is any file that represents information about the earth captured in a certain space and time. The initial focus is primarily remotely-sensed imagery (from satellites, but also planes, drones, balloons, etc), but the core is designed to be extensible to SAR, full motion video, point clouds, hyperspectral, LiDAR and derived data like NDVI, Digital Elevation Models, mosaics, etc. More information about STAC can be found at https://stacspec.org/

Some publicly available SpatioTemporal Asset Catalog (STAC):

  • https://stacindex.org

For this demo, we will use STAC assets from https://stacindex.org/catalogs/spot-orthoimages-canada-2005#/?t=catalogs

1
2
3
4
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 local raster datasets

The add_raster function relies on the xarray_leaflet package and is only available for the ipyleaflet plotting backend. Therefore, Google Colab is not supported. Note that xarray_leaflet does not work properly on Windows (source).

1
2
import os
import leafmap

Download samples raster datasets. More datasets can be downloaded from https://viewer.nationalmap.gov/basic/

1
2
3
4
out_dir = os.getcwd()

landsat = os.path.join(out_dir, "landsat.tif")
dem = os.path.join(out_dir, "dem.tif")

Download a small Landsat imagery.

1
2
3
4
landsat_url = (
    "https://drive.google.com/file/d/1EV38RjNxdwEozjc9m0FcO3LFgAoAX1Uw/view?usp=sharing"
)
leafmap.download_file(landsat_url, "landsat.tif", unzip=False)

Download a small DEM dataset.

1
2
3
4
dem_url = (
    "https://drive.google.com/file/d/1vRkAWQYsLWCi6vcTMk8vLxoXMFbdMFn8/view?usp=sharing"
)
leafmap.download_file(dem_url, "dem.tif", unzip=False)
1
m = leafmap.Map()

Add local raster datasets to the map

More colormap can be found at https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html

1
m.add_raster(dem, colormap="terrain", layer_name="DEM")
1
m.add_raster(landsat, bands=[5, 4, 3], layer_name="Landsat")
1
m

Add legend

Add built-in legend

1
import leafmap

List all available built-in legends.

1
2
3
legends = leafmap.builtin_legends
for legend in legends:
    print(legend)

Add a WMS layer and built-in legend to the map.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
m = leafmap.Map()
url = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2019_Land_Cover_L48/wms?"
m.add_wms_layer(
    url,
    layers="NLCD_2019_Land_Cover_L48",
    name="NLCD 2019 CONUS Land Cover",
    format="image/png",
    transparent=True,
)
m.add_legend(builtin_legend="NLCD")
m

Add U.S. National Wetlands Inventory (NWI). More info at https://www.fws.gov/wetlands.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
m = leafmap.Map(google_map="HYBRID")

url1 = "https://www.fws.gov/wetlands/arcgis/services/Wetlands/MapServer/WMSServer?"
m.add_wms_layer(
    url1, layers="1", format="image/png", transparent=True, name="NWI Wetlands Vector"
)

url2 = "https://www.fws.gov/wetlands/arcgis/services/Wetlands_Raster/ImageServer/WMSServer?"
m.add_wms_layer(
    url2, layers="0", format="image/png", transparent=True, name="NWI Wetlands Raster"
)

m.add_legend(builtin_legend="NWI")
m

Add custom legend

There are two ways you can add custom legends:

  1. Define legend labels and colors
  2. Define legend dictionary

Define legend keys and colors.

1
2
3
4
5
6
7
8
9
m = leafmap.Map()

labels = ["One", "Two", "Three", "Four", "etc"]
# color can be defined using either hex code or RGB (0-255, 0-255, 0-255)
colors = ["#8DD3C7", "#FFFFB3", "#BEBADA", "#FB8072", "#80B1D3"]
# colors = [(255, 0, 0), (127, 255, 0), (127, 18, 25), (36, 70, 180), (96, 68, 123)]

m.add_legend(title="Legend", labels=labels, colors=colors)
m

Define a legend dictionary.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
m = leafmap.Map()

url = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2019_Land_Cover_L48/wms?"
m.add_wms_layer(
    url,
    layers="NLCD_2019_Land_Cover_L48",
    name="NLCD 2019 CONUS Land Cover",
    format="image/png",
    transparent=True,
)

legend_dict = {
    "11 Open Water": "466b9f",
    "12 Perennial Ice/Snow": "d1def8",
    "21 Developed, Open Space": "dec5c5",
    "22 Developed, Low Intensity": "d99282",
    "23 Developed, Medium Intensity": "eb0000",
    "24 Developed High Intensity": "ab0000",
    "31 Barren Land (Rock/Sand/Clay)": "b3ac9f",
    "41 Deciduous Forest": "68ab5f",
    "42 Evergreen Forest": "1c5f2c",
    "43 Mixed Forest": "b5c58f",
    "51 Dwarf Scrub": "af963c",
    "52 Shrub/Scrub": "ccb879",
    "71 Grassland/Herbaceous": "dfdfc2",
    "72 Sedge/Herbaceous": "d1d182",
    "73 Lichens": "a3cc51",
    "74 Moss": "82ba9e",
    "81 Pasture/Hay": "dcd939",
    "82 Cultivated Crops": "ab6c28",
    "90 Woody Wetlands": "b8d9eb",
    "95 Emergent Herbaceous Wetlands": "6c9fb8",
}

m.add_legend(title="NLCD Land Cover Classification", legend_dict=legend_dict)
m

Add colormap

The colormap functionality requires the ipyleaflet plotting backend. Folium is not supported.

1
2
import leafmap
import leafmap.colormaps as cm

Common colormaps

Color palette for DEM data.

1
cm.palettes.dem

Show the DEM palette.

1
cm.plot_colormap(colors=cm.palettes.dem, axis_off=True)

Color palette for NDVI data.

1
cm.palettes.ndvi

Show the NDVI palette.

1
cm.plot_colormap(colors=cm.palettes.ndvi)

Custom colormaps

Specify the number of classes for a palette.

1
cm.get_palette("terrain", n_class=8)

Show the terrain palette with 8 classes.

1
cm.plot_colormap(colors=cm.get_palette("terrain", n_class=8))

Create a palette with custom colors, label, and font size.

1
cm.plot_colormap(colors=["red", "green", "blue"], label="Temperature", font_size=12)

Create a discrete color palette.

1
2
3
cm.plot_colormap(
    colors=["red", "green", "blue"], discrete=True, label="Temperature", font_size=12
)

Specify the width and height for the palette.

1
2
3
4
5
6
7
8
9
cm.plot_colormap(
    "terrain",
    label="Elevation",
    width=8.0,
    height=0.4,
    orientation="horizontal",
    vmin=0,
    vmax=1000,
)

Change the orentation of the colormap to be vertical.

1
2
3
4
5
6
7
8
9
cm.plot_colormap(
    "terrain",
    label="Elevation",
    width=0.4,
    height=4,
    orientation="vertical",
    vmin=0,
    vmax=1000,
)

Horizontal colormap

Add a horizontal colorbar to an interactive map.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m.add_colormap(
    "terrain",
    label="Elevation",
    width=8.0,
    height=0.4,
    orientation="horizontal",
    vmin=0,
    vmax=4000,
)
m

Vertical colormap

Add a vertical colorbar to an interactive map.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m.add_colormap(
    "terrain",
    label="Elevation",
    width=0.4,
    height=4,
    orientation="vertical",
    vmin=0,
    vmax=4000,
)
m

List of available colormaps

1
cm.plot_colormaps(width=12, height=0.4)

Add vector datasets

Add CSV

Read a CSV as a Pandas DataFrame.

1
2
import os
import leafmap
1
2
3
in_csv = "https://raw.githubusercontent.com/opengeos/data/main/world/world_cities.csv"
df = leafmap.csv_to_df(in_csv)
df

Create a point layer from a CSV file containing lat/long information.

1
2
3
m = leafmap.Map()
m.add_xy_data(in_csv, x="longitude", y="latitude", layer_name="World Cities")
m

Set the output directory.

1
2
out_dir = os.getcwd()
out_shp = os.path.join(out_dir, "world_cities.shp")

Convert a CSV file containing lat/long information to a shapefile.

1
leafmap.csv_to_shp(in_csv, out_shp)

Convert a CSV file containing lat/long information to a GeoJSON.

1
2
out_geojson = os.path.join(out_dir, "world_cities.geojson")
leafmap.csv_to_geojson(in_csv, out_geojson)

Convert a CSV file containing lat/long information to a GeoPandas GeoDataFrame.

1
2
gdf = leafmap.csv_to_gdf(in_csv)
gdf

Add GeoJSON

Add a GeoJSON to the map.

1
2
3
4
5
6
m = leafmap.Map(center=[0, 0], zoom=2)
in_geojson = (
    "https://github.com/opengeos/datasets/releases/download/vector/cables.geojson"
)
m.add_geojson(in_geojson, layer_name="Cable lines", info_mode="on_hover")
m

Add a GeoJSON with random filled color to the map.

1
2
3
4
5
6
m = leafmap.Map(center=[0, 0], zoom=2)
url = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/countries.geojson"
m.add_geojson(
    url, layer_name="Countries", fill_colors=["red", "yellow", "green", "orange"]
)
m

Use the style_callback function for assigning a random color to each polygon.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import random

m = leafmap.Map(center=[0, 0], zoom=2)

url = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/countries.geojson"


def random_color(feature):
    return {
        "color": "black",
        "fillColor": random.choice(["red", "yellow", "green", "orange"]),
    }


m.add_geojson(url, layer_name="Countries", style_callback=random_color)
m

Use custom style and hover_style functions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
m = leafmap.Map(center=[0, 0], zoom=2)
url = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/countries.geojson"
style = {
    "stroke": True,
    "color": "#0000ff",
    "weight": 2,
    "opacity": 1,
    "fill": True,
    "fillColor": "#0000ff",
    "fillOpacity": 0.1,
}
hover_style = {"fillOpacity": 0.7}
m.add_geojson(url, layer_name="Countries", style=style, hover_style=hover_style)
m

Add shapefile

1
2
3
4
m = leafmap.Map(center=[0, 0], zoom=2)
in_shp = "https://github.com/opengeos/leafmap/raw/master/examples/data/countries.zip"
m.add_shp(in_shp, layer_name="Countries")
m

Add KML

1
import leafmap
1
2
3
4
m = leafmap.Map()
in_kml = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/us_states.kml"
m.add_kml(in_kml, layer_name="US States KML")
m

Add GeoDataFrame

1
import geopandas as gpd
1
2
3
4
5
6
m = leafmap.Map()
gdf = gpd.read_file(
    "https://github.com/opengeos/datasets/releases/download/vector/cables.geojson"
)
m.add_gdf(gdf, layer_name="Cable lines")
m

Read the GeoPandas sample dataset as a GeoDataFrame.

1
2
3
4
5
path_to_data = (
    "https://github.com/opengeos/datasets/releases/download/vector/nybb.geojson"
)
gdf = gpd.read_file(path_to_data)
gdf
1
2
3
m = leafmap.Map()
m.add_gdf(gdf, layer_name="New York boroughs", fill_colors=["red", "green", "blue"])
m

Add point layer

Add a point layer using the interactive GUI.

1
2
m = leafmap.Map()
m

Add a point layer programmatically.

1
2
3
4
m = leafmap.Map()
url = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/us_cities.geojson"
m.add_point_layer(url, popup=["name", "pop_max"], layer_name="US Cities")
m

Add vector

The add_vector function supports any vector data format supported by GeoPandas.

1
2
3
4
5
6
m = leafmap.Map(center=[0, 0], zoom=2)
url = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/countries.geojson"
m.add_vector(
    url, layer_name="Countries", fill_colors=["red", "yellow", "green", "orange"]
)
m

Download OSM data

OSM from geocode

Add OSM data of place(s) by name or ID to the map. Note that the leafmap custom layer control does not support GeoJSON, we need to use the ipyleaflet built-in layer control.

1
import leafmap
1
2
3
m = leafmap.Map(toolbar_control=False, layers_control=True)
m.add_osm_from_geocode("New York City", layer_name="NYC")
m
1
2
3
m = leafmap.Map(toolbar_control=False, layers_control=True)
m.add_osm_from_geocode("Chicago, Illinois", layer_name="Chicago, IL")
m

OSM from place

Add OSM entities within boundaries of geocodable place(s) to the map.

Show OSM feature tags. https://wiki.openstreetmap.org/wiki/Map_features

1
# leafmap.osm_tags_list()

OSM from address

1
2
3
4
5
m = leafmap.Map(toolbar_control=False, layers_control=True)
m.add_osm_from_address(
    address="New York City", tags={"amenity": "bar"}, dist=1500, layer_name="NYC bars"
)
m
1
2
3
4
5
6
7
8
m = leafmap.Map(toolbar_control=False, layers_control=True)
m.add_osm_from_address(
    address="New York City",
    tags={"landuse": ["retail", "commercial"], "building": True},
    dist=1000,
    layer_name="NYC buildings",
)
m

OSM from bbox

1
2
3
4
5
6
m = leafmap.Map(toolbar_control=False, layers_control=True)
north, south, east, west = 40.7551, 40.7454, -73.9738, -73.9965
m.add_osm_from_bbox(
    north, south, east, west, tags={"amenity": "bar"}, layer_name="NYC bars"
)
m

OSM from point

Add OSM entities within some distance N, S, E, W of a point to the map.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
m = leafmap.Map(
    center=[46.7808, -96.0156], zoom=12, toolbar_control=False, layers_control=True
)
m.add_osm_from_point(
    center_point=(46.7808, -96.0156),
    tags={"natural": "water"},
    dist=10000,
    layer_name="Lakes",
)
m
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
m = leafmap.Map(
    center=[39.9170, 116.3908], zoom=15, toolbar_control=False, layers_control=True
)
m.add_osm_from_point(
    center_point=(39.9170, 116.3908),
    tags={"building": True, "natural": "water"},
    dist=1000,
    layer_name="Beijing",
)
m

OSM from view

Add OSM entities within the current map view to the map.

1
2
3
m = leafmap.Map(toolbar_control=False, layers_control=True)
m.set_center(-73.9854, 40.7500, 16)
m
1
m.add_osm_from_view(tags={"amenity": "bar", "building": True}, layer_name="New York")

Create a GeoPandas GeoDataFrame from place.

1
2
gdf = leafmap.osm_gdf_from_place("New York City", tags={"amenity": "bar"})
gdf

Use WhiteboxTools

Use the built-in toolbox to perform geospatial analysis. For example, you can perform depression filling using the sample DEM dataset downloaded in the above step.

1
2
3
import os
import leafmap
import urllib.request

Download a sample DEM dataset.

1
url = "https://github.com/opengeos/whitebox-python/raw/master/whitebox/testdata/DEM.tif"
1
urllib.request.urlretrieve(url, "dem.tif")
1
2
m = leafmap.Map()
m

Display the toolbox using the default mode.

1
leafmap.whiteboxgui()

Display the toolbox using the collapsible tree mode. Note that the tree mode does not support Google Colab.

1
leafmap.whiteboxgui(tree=True)

Perform geospatial analysis using the whitebox package.

1
2
import os
import whitebox
1
2
wbt = whitebox.WhiteboxTools()
wbt.verbose = False
1
2
data_dir = os.getcwd()
wbt.set_working_dir(data_dir)
1
2
3
wbt.feature_preserving_smoothing("dem.tif", "smoothed.tif", filter=9)
wbt.breach_depressions("smoothed.tif", "breached.tif")
wbt.d_inf_flow_accumulation("breached.tif", "flow_accum.tif")
1
2
3
4
import matplotlib.pyplot as plt
import imageio

%matplotlib inline
1
2
3
4
original = imageio.imread(os.path.join(data_dir, "dem.tif"))
smoothed = imageio.imread(os.path.join(data_dir, "smoothed.tif"))
breached = imageio.imread(os.path.join(data_dir, "breached.tif"))
flow_accum = imageio.imread(os.path.join(data_dir, "flow_accum.tif"))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
fig = plt.figure(figsize=(16, 11))

ax1 = fig.add_subplot(2, 2, 1)
ax1.set_title("Original DEM")
plt.imshow(original)

ax2 = fig.add_subplot(2, 2, 2)
ax2.set_title("Smoothed DEM")
plt.imshow(smoothed)

ax3 = fig.add_subplot(2, 2, 3)
ax3.set_title("Breached DEM")
plt.imshow(breached)

ax4 = fig.add_subplot(2, 2, 4)
ax4.set_title("Flow Accumulation")
plt.imshow(flow_accum)

plt.show()
1
import leafmap
1
2
for basemap in leafmap.basemaps:
    print(basemap)
1
layers = list(leafmap.basemaps.keys())[17:117]
1
leafmap.linked_maps(rows=20, cols=5, height="200px", layers=layers, labels=layers)

Create linked map

1
import leafmap
1
leafmap.basemaps.keys()
1
2
layers = ["ROADMAP", "HYBRID"]
leafmap.linked_maps(rows=1, cols=2, height="400px", layers=layers)
1
2
layers = ["Esri.WorldTopoMap", "OpenTopoMap"]
leafmap.linked_maps(rows=1, cols=2, height="400px", layers=layers)

Create a 2 * 2 linked map to visualize land cover change. Specify the center and zoom parameters to change the default map center and zoom level.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
layers = [str(f"NLCD {year} CONUS Land Cover") for year in [2001, 2006, 2011, 2016]]
labels = [str(f"NLCD {year}") for year in [2001, 2006, 2011, 2016]]
leafmap.linked_maps(
    rows=2,
    cols=2,
    height="300px",
    layers=layers,
    labels=labels,
    center=[36.1, -115.2],
    zoom=9,
)

Create split-panel map

Create a split-panel map by specifying the left_layer and right_layer, which can be chosen from the basemap names, or any custom XYZ tile layer.

1
import leafmap
1
leafmap.split_map(left_layer="ROADMAP", right_layer="HYBRID")

Hide the zoom control from the map.

1
2
3
leafmap.split_map(
    left_layer="Esri.WorldTopoMap", right_layer="OpenTopoMap", zoom_control=False
)

Add labels to the map and change the default map center and zoom level.

1
2
3
4
5
6
7
8
9
leafmap.split_map(
    left_layer="NLCD 2001 CONUS Land Cover",
    right_layer="NLCD 2019 CONUS Land Cover",
    left_label="2001",
    right_label="2019",
    label_position="bottom",
    center=[36.1, -114.9],
    zoom=10,
)

Create heat map

Specify the file path to the CSV. It can either be a file locally or on the Internet.

1
import leafmap
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
m = leafmap.Map(layers_control=True)
in_csv = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/world_cities.csv"
m.add_heatmap(
    in_csv,
    latitude="latitude",
    longitude="longitude",
    value="pop_max",
    name="Heat map",
    radius=20,
)
m

Use the folium plotting backend.

1
from leafmap import foliumap
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
m = foliumap.Map()
in_csv = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/world_cities.csv"
m.add_heatmap(
    in_csv,
    latitude="latitude",
    longitude="longitude",
    value="pop_max",
    name="Heat map",
    radius=20,
)
1
2
3
4
colors = ["blue", "lime", "red"]
m.add_colorbar(colors=colors, vmin=0, vmax=10000)
m.add_title("World Population Heat Map", font_size="20px", align="center")
m

Save map to HTML

1
import leafmap
1
2
3
m = leafmap.Map()
m.add_basemap("Esri.NatGeoWorldMap")
m

Specify the output HTML file name to save the map as a web page.

1
m.to_html("mymap.html")

If the output HTML file name is not provided, the function will return a string containing contain the source code of the HTML file.

1
html = m.to_html()
1
# print(html)

Use kepler plotting backend

1
import leafmap.kepler as leafmap

Create an interactive map

Create an interactive map. You can specify various parameters to initialize the map, such as center, zoom, height, and widescreen.

1
2
m = leafmap.Map(center=[40, -100], zoom=2, height=600, widescreen=False)
m

If you encounter an error saying Error displaying widget: model not found when trying to display the map, you can use m.static_map() as a workaround until this kepler.gl bug has been resolved.

1
# m.static_map(width=1280, height=600)

Add CSV

Add a CSV to the map. If you have a map config file, you can directly apply config to the map.

1
2
3
4
5
m = leafmap.Map(center=[37.7621, -122.4143], zoom=12)
in_csv = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/hex_data.csv"
config = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/hex_config.json"
m.add_csv(in_csv, layer_name="hex_data", config=config)
m
1
m.static_map(width=1280, height=600)

Save map config

Save the map configuration as a JSON file.

1
m.save_config("cache/config.json")

Save map as html

Save the map to an interactive html.

1
m.to_html(outfile="cache/kepler_hex.html")

Add GeoJONS

Add a GeoJSON with US state boundaries to the map.

1
2
3
4
m = leafmap.Map(center=[50, -110], zoom=2)
polygons = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/us_states.json"
m.add_geojson(polygons, layer_name="Countries")
m
1
m.static_map(width=1280, height=600)

Add shapefile

Add a shapefile to the map.

1
2
3
4
m = leafmap.Map(center=[20, 0], zoom=1)
in_shp = "https://github.com/opengeos/leafmap/raw/master/examples/data/countries.zip"
m.add_shp(in_shp, "Countries")
m
1
m.static_map(width=1280, height=600)

Add GeoDataFrame

Add a GeoPandas GeoDataFrame to the map.

1
import geopandas as gpd
1
2
3
4
gdf = gpd.read_file(
    "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/world_cities.geojson"
)
gdf
1
2
3
m = leafmap.Map(center=[20, 0], zoom=1)
m.add_gdf(gdf, "World cities")
m
1
# m.static_map(width=1280, height=600)

Use planet imagery

First, you need to sign up a Planet account and get an API key. See https://developers.planet.com/quickstart/apis. Uncomment the following line to pass in your API key.

1
2
import os
import leafmap
1
2
if os.environ.get("PLANET_API_KEY") is None:
    os.environ["PLANET_API_KEY"] = "your-api-key"
1
quarterly_tiles = leafmap.planet_quarterly_tiles()
1
2
for tile in quarterly_tiles:
    print(tile)
1
monthly_tiles = leafmap.planet_monthly_tiles()
1
2
for tile in monthly_tiles:
    print(tile)

Add a Planet monthly mosaic by specifying year and month.

1
2
3
m = leafmap.Map()
m.add_planet_by_month(year=2020, month=8)
m

Add a Planet quarterly mosaic by specifying year and quarter.

1
2
3
m = leafmap.Map()
m.add_planet_by_quarter(year=2019, quarter=2)
m

Use timeseries inspector

1
2
import os
import leafmap
1
2
if os.environ.get("PLANET_API_KEY") is None:
    os.environ["PLANET_API_KEY"] = "your-api-key"
1
tiles = leafmap.planet_tiles()
1
leafmap.ts_inspector(tiles, center=[40, -100], zoom=4)

Use time slider

Use the time slider to visualize Planet quarterly mosaic.

1
2
import os
import leafmap
1
2
if os.environ.get("PLANET_API_KEY") is None:
    os.environ["PLANET_API_KEY"] = "your-api-key"

Specify the map center and zoom level.

1
2
m = leafmap.Map(center=[38.2659, -103.2447], zoom=13)
m

Use the time slider to visualize Planet quarterly mosaic.

1
2
3
4
m = leafmap.Map()
layers_dict = leafmap.planet_quarterly_tiles()
m.add_time_slider(layers_dict, time_interval=1)
m

Use the time slider to visualize basemaps.

1
2
3
4
5
m = leafmap.Map()
m.clear_layers()
layers_dict = leafmap.basemap_xyz_tiles()
m.add_time_slider(layers_dict, time_interval=1)
m