Operational 2 m temperature animation¶
This uses cleopatra's temperature_2m data-style — the operational default:
the muted Spectral_r colour ramp rendered as discrete 2 °C contour bands over −40…40 °C with
the out-of-range ends capped (extend="both") — the look of a professional weather-service chart, not the neon
blue→magenta rainbow. (The generic temperature preset auto-ranges to the data instead; pass it vmin/vmax
to pin a non-Celsius field to a chosen range.)
The map is composed like an reference chart: temperature bands + grey coastlines/borders + an arrow-capped colorbar labelled with the contour levels, over the real ERA5-Land data (1 Jun – 15 Jul 2026).
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
from cleopatra.glyphs.base.animation import embed_gif
from cleopatra.glyphs.gridded.array_glyph import ArrayGlyph
# --- data: an ERA5-Land 2 m-temperature stack over Europe (°C, 23 daily frames) ---
npz = np.load(Path("../../../examples/data/europe_t2m.npz"), allow_pickle=True)
celsius = npz["celsius"][::2] # every other day
labels = list(npz["labels"])[::2]
west, south, east, north = (float(v) for v in npz["extent"])
extent = [west, east, south, north] # ArrayGlyph extent order: [xmin, xmax, ymin, ymax]
print("stack:", celsius.shape, "| frames:", labels[0], "->", labels[-1])
from cleopatra.styling.params import DataStyle
stack: (23, 111, 164) | frames: Jun 01 -> Jul 15
The animation¶
Everything comes from one thing: style="temperature_2m". ArrayGlyph reads the preset for the Spectral_r
ramp, the 2 °C contour bands, extend="both", and the arrow-capped colorbar; .animate() runs the per-frame loop —
no manual ScalarMappable, BoundaryNorm, imshow, or FuncAnimation. The coastlines/borders are added straight on
the glyph with add_features (its own GeoMixin method), before animating: the first add_features call creates the
axes, and animate reuses it.
glyph = ArrayGlyph(celsius, extent=extent)
# Add the reference layers on the glyph itself. The first call creates the axes;
# `animate` below reuses it, so the coastlines/borders sit under the data frames.
glyph.add_features("coastline", "50m", color="0.35", linewidth=0.6, zorder=5)
glyph.add_features("borders", "50m", color="0.55", linewidth=0.4, zorder=5)
anim = glyph.animate(data_style=DataStyle(style="temperature_2m"),
time=labels,
colorbar=True, # a full arrow-capped reference colorbar instead of the preset swatch
title="ERA5-Land 2 m temperature",
)
plt.close(glyph.fig) # drop the figure from the inline backend so only the GIF shows
embed_gif(anim, fps=6)
<IPython.core.display.Image object>
That whole reference chart — banded Spectral_r, the 2 °C levels, extend="both", the arrow-capped
colorbar, coastlines — is one ArrayGlyph(..., style="temperature_2m") plus .animate(...), because the look is
baked into the preset. The same one line styles a static .plot() too. For a field that is not fixed to the reference
−40 … 40 °C window, use the generic temperature style (optionally with vmin/vmax), which
auto-ranges to the data.