2026-04-21
gganimateImageMagickgganimategganimateggplot2 for animation.
gganimate README Animationgganimategganimate help files organize functions into these grammar classes:
transition_*() defines how the items change.view_*() defines how the view changes.shadow_*() defines how items out-of-focus should appear.enter_*()/exit_*() defines how items come and go.ease_aes() defines how different aesthetics should be eased during transitions.transition_states()
transition_time()
transition_reveal()
transition_events()
transition_filter()
transition_layers()
ggplot2 layers)transition_components()
transition_states()
facet_wrap().
transition_states()
transition_time()
transition_time()
transition_reveal()
transition_events()
no title artist year
1 1 Theme from A Summer Place Percy Faith 1960
2 2 He'll Have to Go Jim Reeves 1960
3 3 Cathy's Clown The Everly Brothers 1960
4 4 Running Bear Johnny Preston 1960
5 5 Teen Angel Mark Dinning 1960
6 6 I'm Sorry Brenda Lee 1960
transition_events()
# Find those artists with at least 10 appearances
multi <- wiki_hot_100s %>%
count(artist) %>%
filter(n > 10)
# Subset data to just those
tens <- wiki_hot_100s %>%
filter(artist %in% multi$artist)
# Sort by earliest appearance
sorted <- tens %>%
group_by(artist) %>%
summarize(start = min(year)) %>%
arrange(start) %>%
# Pull vector of artist names
pull(artist)
# Change artist to factor by date
tens <- tens %>%
mutate(artist = factor(artist, levels = sorted)) %>%
# Categorize number of song
mutate(no_cat = case_when(
no == 1 ~ "1",
no == 2 ~ "2",
no == 3 ~ "3",
no <= 10 ~ "Top 10",
no <= 25 ~ "Top 25",
no <= 50 ~ "Top 50",
no <= 100 ~ "Top 100"
)) %>%
# Factor
mutate(no_cat = factor(no_cat,
levels = c("1", "2", "3", "Top 10",
"Top 25", "Top 50", "Top 100")))
# Create data.frame of first and last appearance
fl <- tens %>%
group_by(artist) %>%
summarize(first = min(year), last = max(year))
# Join
tens_fl <- tens %>%
left_join(fl, by = "artist")transition_events()
# Plot
p <- ggplot(tens_fl, aes(x = year, y = artist, color = no_cat)) +
geom_point(size = 2.5) +
scale_color_viridis_d(name = "Ranking", direction = -1) +
scale_x_continuous(breaks = seq(1960, 2016, by = 4)) +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
axis.text = element_text(size = 7))
ptransition_events()
transition_filter()
transition_layers()
geom sequentially.# Plot penguins data
data("penguins")
p <- penguins %>%
ggplot() +
geom_point(aes(x = bill_len, y = flipper_len, color = species)) +
geom_smooth(aes(x = bill_len, y = flipper_len),
method = "lm", color = "gray30", linetype = "dashed") +
geom_smooth(aes(x = bill_len, y = flipper_len, color = species),
method = "lm") +
coord_cartesian(xlim = c(30, 60),
ylim = c(170, 240)) +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)") +
theme_bw()
p transition_layers()
geom sequentially.transition_components()
# Function sample data from a random walk.
rw <- function(id) {
# Empty data.frame
df <- data.frame(id = id,
t = 1:30,
x = NA, y = NA)
# Random starting location
df$x[1] <- runif(1, min = -3, max = 3)
df$y[1] <- runif(1, min = -3, max = 3)
# Loop to "walk"
for (t in 2:30) {
df$x[t] <- df$x[t - 1] + rnorm(1)
df$y[t] <- df$y[t - 1] + rnorm(1)
}
# Return
return(df)
}
# Sample 3 individuals
set.seed(123456)
dat <- lapply(1:3, rw) %>%
bind_rows()transition_components()
transition_components()
dat %>%
# Let ID 1 go all 30 timesteps
# Only let ID 2 enter at t = 10
# Have ID 3 go from t = 5 to 20
filter(id == 1 | (id == 2 & t > 9) | (id == 3 & t %in% 5:20)) %>%
ggplot(aes(x = x, y = y, color = factor(id), group = factor(id))) +
geom_point(size = 3) +
theme_bw() +
transition_components(time = t) +
ggtitle("t = {frame_time}")view_follow()
view_step()
view_zoom()
view_follow()
penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 4, state_length = 1) +
view_follow()view_step()
penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 4, state_length = 1) +
view_step(pause_length = 2, step_length = 1, nsteps = 3)view_zoom()
pan_zoom.penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 4, state_length = 1) +
view_zoom(pause_length = 1, step_length = 2, nsteps = 3)shadow_wake()
shadow_trail()
shadow_mark()
shadow_wake()
penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 4, state_length = 1) +
shadow_wake(wake_length = 0.1)shadow_trail()
dat %>%
# Let ID 1 go all 30 timesteps
# Only let ID 2 enter at t = 10
# Have ID 3 go from t = 5 to 20
filter(id == 1 | (id == 2 & t > 9) | (id == 3 & t %in% 5:20)) %>%
ggplot(aes(x = x, y = y, color = factor(id), group = factor(id))) +
geom_point(size = 3) +
theme_bw() +
transition_components(time = t) +
ggtitle("t = {frame_time}") +
shadow_trail(max_frames = 3, alpha = 0.3)shadow_mark()
penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 1, state_length = 1) +
shadow_mark(past = TRUE, future = TRUE, colour = 'grey')enter_appear()/exit_disappear()enter_fade()/exit_fade()enter_grow()/exit_shrink()enter_recolor()/exit_recolor()enter_fly()/exit_fly()enter_drift()/exit_drift()enter_appear()/exit_disappear()penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 1, state_length = 1) +
enter_appear() +
exit_disappear()enter_fade()/exit_fade()penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 1, state_length = 1) +
enter_fade() +
exit_fade()enter_grow()/exit_shrink()penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 3, state_length = 1) +
enter_grow() +
exit_shrink()enter_recolor()/exit_recolor()penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 2, state_length = 1) +
enter_recolor(color = "gray") +
exit_recolor(color = "gray")enter_fly()/exit_fly()penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 1, state_length = 1) +
enter_fly(x_loc = 30, y_loc = 170) +
exit_fly(x_loc = 60, y_loc = 230)enter_drift()/exit_drift()penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 1, state_length = 1) +
enter_drift(x_mod = 20) +
exit_drift(y_mod = 100)enter_*()/exit_*() effects.penguins %>%
filter(!is.na(bill_len),
!is.na(flipper_len)) %>%
ggplot(aes(bill_len, flipper_len, color = species)) +
geom_point() +
theme_bw() +
labs(x = "Bill Length (mm)",
y = "Flipper Length (mm)",
title = "{closest_state}") +
transition_states(species, transition_length = 2, state_length = 1) +
# Two enter_*()
enter_fade() + enter_grow() +
# Two exit_*()
exit_fly(x_loc = 7, y_loc = 40) + exit_recolor(color = "black")gganimate provides a ton of flexibility.gganimate.ImageMagick.ImageMagickImageMagick.ImageMagick [1] "01" "02" "03" "04" "05" "06" "07" "08" "09" "10"
ImageMagickImageMagickmagick -delay 20 folder/*.png anim_file.gif
magick calls the program.-delay 20 means display each frame for 20 milliseconds.
folder/*.png returns the filenames of all PNG files inside of folder/ (relative to the current path in your terminal).anim_file.gif is the output file.Render took: 25.5 minutes.