Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate ggplot time series plot with a sliding window

I'm looking for ways to animate a long time series plot without losing resolution. I would like the view to "pan" across the data, showing a sliding subset of it from the beginning to the end.

Suppose I have the following:

  library(ggplot2)
  library(dplyr)
  library(gganimate)

  df <- as.data.frame(cumsum(rnorm(1:10000))) %>% rename(y = 1)
  df <- mutate(df, seq = seq(1, 10000, by = 1))

  ggplot(df, aes(x = seq, y = y)) + 
    geom_line()

enter image description here

I'd like to create an animation that shows more detail by just focusing on one section of the data at a time, and sliding along from the beginning to the end. Imagine looking at the series through a magnifying lens while sliding the plot underneath... that's the effect I'm trying to achieve. Is it possible through gganimate? If not, any suggestions?

like image 965
Thomas Speidel Avatar asked Apr 06 '19 04:04

Thomas Speidel


1 Answers

I wasn't sure how to do this entirely within the view_* framework of gganimate, but here's an approach using a bit of manual preparation. I copy the data frame for every frame I want to show, and then filter to the data points I want each frame to see. gganimate::view_follow sets each frame's view range to only show the data for that frame.

library(tidyverse)
library(gganimate)
df <- as.data.frame(cumsum(rnorm(1:10000))) %>% rename(y = 1)
df <- mutate(df, seq = seq(1, 10000, by = 1))

window_width = nrow(df)/5  # How much of the whole data to show at once
frames = 200   # Increase to make smoother animation & bigger file
shift_per_frame = (nrow(df) - window_width) / frames

# This bit of purrr copies the whole data frame [frames] times, identifying each with "id"
df_copied <- map_df(seq_len(frames), ~df, .id = "id") %>%
  mutate(id = as.integer(id)) %>%
  filter(seq >= id * shift_per_frame,
         seq <= id * shift_per_frame + window_width)

a <- ggplot(df_copied, aes(x = seq, y = y)) + 
  geom_line() +
  transition_manual(id) +
  view_follow()

animate(a, nframes = frames)

enter image description here

...or with view_follow(fixed_y = TRUE): enter image description here

(Note, for 10k values, it will look better to subdivide into more frames for smoother movement, but this will make a larger file than I could attach here.)

like image 67
Jon Spring Avatar answered Nov 17 '22 22:11

Jon Spring