How to Visualize xarray Outputs with Temperature, Wind, and Geopotential Fields in WeatherNext

WeatherNext stores atmospheric forecasts as nested xarray.Dataset structures that you can visualize using standard xarray plotting methods combined with Matplotlib.

The WeatherNext repository from Google DeepMind outputs weather predictions as xarray datasets containing standard meteorological variables. This guide shows you how to extract and plot temperature, wind, and geopotential fields using the repository's built-in utilities and the standard scientific Python stack.


Understanding WeatherNext's xarray Output Structure

WeatherNext packages its model forecasts as xarray.Dataset objects. Each dataset contains atmospheric variables as separate xarray.DataArray objects:

  • t — Temperature in Kelvin
  • u — Zonal wind component in m/s
  • v — Meridional wind component in m/s
  • z — Geopotential height in m²/s²

The repository provides a specialized wrapper in weathernext/utils/xarray_tree.py that treats every leaf node of a dataset as an independent DataArray while preserving the ability to reconstruct the original Dataset after processing. This utility is essential when working with WeatherNext's potentially non-uniform coordinate structures.


Loading and Extracting WeatherNext Forecast Data

Start by loading your NetCDF output and extracting the three fields you need to visualize.

import xarray as xr

# Load WeatherNext forecast output

ds = xr.open_dataset("forecast_output.nc")

# Extract individual DataArrays

temp = ds["t"]          # Temperature

u_wind = ds["u"]        # Zonal wind

v_wind = ds["v"]        # Meridional wind

geopot = ds["z"]        # Geopotential height

WeatherNext follows CF conventions, so coordinate variables (latitude, longitude, pressure level, time) attach automatically to each field.


Visualizing Temperature with xarray pcolormesh

Temperature fields display effectively as filled color maps. The xarray plot.pcolormesh method provides automatic coordinate handling and color bar generation.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(10, 6))

temp.plot.pcolormesh(
    ax=ax,
    cmap="coolwarm",
    add_colorbar=True,
    cbar_kwargs={"label": "Temperature (K)"},
)
ax.set_title("Temperature Field")
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")

The coolwarm colormap emphasizes both warm and cold anomalies symmetrically around neutral tones.


Plotting Wind Vectors with quiver

Wind requires combining both components into vector arrows. Subsampling prevents overcrowding in high-resolution WeatherNext outputs.

fig, ax = plt.subplots(figsize=(10, 6))

# Subsample every 5th grid point for clarity

step = 5
u_sub = u_wind[::step, ::step]
v_sub = v_wind[::step, ::step]

# Optional: background shading for context

temp[::step, ::step].plot.pcolormesh(ax=ax, cmap="Greys", alpha=0.3)

ax.quiver(
    u_sub["lon"], u_sub["lat"],
    u_sub.values, v_sub.values,
    scale=700,
    width=0.002,
    color="k"
)
ax.set_title("Wind Vectors")
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")

Adjust the scale parameter to control arrow length. Larger values produce shorter arrows.


Displaying Geopotential Height with contour

Geopotential height fields work best as contour lines, emphasizing pressure-level topology and wave patterns.

fig, ax = plt.subplots(figsize=(10, 6))

geopot.plot.contour(
    ax=ax,
    colors="black",
    linewidths=0.8,
    add_colorbar=False,
    levels=12,
)
ax.set_title("Geopotential Height")
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")

Specify levels to control contour density. Twelve levels typically resolve synoptic-scale features without excessive clutter.


Combining All Three Fields in a Multi-Panel Figure

For comparative analysis, arrange temperature, wind, and geopotential plots side by side using Matplotlib subplots.

import xarray as xr
import matplotlib.pyplot as plt

# Load WeatherNext dataset

ds = xr.open_dataset("forecast_output.nc")
temp = ds["t"]
u_wind, v_wind = ds["u"], ds["v"]
geopot = ds["z"]

# Create figure with three panels

