HAHS.
Back to Catalog

Playback / Scrub

interaction

Also known as: animation playback, timeline scrub, play/pause, time slider, temporal animation

Show change over timeEnable explorationGuide narrative TemporalNumerical

Description

Playback / scrub is an interaction pattern that provides media-player-style controls — play, pause, step forward, step backward, and a scrubbing slider — to animate a visualization through a temporal or sequential dimension. Pressing play causes the chart to update frame by frame, showing how the data changes over time: bars grow and shrink, points migrate across a scatterplot, map regions shift colors, and trend lines extend. The scrub slider lets the user drag to any point in the sequence, providing random access to any moment in the data’s temporal evolution.

The most famous example is Hans Rosling’s Gapminder visualization (popularized in his 2006 TED talk), where pressing play animates country bubbles across a health-vs-wealth scatterplot from 1800 to the present. The animation reveals trajectories, convergences, and divergences that are invisible in a static snapshot. The pattern has since become a standard feature in tools like Flourish, Datawrapper, and Google’s Public Data Explorer.

Playback works because human perception is finely tuned to detect motion — movement attracts attention and conveys change more viscerally than any static comparison. However, animation also has cognitive costs: it relies on memory (the user must remember what the previous frame looked like to notice what changed) and can overwhelm when many items move simultaneously. This is why the scrub slider is essential: it lets the user pause, rewind, and compare specific frames, converting the animation from a passive viewing experience into an interactive exploration tool.

Playback / Scrub — try it yourself

When to Use

  • When the data has a natural temporal dimension (years, months, days) and the analytical question is “how did things change over time?”
  • When the trajectories or dynamics of individual data items are as interesting as their final positions.
  • For presentations and storytelling where animated change is more engaging than a static comparison.
  • When the dataset has too many time steps to show as small multiples but the evolution is meaningful.
  • When the audience benefits from seeing the data “come alive” — engaging non-technical viewers.

When NOT to Use

  • When there are only 2-3 time points — a simple before/after comparison or small multiples is clearer and does not require animation.
  • When many items move simultaneously in unpredictable directions — the animation becomes chaotic and unreadable.
  • When precise comparison between time points is needed — static side-by-side views or superimposed traces are more reliable than memory of a previous animation frame.
  • When the temporal patterns are subtle — small changes are hard to perceive in animation.
  • When the audience is using assistive technology — screen readers cannot convey animated spatial changes.

How It Works

  1. The interface presents playback controls — a play/pause button, a timeline slider (scrubber), and optionally step-forward/step-backward buttons.
  2. Pressing play starts a timer (via setInterval or requestAnimationFrame) that advances the current time step at a defined frame rate.
  3. At each time step, the visualization updates: marks transition to their new positions, sizes, or colors corresponding to the current time value.
  4. The scrub slider tracks the current position — its handle moves in sync with the animation, showing progress through the time range.
  5. The user can drag the slider at any time to jump to a specific time step, pausing automatic playback.
  6. Speed controls (0.5x, 1x, 2x) may be available to adjust the animation pace.
  7. At the end of the time range, playback either stops or loops back to the beginning.

Variations

  • Continuous playback: The time parameter is interpolated smoothly between data points, creating fluid motion.
  • Discrete step playback: The animation jumps between distinct time steps (e.g., year by year) with a transition between each.
  • Cumulative playback: Rather than replacing data at each step, new data is added (e.g., a line chart that extends as time advances).
  • Trail playback: Moving marks leave fading trails showing their recent trajectory — helps track individual item paths.
  • Playback with narration: Each time step triggers a text annotation explaining what is happening, combining playback with scrollytelling.
  • Bidirectional scrub: The user can scrub backward and forward freely, not just in the forward direction.
  • Multi-speed with slow-motion zones: Certain time periods automatically slow down to highlight important events.

Code Reference

// Playback/scrub for an animated scatterplot (Gapminder style)
const years = d3.range(1960, 2024);
let yearIndex = 0, playing = false, timer;

d3.select("#play-btn").on("click", () => {
  playing = !playing;
  d3.select("#play-btn").text(playing ? "Pause" : "Play");
  if (playing) {
    timer = d3.interval(() => {
      yearIndex = (yearIndex + 1) % years.length;
      updateToYear(years[yearIndex]);
      d3.select("#scrubber").property("value", yearIndex);
    }, 200);
  } else {
    timer.stop();
  }
});

d3.select("#scrubber")
  .attr("type", "range").attr("min", 0).attr("max", years.length - 1)
  .on("input", function () {
    yearIndex = +this.value;
    updateToYear(years[yearIndex]);
  });

function updateToYear(year) {
  const yearData = data.filter(d => d.year === year);
  svg.selectAll("circle")
    .data(yearData, d => d.country)
    .transition().duration(150)
    .attr("cx", d => x(d.income))
    .attr("cy", d => y(d.health))
    .attr("r", d => r(d.population));
  d3.select("#year-label").text(year);
}