Leafmap

Contents

14. Leafmap#

Open In Colab

14.1. Overview#

This lecture offers a comprehensive introduction to Leafmap, a powerful, open-source Python package for creating, managing, and analyzing interactive geospatial maps. Leafmap simplifies working with geospatial data by providing a high-level, Pythonic interface that integrates seamlessly with Jupyter environments, such as Google Colab, Jupyter Notebook, and JupyterLab.

Built on top of several well-established libraries like folium, ipyleaflet, maplibre, bokeh, pydeck, kepler.gl, and plotly, Leafmap extends their functionalities with a unified API. This extension streamlines the process of visualizing and analyzing geospatial data interactively, minimizing the amount of coding required.

In this lecture, we will explore Leafmap’s key features, including how to create interactive maps, add and customize basemaps, visualize both vector and raster data, and edit vector layers. Each section provides practical examples and guidance essential for using Leafmap effectively in GIS programming tasks.

14.2. Learning Objectives#

By the end of this lecture, you will be able to:

  • Create and customize interactive maps using Leafmap.

  • Add and configure different basemap layers.

  • Visualize and style vector and raster geospatial data.

  • Edit vector data directly on interactive maps.

  • Search for open geospatial datasets and incorporate them into your maps.

14.3. Install leafmap#

To install Leafmap, uncomment the following line and run the cell.

# %pip install -U leafmap

14.4. Import libraries#

To get started, import the necessary libraries.

import leafmap

Leafmap supports multiple plotting backends, including folium, ipyleaflet, maplibre, bokeh, pydeck, keplergl, and plotly. The default plotting backend is ipyleaflet, offering the most extensive features.

To switch the plotting backend, uncomment one of the following lines and run the cell:

# import leafmap.foliumap as leafmap
# import leafmap.bokehmap as leafmap
# import leafmap.maplibregl as leafmap
# import leafmap.deck as leafmap
# import leafmap.kepler as leafmap
# import leafmap.plotlymap as leafmap

14.5. Creating interactive maps#

Leafmap provides a high-level, Pythonic interface for creating interactive maps. You can create a basic interactive map by calling the Map function. The default basemap is OpenStreetMap.

m = leafmap.Map()
m

14.5.1. Customizing the Map#

You can customize the map’s center, zoom level, and height. The center takes a tuple of latitude and longitude, zoom is an integer, and height specifies the map height in pixels. The example below centers the map on the U.S. with a zoom level of 4 and a height of 600 pixels:

m = leafmap.Map(center=(40, -100), zoom=4, height="600px")
m

14.5.2. Adding or Removing Controls#

By default, the map includes controls such as zoom, fullscreen, scale, attribution, and toolbar. You can toggle these controls using parameters like zoom_control, fullscreen_control, scale_control, attribution_control, and toolbar_control parameters to True or False. The example below disables all controls:

m = leafmap.Map(
    zoom_control=False,
    draw_control=False,
    scale_control=False,
    fullscreen_control=False,
    attribution_control=False,
    toolbar_control=False,
)
m

To add a search control to the map, use the m.add_search_control() method. The search control allows users to search for places and zoom to them. The example below adds a search control to the map:

url = "https://nominatim.openstreetmap.org/search?format=json&q={s}"
m.add_search_control(url, zoom=10, position="topleft")

14.5.3. Working with Layers#

You can access the layers on the map using the layers attribute:

