Animation

Lecture 18

Dr. Greg Chism

University of Arizona
INFO 526 - Summer 2024

Setup

# load packages
library(countdown)
library(tidyverse)
library(gt)
library(readxl)
library(gganimate)
library(gifski)
library(knitr)
library(kableExtra)
library(palmerpenguins)
library(transformr)
library(datasauRus)

# set theme for ggplot2
ggplot2::theme_set(ggplot2::theme_minimal(base_size = 14))

# set width of code output
options(width = 65)

# set figure parameters for knitr
knitr::opts_chunk$set(
  fig.width = 7, # 7" width
  fig.asp = 0.618, # the golden ratio
  fig.retina = 3, # dpi multiplier for displaying HTML output on retina
  fig.align = "center", # center align figures
  dpi = 300 # higher dpi, sharper image
)

Animation

Philosophy

  • The purpose of interactivity is to display more than can be achieved with persistent plot elements, and to invite the reader to engage with the plot.

  • Animation allows more information to be displayed, but developer keeps control

  • Beware that it is easy to forget what was just displayed, so keeping some elements persistent, maybe faint, can be useful for the reader

gganimate

  • gganimate extends the grammar of graphics as implemented by ggplot2 to include the description of animation

  • It provides a range of new grammar classes that can be added to the plot object in order to customize how it should change with time

Animation example

How does gganimate work?

  • Start with a ggplot2 specification

  • Add layers with graphical primitives (geoms)

  • Add formatting specification

  • Add animation specification

A simple example

freedom_ranked |>
  filter(country == "Turkey") |>
  ggplot()

A simple example

freedom_ranked |>
  filter(country == "Turkey") |>
  ggplot(
    aes(
      x = year, 
      y = civil_liberty
    )
  )

A simple example

freedom_ranked |>
  filter(country == "Turkey") |>
  ggplot(
    aes(
      x = year, 
      y = civil_liberty
    )
  ) +
  geom_line(linewidth = 2)

A simple example

freedom_ranked |>
  filter(country == "Turkey") |>
  ggplot(
    aes(
      x = year, 
      y = civil_liberty
    )
  ) +
  geom_line(linewidth = 2) +
  labs(
    x = "Year", 
    y = "Civil liberty score",
    title = "Turkey's civil liberty score"
  )

A simple example

turkey_cl <- freedom_ranked |>
  filter(country == "Turkey") |>
  ggplot(
    aes(
      x = year, 
      y = civil_liberty
    )
  ) +
  geom_line(linewidth = 2) +
  labs(
    x = "Year", 
    y = "Civil liberty score",
    title = "Turkey's civil liberty score"
  ) +
  transition_reveal(year)

Grammar of animation

Grammar of animation

  • Transitions: transition_*() defines how the data should be spread out and how it relates to itself across time

  • Views: view_*() defines how the positional scales should change along the animation

  • Shadows: shadow_*() defines how data from other points in time should be presented in the given point in time

  • Entrances/Exits: enter_*()/exit_*() defines how new data should appear and how old data should disappear during the course of the animation

  • Easing: ease_aes() defines how different aesthetics should be eased during transitions

Transitions

How the data changes through the animation.

Function Description
transition_manual Build an animation frame by frame (no tweening applied).
transition_states Transition between frames of a plot (like moving between facets).
transition_time Like transition_states, except animation pacing respects time.
transition_components Independent animation of plot elements (by group).
transition_reveal Gradually extends the data used to reveal more information.
transition_layers Animate the addition of layers to the plot. Can also remove layers.
transition_filter Transition between a collection of subsets from the data.
transition_events Define entrance and exit times of each visual element (row of data).

Transitions

Which transition was used in the following animations?

transition_layers()

New layers are being added (and removed) over the dots.

Views

How the plot window changes through the animation.

Function Description
view_follow Change the view to follow the range of current data.
view_step Similar to view_follow, except the view is static between transitions.
view_step_manual Same as view_step, except view ranges are manually defined.
view_zoom Similar to view_step, but appears smoother by zooming out then in.
view_zoom_manual Same as view_zoom, except view ranges are manually defined.

Views

Which view was used in the following animations?

view_follow()

Plot axis follows the range of the data.

Shadows

How the history of the animation is shown. Useful to indicate speed of changes.

Function Description
shadow_mark Previous (and/or future) frames leave permananent background marks.
shadow_trail Similar to shadow_mark, except marks are from tweened data.
shadow_wake Shows a shadow which diminishes in size and/or opacity over time.

Shadows

Which shadow was used in the following animations?

shadow_wake()

The older tails of the points shrink in size, leaving a “wake” behind it.

Shadows

Which shadow was used in the following animations?

shadow_mark()

Permanent marks are left by previous points in the animation.

Entrances and exits

How elements of the plot appear and disappear.

Function Description
enter_appear/exit_disappear Poof! Instantly appears or disappears.
enter_fade/exit_fade Opacity is used to fade in or out the elements.
enter_grow/exit_shrink Element size will grow from or shrink to zero.
enter_recolor/exit_recolor Change element colors to blend into the background.
enter_fly/exit_fly Elements will move from/to a specific x,y position.
enter_drift/exit_drift Elements will shift relative from/to their x,y position.
enter_reset/exit_reset Clear all previously added entrace/exits.

Animation controls

How data moves from one position to another.

p + ease_aes({aesthetic} = {ease})
p + ease_aes(x = "cubic")

ease examples

ease examples

Deeper dive

A not-so-simple example

Pass in the dataset to ggplot

ggplot(datasaurus_dozen)

A not-so-simple example

For each dataset we have x and y values, in addition we can map dataset to color

ggplot(
  datasaurus_dozen,
  aes(x, y, color = dataset)
)

A not-so-simple example

Trying a simple scatter plot first, but there is too much information

ggplot(
  datasaurus_dozen,
  aes(x, y, color = dataset)
) +
  geom_point(show.legend = FALSE)

A not-so-simple example

We can use facets to split up by dataset, revealing the different distributions

ggplot(
  datasaurus_dozen,
  aes(x, y, color = dataset)
) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~dataset)

A not-so-simple example

We can just as easily animate, transitioning between dataset states!

datasaurus_dozen <- ggplot(
  datasaurus_dozen,
  aes(x, y, color = dataset)
) +
  geom_point(size = 2, show.legend = FALSE) +
  transition_states(
    dataset, 
    transition_length = 3, 
    state_length = 1
  ) +
  labs(
    title = "Dataset: {closest_state}"
  )

Tips

Animation options

Sometimes you need more frames, sometimes fewer

  • Save plot object, and use animate() with arguments like
    • nframes: number of frames to render (default 100)
    • fps: framerate of the animation in frames/sec (default 10)
    • duration: length of the animation in seconds (unset by default)
    • etc.
  • In Quarto, save the plot and animate it with animate().

Considerations in making effective animations

  • Pace: speed of animation - Quick animations may be hard to follow. Slow animations are boring and tedious.
  • Perplex: amount of information - It is easy for animations to be overwhelming and confusing. Multiple simple animations can be easier to digest.
  • Purpose: Usefulness of using animation Is animation needed? Does it provide additional value?

Acknowledgements