2. Visualizing Geospatial Data#

2.1. Introduction#

Effective geospatial data visualization is the cornerstone of understanding the world around us. This chapter delves into the realm of visualizing geospatial data using the leafmap library. We will explore various techniques to display vector and raster data, create legends and colorbars to customize the visual appearance of maps, and leverage interactive features for enhanced exploration and analysis.

2.2. Technical requirements#

To follow along with this chapter, you will need to have leafmap and several optional dependencies installed. If you have already followed ch1:install - Installing leafmap, then you should already have a conda environment with all the necessary packages installed. Otherwise, you can create a new conda environment and install pygis with the following commands, which will automatically install leafmap and all the required dependencies:

conda create -n geo python
conda activate geo
conda install -c conda-forge mamba
mamba install -c conda-forge pygis

Next, launch JupyterLab by typing the following commands in your terminal or Anaconda prompt:

jupyter lab

Alternatively, you can use leafmap in a cloud environment without installing anything on your local computer. Click on one of the following links to launch a cloud-based JupyterLab server:

Once in the selected cloud environment, you can uncomment the following line and run the cell to install pygis, which includes leafmap and all the necessary dependencies:

# %pip install pygis

The installation process may take 2-3 minutes. Once pygis has been installed successfully, restart the kernel to enable the newly installed packages.

To begin, import the necessary libraries that will be used in this chapter:

import leafmap

2.3. Visualizing vector data#

2.3.1. GeoJSON#

2.3.1.1. Point data#

cities = 'https://open.gishub.org/data/us/cities.geojson'
m = leafmap.Map(center=[40, -100], zoom=4)
m.add_geojson(cities, layer_name='Cities')
m
m = leafmap.Map(center=[40, -100], zoom=4)
m.add_marker_cluster(cities, layer_name='Cities')
m

2.3.1.2. Line data#

cables = 'https://open.gishub.org/data/vector/cables.geojson'
m = leafmap.Map(center=[0, 0], zoom=2)
m.add_geojson(cables, layer_name="Submarine Cables", zoom_to_layer=False)
m
m = leafmap.Map(center=[0, 0], zoom=2)
m.add_basemap("CartoDB.DarkMatter")
callback = lambda feat: {"color": feat["properties"]["color"], "weight": 1}
m.add_geojson(cables, layer_name="Cable lines", style_callback=callback)
m

2.3.1.3. Polygon data#

countries = "https://open.gishub.org/data/world/countries.geojson"
m = leafmap.Map(center=[0, 0], zoom=2)
m.add_geojson(countries, layer_name="Countries")
m
m = leafmap.Map(center=[0, 0], zoom=2)
style = {
    "stroke": True,
    "color": "#0000ff",
    "weight": 2,
    "opacity": 1,
    "fill": True,
    "fillColor": "#0000ff",
    "fillOpacity": 0.1,
}
hover_style = {"fillOpacity": 0.7}
m.add_geojson(countries, layer_name="Countries", style=style, hover_style=hover_style)
m

2.3.2. Shapefile#

states = "https://open.gishub.org/data/us/us_states.zip"
m = leafmap.Map(center=[40, -100], zoom=4)
m.add_shp(states, layer_name="US States")
m

2.3.3. GeoDataFrame#

import geopandas as gpd
gdf = gpd.read_file(states)
gdf.head()
m = leafmap.Map(center=[40, -100], zoom=4)
m.add_gdf(gdf, layer_name="US States")
m

2.3.4. GeoPackage#

regions = "https://open.gishub.org/data/us/us_regions.gpkg"
m = leafmap.Map(center=[40, -100], zoom=4)
m.add_vector(regions, layer_name="US Regions")
m

2.3.5. Vector tile layer#

m = leafmap.Map()
url = "https://planetarycomputer.microsoft.com/api/data/v1/vector/collections/ms-buildings/tilesets/global-footprints/tiles/{z}/{x}/{y}"
attribution = "Microsoft"
vector_tile_layer_styles = {}
m.add_vector_tile_layer(url, attribution, vector_tile_layer_styles)
m

2.4. Visualizing raster data#

2.4.1. GeoTIFF#

2.4.1.1. Single-band Rasters#

dem = 'dem.tif'
dem_url = 'https://open.gishub.org/data/raster/srtm90.tif'
leafmap.download_file(url=dem_url, output=dem, overwrite=True)
m = leafmap.Map()
m.add_raster(dem, cmap='terrain', layer_name="DEM")
m
m.add_raster(dem, cmap='viridis', layer_name="DEM2")

2.4.1.2. Multi-band Rasters#

landsat = 'landsat.tif'
landsat_url = 'https://open.gishub.org/data/raster/landsat.tif'
leafmap.download_file(url=landsat_url, output=landsat)
m.add_raster(landsat, band=[4, 3, 2], vmin=1, vmax=100, layer_name="Landsat")
m