m.layers
(TileLayer(attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', base=True, max_zoom=19, min_zoom=1, name='OpenStreetMap', options=['attribution', 'bounds', 'detect_retina', 'max_native_zoom', 'max_zoom', 'min_native_zoom', 'min_zoom', 'no_wrap', 'tile_size', 'tms', 'zoom_offset'], url='https://tile.openstreetmap.org/{z}/{x}/{y}.png'),)

To add or remove layers, use the add and remove methods. For example, to remove the last layer:

m.remove(m.layers[-1])

14.5.4. Clearing Controls and Layers#

You can clear all controls and layers from the map with clear_controls and clear_layers methods. First, create a map:

m = leafmap.Map()
m

Then, remove all controls:

m.clear_controls()

And clear all layers:

m.clear_layers()

14.6. Changing Basemaps#

You can easily change the basemap of a map. For example, the following code adds the OpenTopoMap basemap:

m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m

To change basemap interactively, add the basemap control to the map with the add_basemap_gui() method:

m = leafmap.Map()
m.add_basemap_gui()
m

14.6.1. Adding an XYZ Tile Layer#

To add custom XYZ tile layers, you can use the add_tile_layer() method. The example below adds a Google Satellite layer using an XYZ URL template:

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

14.6.2. Adding a WMS Tile Layer#

Web Map Service (WMS) layers can be added using the add_wms_layer() method. The following code adds a WMS layer of NAIP Imagery from the USGS, centered on the U.S. with a zoom level of 4:

m = leafmap.Map(center=[40, -100], zoom=4)
url = "https://imagery.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?"
m.add_wms_layer(
    url=url,
    layers="USGSNAIPImagery:FalseColorComposite",
    name="NAIP",
    attribution="USGS",
    format="image/png",
    shown=True,
)
m

14.6.3. Adding a Legend to a Map#

To provide better context for the data layers, you can add a legend to your map. In this example, we add a WMS layer displaying the 2021 NLCD land cover data and a corresponding legend to explain the land cover types:

m = leafmap.Map(center=[40, -100], zoom=4)
m.add_basemap("Esri.WorldImagery")
url = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2021_Land_Cover_L48/wms?"
m.add_wms_layer(
    url=url,
    layers="NLCD_2021_Land_Cover_L48",
    name="NLCD 2021",
    attribution="MRLC",
    format="image/png",
    shown=True,
)
m.add_legend(title="NLCD Land Cover Type", builtin_legend="NLCD")
m

14.6.4. Adding a Colorbar to Visualize Data#

If you need to visualize continuous data like elevation, you can add a colorbar to the map. The example below shows how to add a colorbar with a terrain colormap for elevation, ranging from 0 to 4000 meters:

m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m.add_colormap(
    "terrain",
    label="Elevation",
    orientation="horizontal",
    vmin=0,
    vmax=4000,
)
m

Each of these sections demonstrates different features of the Leafmap library, allowing you to customize maps by adding basemaps, XYZ tiles, WMS layers, legends, and colorbars to enhance map visualization.

14.7. Visualizing Vector Data#

Leafmap makes it easy to visualize various vector data formats such as GeoJSON, Shapefile, GeoPackage, and others supported by GeoPandas. The following examples demonstrate different ways to add vector data to your map.

14.7.1. Adding a Marker#

You can add individual markers to the map at specific locations. In this example, a draggable marker is placed at the given latitude and longitude.

m = leafmap.Map()
location = [40, -100]
m.add_marker(location, draggable=True)
m

14.7.2. Adding Multiple Markers#

To add multiple markers at once, use the add_markers() method. This example places markers at three different locations:

m = leafmap.Map()
m.add_markers(markers=[[40, -100], [45, -110], [50, -120]])
m

14.7.3. Adding Marker Clusters#

For a large number of points, you can group them into clusters. This method reduces map clutter by aggregating nearby points. The example below uses a CSV file of world cities to create marker clusters:

m = leafmap.Map()
url = "https://github.com/opengeos/datasets/releases/download/world/world_cities.csv"
m.add_marker_cluster(url, x="longitude", y="latitude", layer_name="World cities")
m

14.7.4. Customizing Markers#

Markers can be customized with colors, icons, and labels. The following example customizes points from a CSV file of U.S. cities, using different icons and adding a legend:

m = leafmap.Map(center=[40, -100], zoom=4)
cities = "https://github.com/opengeos/datasets/releases/download/us/cities.csv"
regions = "https://github.com/opengeos/datasets/releases/download/us/us_regions.geojson"
m.add_geojson(regions, layer_name="US Regions")
m.add_points_from_xy(
    cities,
    x="longitude",
    y="latitude",
    color_column="region",
    icon_names=["gear", "map", "leaf", "globe"],
    spin=True,
    add_legend=True,
)
m

14.7.5. Visualizing Polylines#

Polyline visualization is useful for displaying linear features such as roads or pipelines. In this example, a GeoJSON file containing submarine cable lines is added to the map:

m = leafmap.Map(center=[20, 0], zoom=2)
data = "https://github.com/opengeos/datasets/releases/download/vector/cables.geojson"
m.add_vector(data, layer_name="Cable lines", info_mode="on_hover")
m

14.7.5.1. Customizing Polyline Styles#

You can further customize polylines with a style callback function. This example dynamically changes the color and weight of each polyline based on its properties:

m = leafmap.Map(center=[20, 0], zoom=2)
m.add_basemap("CartoDB.DarkMatter")
data = "https://github.com/opengeos/datasets/releases/download/vector/cables.geojson"
callback = lambda feat: {"color": feat["properties"]["color"], "weight": 1}
m.add_vector(data, layer_name="Cable lines", style_callback=callback)
m

14.7.6. Visualizing Polygons#

To visualize polygon features, you can use the add_vector() method. In this example, a GeoJSON file of New York City buildings is added and the map automatically zooms to the layer’s extent:

m = leafmap.Map()
url = "https://github.com/opengeos/datasets/releases/download/places/nyc_buildings.geojson"
m.add_vector(url, layer_name="NYC Buildings", zoom_to_layer=True)
m

14.7.7. Visualizing GeoPandas GeoDataFrames#

You can directly visualize GeoPandas GeoDataFrames on the map. In this example, a GeoDataFrame containing building footprints from Las Vegas is displayed with custom styling:

import geopandas as gpd
url = "https://github.com/opengeos/datasets/releases/download/places/las_vegas_buildings.geojson"
gdf = gpd.read_file(url)
gdf.head()
id height geometry
0 08b2986b81b34fff0200120c6aabf673 2.539160 POLYGON ((-115.20758 36.11913, -115.20754 36.1...
1 08b2986b81b34fff0200ce30fa61746d 3.209284 POLYGON ((-115.20756 36.11929, -115.20776 36.1...
2 08b2986b81b34fff0200b898b488ab8b 2.691431 POLYGON ((-115.20759 36.11932, -115.20759 36.1...
3 08b2986b81b34fff02004b957b4cd490 2.795901 POLYGON ((-115.20762 36.11953, -115.20775 36.1...
4 08b2986b81869fff020091d66f33d09b 2.649764 POLYGON ((-115.20727 36.11898, -115.20727 36.1...

You can use the GeoDataFrame.explore() method to visualize the data interactively, which utilizes the folium library. The example below displays the building footprints interactively:

gdf.explore()
Make this Notebook Trusted to load map: File -> Trust Notebook

To display the GeoDataFrame using Leaflet, use the add_gdf() method. The following code adds the building footprints to the map:

m = leafmap.Map()
m.add_basemap("HYBRID")
style = {"color": "red", "fillColor": "red", "fillOpacity": 0.1, "weight": 2}
m.add_gdf(gdf, style=style, layer_name="Las Vegas Buildings", zoom_to_layer=True)
m

14.8. Creating Choropleth Maps#

Choropleth maps are useful for visualizing data distributions. The add_data() method allows you to create choropleth maps from various vector formats. Below is an example that visualizes population data using the “Quantiles” classification scheme:

m = leafmap.Map()
data = "https://raw.githubusercontent.com/opengeos/leafmap/master/docs/data/countries.geojson"
m.add_data(
    data, column="POP_EST", scheme="Quantiles", cmap="Blues", legend_title="Population"
)
m

You can also use different classification schemes like “EqualInterval” for different data visualizations:

m = leafmap.Map()
m.add_data(
    data,
    column="POP_EST",
    scheme="EqualInterval",
    cmap="Blues",
    legend_title="Population",
)
m

14.9. Visualizing GeoParquet Data#

GeoParquet is a columnar format for geospatial data that allows efficient storage and retrieval. The following example demonstrates how to download, read, and visualize GeoParquet files using GeoPandas and Leafmap.

14.9.1. Loading and Visualizing Point Data#

First, import the necessary libraries:

import geopandas as gpd

Download and load a GeoParquet file containing city data:

url = "https://opengeos.org/data/duckdb/cities.parquet"
filename = "cities.parquet"
leafmap.download_file(url, filename, quiet=True)
'/home/runner/work/geog-312/geog-312/book/geospatial/cities.parquet'

Read the GeoParquet file into a GeoDataFrame and preview the first few rows:

gdf = gpd.read_parquet(filename)
gdf.head()
country geometry id latitude longitude name population
0 UGA POINT (32.5333 0.5833) 1.0 0.5833 32.5333 Bombo 75000.0
1 UGA POINT (30.275 0.671) 2.0 0.6710 30.2750 Fort Portal 42670.0
2 ITA POINT (15.799 40.642) 3.0 40.6420 15.7990 Potenza 69060.0
3 ITA POINT (14.656 41.563) 4.0 41.5630 14.6560 Campobasso 50762.0
4 ITA POINT (7.315 45.737) 5.0 45.7370 7.3150 Aosta 34062.0

You can use GeoDataFrame.explore() to visualize the data interactively:

gdf.explore()
Make this Notebook Trusted to load map: File -> Trust Notebook

Alternatively, you can add the data to a Leafmap interactive map and plot the points by specifying their latitude and longitude:

m = leafmap.Map()
m.add_points_from_xy(gdf, x="longitude", y="latitude")
m

14.9.2. Visualizing Polygon Data#

For polygon data, such as wetlands, you can follow a similar process. Start by downloading the GeoParquet file containing wetland polygons:

url = "https://data.source.coop/giswqs/nwi/wetlands/DC_Wetlands.parquet"
filename = "DC_Wetlands.parquet"
leafmap.download_file(url, filename, quiet=True)
'/home/runner/work/geog-312/geog-312/book/geospatial/DC_Wetlands.parquet'

Load the data into a GeoDataFrame and check its coordinate reference system (CRS):

gdf = gpd.read_parquet(filename)
gdf.head()
ATTRIBUTE WETLAND_TYPE ACRES Shape_Length Shape_Area geometry
0 PEM5Ax Freshwater Emergent Wetland 0.454008 621.865659 1837.304895 MULTIPOLYGON (((1629715.061 1937762.608, 16297...
1 PFO1A Freshwater Forested/Shrub Wetland 3.339719 586.449553 13515.364977 MULTIPOLYGON (((1629117.705 1937092.842, 16291...
2 PUBHh Freshwater Pond 0.873177 335.425439 3533.620783 MULTIPOLYGON (((1630250.202 1937446.102, 16302...
3 R4SBC Riverine 0.788316 1078.745304 3190.202659 MULTIPOLYGON (((1630224.321 1937472.319, 16302...
4 R4SBC Riverine 0.069572 106.791860 281.546217 MULTIPOLYGON (((1630340.011 1937467.028, 16303...
gdf.crs
<Projected CRS: EPSG:5070>
Name: NAD83 / Conus Albers
Axis Info [cartesian]:
- X[east]: Easting (metre)
- Y[north]: Northing (metre)
Area of Use:
- name: United States (USA) - CONUS onshore - Alabama; Arizona; Arkansas; California; Colorado; Connecticut; Delaware; Florida; Georgia; Idaho; Illinois; Indiana; Iowa; Kansas; Kentucky; Louisiana; Maine; Maryland; Massachusetts; Michigan; Minnesota; Mississippi; Missouri; Montana; Nebraska; Nevada; New Hampshire; New Jersey; New Mexico; New York; North Carolina; North Dakota; Ohio; Oklahoma; Oregon; Pennsylvania; Rhode Island; South Carolina; South Dakota; Tennessee; Texas; Utah; Vermont; Virginia; Washington; West Virginia; Wisconsin; Wyoming.
- bounds: (-124.79, 24.41, -66.91, 49.38)
Coordinate Operation:
- name: Conus Albers
- method: Albers Equal Area
Datum: North American Datum 1983
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich

You can visualize the polygon data directly using explore() with folium:

gdf.explore()
Make this Notebook Trusted to load map: File -> Trust Notebook