fig, axs = plt.subplots(1, 3, figsize=(18, 5))

# Panel 1: Temperature pcolormesh

temp.plot.pcolormesh(
    ax=axs[0],
    cmap="coolwarm",
    cbar_kwargs={"label": "Temperature (K)"},
)
axs[0].set_title("Temperature")

# Panel 2: Wind quiver with temperature background

step = 5
axs[1].pcolormesh(
    temp["lon"][::step], temp["lat"][::step],
    temp[::step, ::step],
    cmap="Greys", alpha=0.3
)
axs[1].quiver(
    u_wind["lon"][::step], u_wind["lat"][::step],
    u_wind[::step, ::step], v_wind[::step, ::step],
    scale=700, width=0.002, color="k"
)
axs[1].set_title("Wind Vectors")

# Panel 3: Geopotential contours

geopot.plot.contour(
    ax=axs[2],
    colors="black",
    linewidths=0.8,
    levels=12,
)
axs[2].set_title("Geopotential Height")

plt.tight_layout()
plt.show()

This layout enables direct visual comparison of thermal structure, flow patterns, and geopotential topography.


Pre-Processing with xarray_tree.map_structure

Before visualization, you may need to apply transformations uniformly across all variables. The xarray_tree.map_structure function in weathernext/utils/xarray_tree.py safely applies functions to every DataArray leaf while preserving dataset structure.

from weathernext.utils import xarray_tree

# Convert temperature from Kelvin to Celsius

def kelvin_to_celsius(arr):
    if arr.name == "t":
        return arr - 273.15
    return arr

processed_ds = xarray_tree.map_structure(kelvin_to_celsius, ds)

If coordinates mismatch across variables—a possibility in WeatherNext outputs—map_structure automatically falls back to a plain dictionary representation rather than failing. This behavior is implemented in lines 54-65 of xarray_tree.py.


Dependencies and Repository Structure

WeatherNext declares Matplotlib as a dependency in [setup.py](https://github.com/google-deepmind/weathernext/blob/main/setup.py), ensuring visualization tools install automatically with the package.

File Purpose
weathernext/utils/xarray_tree.py Dataset traversal and transformation utilities
weathernext/utils/data_modalities.py Canonical variable names (t, u, v, z)
setup.py Matplotlib dependency declaration

The canonical variable naming scheme in data_modalities.py ensures consistency across WeatherNext's data loading, processing, and visualization pipelines.


Summary

  • WeatherNext outputs standard xarray.Dataset objects containing temperature, wind components, and geopotential height as separate DataArrays.
  • Extract fields by name (ds["t"], ds["u"], ds["v"], ds["z"]) for individual visualization.
  • Use xarray's built-in plotting: pcolormesh for temperature, quiver for wind vectors, and contour for geopotential height.
  • Apply xarray_tree.map_structure from weathernext/utils/xarray_tree.py for uniform pre-processing across all dataset variables.
  • Subsample wind fields to prevent visual clutter in high-resolution outputs.

Frequently Asked Questions

What coordinate system does WeatherNext use for its xarray outputs?

WeatherNext follows CF (Climate and Forecast) conventions, attaching latitude, longitude, pressure level, and time coordinates to all output variables. These coordinates propagate automatically through xarray selection and plotting operations.

Can I visualize multiple forecast timesteps simultaneously?

Yes. WeatherNext datasets include a time dimension. Use xarray's .isel(time=...) or .sel(time=...) to select specific lead times, or create animation loops iterating over the time coordinate with matplotlib.animation.FuncAnimation.

How do I handle missing or masked values in WeatherNext outputs?

Apply xarray_tree.map_structure with a masking function before visualization. The utility preserves NaN values in xarray's standard representation, which Matplotlib automatically excludes from plots.

Why does my wind quiver plot appear as solid black?

Your grid resolution exceeds the visualization capacity. Apply subsampling with slice notation ([::5, ::5]) or increase the scale parameter in quiver() to shorten arrow lengths.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →