Skip to article frontmatterSkip to article content

Interactive plots with Ipyleaflet

Overview:

  1. Interactively display images from remote map servers with ipyleaflet
  2. Overlay gridded data on the interactive map

Prerequisites

ConceptsImportanceNotes
Xarray
  • Time to learn: 20 minutes

Imports

from datetime import datetime, timedelta
from ipyleaflet import Map, TileLayer, basemaps, basemap_to_tiles
from ipyleaflet.velocity import Velocity
import xarray as xr

Interactively display images from remote map servers with ipyleaflet

While we’ve made some nice looking maps so far in the course, they are all static images ... i.e., they can only be viewed ... not interacted with. Most of us have browsed interactive map-based websites, such as Google Maps, where we can use our mouse or touch-enabled screen to move around, zoom in or out, or otherwise intereact with the plot. The Javascript programming language is what makes this interactivity possible. Here, we will use a Python package, ipyleaflet, as a “bridge” to Javascript.

Note: The "leaflet" in ipyleaflet refers to the Leaflet open-source Javascript library.

Use a satellite composite as the base image.

Now, specify an image tile server and product, using the same sources as those provided by Contextily, which we’ll cover in some upcoming notebooks.. Center the map and specify a zoom level.

Create time strings

We’ll need to select a date and time, and then pass in date/time objects or strings to various functions below; their format will be function-specific.

timeObj = datetime(2025,10,16,12)
timeStr1 = timeObj.strftime("%Y-%m-%d")
timeStr2 = timeObj.strftime("%Y%m%d_%H%M")
timeStr2
'20251016_1200'
m = Map(
    basemap=basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, timeStr1),
    center=(40, -70),
    zoom=4
)

m
Loading...

Add a background cartographic layer.

We’ll use ipyleaflet’s add_layer method. We simply add another remote tile server. The default opacity is 1.0, so reduce that a bit so we still see the satellite layer.

basemapLayer = basemap_to_tiles(basemaps.CartoDB.Positron,opacity=0.5)
m.add_layer(basemapLayer)

Interact with the dynamic map

Zoom in and out with the +/- buttons to see both layers dynamically update.

Overlay gridded data on the interactive map

We will display an animated wind velocity flow field, a la https://earth.nullschool.net or https://www.windy.com/.

Note: ipyleaflet can read in Xarray DataArray objects so we will exploit that here.

Read in a dataset based on the 0.5-degree resolution GFS on a given date and time.

ds = xr.open_dataset('https://thredds.ucar.edu/thredds/dodsC/grib/NCEP/GFS/Global_0p5deg_ana/GFS_Global_0p5deg_ana_'+ timeStr2 +'.grib2')

Examine the dataset

ds
Loading...

Specify an analysis time, and then create DataArray objects that are subset for the specified time and the 20m AGL level (this is the lowest level in the dataset)

u = ds['u-component_of_wind_height_above_ground'].sel(time=timeObj,height_above_ground1=20)
v = ds['v-component_of_wind_height_above_ground'].sel(time=timeObj,height_above_ground1=20)

Create a Dataset that contains just the wind components

ipyleaflet’s Velocity method produces an animated streamline effect. It accepts an Xarray dataset that contains just two arrays ... specifically, the u- and v- components of the wind vector we have chosen for visualization.

(Perhaps there is a more efficient way of doing this, but the following cell will create a new Xarray Dataset that consists of just two arrays ... u and v.)

# First create the Dataset out of the 'u' Dataarray
dsWind = u.to_dataset()

# Append v to the Dataset
dsWind['v'] = v

# Rename the u DataArray to 'u'
name_dict = {'u-component_of_wind_height_above_ground':'u'}
dsWind = dsWind.rename_vars(name_dict)

# Verify that the Dataset looks ok
dsWind
Loading...

Create the animation

Center it, specify a zoom level, and select a background map; create and add a velocity layer from the Dataset that contains u and v.

center = (43, -69)
zoom = 6
m = Map(center=center, zoom=zoom, interpolation='nearest', basemap=basemaps.CartoDB.DarkMatter)


display_options = {
    'velocityType': 'Global Wind',
    'displayPosition': 'bottomleft',
    'displayEmptyString': 'No wind data'
}
wind = Velocity(data=dsWind,
                zonal_speed='u',
                meridional_speed='v',
                latitude_dimension='lat',
                longitude_dimension='lon',
                velocity_scale=0.01,
                max_velocity=120,
                display_options=display_options)
m.add_layer(wind)

Display the map.

m
Loading...

If you move your mouse/touchpad, you will see direction and speed at the nearest gridpoint displayed at the bottom left of the frame.

Things to try:
  1. Create a velocity map using gridded data from a different vertical level (e.g., 250 hPa); another source ... such as our realtime ECMWF / GFS in /data7, an ERA5 Zarr store, or another datasource from the Unidata THREDDS Server.

  2. Make this notebook dynamic in terms of date so it will always provide a recent (e.g. one day ago) visualization.


Summary

  • Ipyleaflet provides Javascript-enabled interactivity in a Jupyter notebook.
  • Ipyleaflet’s Velocity function creates a flow-vector field that can be layered onto a basemap.
  • The Velocity function accepts an Xarray dataset that contains the u- and v- wind components.

What’s Next?

We’ll explore some GIS terminology ... rasters and vectors. We’ll continue to explore interactive visualizations, next with the Holoviz suite of packages.