2.4.2. COG#

2.4.2.1. Introduction to COG#

2.4.2.2. Publicly Available COGs#

2.4.2.3. Visualizing COGs#

import os
os.environ['TITILER_ENDPOINT'] = 'https://titiler.xyz'
url = 'https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif'
leafmap.cog_bounds(url)
leafmap.cog_center(url)
leafmap.cog_bands(url)
leafmap.cog_tile(url)
m = leafmap.Map()
m.add_cog_layer(url, name="Fire (pre-event)")
m
url2 = 'https://opendata.digitalglobe.com/events/california-fire-2020/post-event/2020-08-14/pine-gulch-fire20/10300100AAC8DD00.tif'
m.add_cog_layer(url2, name="Fire (post-event)")

2.4.3. STAC#

2.4.3.1. Why Use STAC#

2.4.3.2. Visualizing STAC#

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'
leafmap.stac_bounds(url)
leafmap.stac_center(url)
leafmap.stac_bands(url)
leafmap.stac_tile(url, bands=['B3', 'B2', 'B1'])
m.add_stac_layer(url, bands=['pan'], name='Panchromatic')
m
m.add_stac_layer(url, bands=['B3', 'B2', 'B1'], name='False color')

2.5. Legends#

2.5.1. Built-in legends#

legends = leafmap.builtin_legends
for legend in legends:
    print(legend)
m = leafmap.Map(center=[40, -100], zoom=4)
m.add_basemap('Esri.WorldImagery')
m.add_basemap('NLCD 2021 CONUS Land Cover')
m.add_legend(builtin_legend='NLCD', title='NLCD Land Cover Type')
m

2.5.2. Custom legends#

m = leafmap.Map(center=[40, -100], zoom=4)
m.add_basemap('Esri.WorldImagery')
m.add_basemap('NLCD 2021 CONUS Land Cover')

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 Type", legend_dict=legend_dict)
m

2.6. Colorbars#

import leafmap.colormaps as cm
cm.palettes.dem
cm.plot_colormap(colors=cm.palettes.dem, axis_off=True)
cm.palettes.ndvi
cm.plot_colormap(colors=cm.palettes.ndvi)
cm.get_palette('terrain', n_class=8)
cm.plot_colormap(colors=cm.get_palette('terrain', n_class=8))
cm.plot_colormap(colors=["red", "green", "blue"], label="Temperature", font_size=12)
cm.plot_colormap(
    colors=["red", "green", "blue"], discrete=True, label="Temperature", font_size=12
)
cm.plot_colormap(
    'terrain',
    label="Elevation",
    width=8.0,
    height=0.4,
    orientation='horizontal',
    vmin=0,
    vmax=1000,
)
cm.plot_colormap(
    'terrain',
    label="Elevation",
    width=0.4,
    height=4,
    orientation='vertical',
    vmin=0,
    vmax=1000,
)
m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m.add_colormap(
    'terrain',
    label="Elevation",
    width=3.0,
    height=0.25,
    orientation='horizontal',
    vmin=0,
    vmax=4000,
)
m
m = leafmap.Map()
m.add_basemap("OpenTopoMap")
m.add_colormap(
    'terrain',
    label="Elevation",
    width=0.3,
    height=3,
    orientation='vertical',
    vmin=0,
    vmax=4000,
)
m
cm.plot_colormaps(width=8, height=0.4)

2.7. Labels#

data = "https://open.gishub.org/data/us/us_states.geojson"
m = leafmap.Map(center=[40, -100], zoom=4, layers_control=True)
m.add_labels(
    data,
    "id",
    font_size="12pt",
    font_color="blue",
    font_family="arial",
    font_weight="bold",
)
m
m.remove_labels()

2.8. Split maps#

leafmap.split_map(
    left_layer="Esri.WorldTopoMap", right_layer="OpenTopoMap", zoom_control=False
)
m = leafmap.Map(center=[36.1, -114.9], zoom=10)
m.split_map(
    left_layer="NLCD 2001 CONUS Land Cover",
    right_layer="NLCD 2021 CONUS Land Cover",
    left_label="2001",
    right_label="2021",
    add_close_button=False,
)
m

2.9. Linked maps#

layers = ['Stamen.Terrain', 'OpenTopoMap']
leafmap.linked_maps(rows=1, cols=2, height='400px', layers=layers)
layers = [str(f"NLCD {year} CONUS Land Cover") for year in [2001, 2006, 2011, 2021]]
labels = [str(f"NLCD {year}") for year in [2001, 2006, 2011, 2021]]
leafmap.linked_maps(
    rows=2,
    cols=2,
    height='300px',
    layers=layers,
    labels=labels,
    center=[36.1, -115.2],
    zoom=9,
)

2.10. Summary#

2.11. References#