Animated bubble chart (gapminder)

Animation
Keyframe animation: a Gapminder bubble chart flowing over year, with scales frozen once across all years and frames tweened in the Rust backend.

vellumplot animates a plot by compiling one keyframe per state and tweening the frames between them. The scales are trained once over every state and frozen, so the axes, the colour ramp and the size legend stay put while the data moves. The animation is non-reactive: the states are fixed up front and nothing retrains.

transition_time() is the right idiom for a continuous time like year: it allocates frames in proportion to the gaps between years and never pauses or wraps, so the bubbles glide at a constant rate. animate() compiles the keyframes and anim_save() tweens, renders (in parallel), and encodes the frames, all in one pass on the Rust backend. The extension chooses the format: .png here for a full-colour, lossless animated PNG (a plot’s antialiased edges need more than GIF’s 256 colours per frame), or .gif for the smaller, universally embeddable version. There is a third option, .svg, which emits every frame as vector markup: the right answer for line art and the wrong one for 142 bubbles a frame, so this page is an APNG. See An animation with no pixels in it for that side of the trade.

library(gapminder)

a <- vplot(gapminder,dpi = 200) |>
  mark_point(x = gdpPercap, y = lifeExp, size = pop, color = continent) |>
  scale_x_continuous(trans = "log10") |>
  labs(title = "Gapminder", x = "GDP per capita", y = "Life expectancy") |>
  transition_time(year) |>
  animate(nframes = 150, fps = 25)

Each bubble’s position and size interpolate frame to frame; colours interpolate perceptually in Oklab. Because the x, y and size scales were frozen over the union of all years, a country that is poor early and rich late keeps one stable frame of reference throughout.

Back to top