Search code examples
rggplot2gganimate

gganimate - have geom_rect adjust each frame


I have the following data:

library(ggplot2)
library(gganimate)
library(tidyverse)

createData<- function(vintage, id){#create data
# Generate a sequence of dates from 2010-01-01 to 2025-12-31 with a quarterly frequency
Dates <- seq(from = as.Date("2010-01-01"), to = as.Date("2025-12-31"), by = "quarter")
RLG<- cumsum(sample(c(-1, 1), 64, TRUE))
df<- data.frame( Dates,RLG, vintage,id)
return(df)
}
#createData

df<- createData("2018-01-01",1) %>%
  rbind(createData("2019-01-01",2))%>%
  rbind(createData("2020-01-01",3)) %>%
  rbind(createData("2021-01-01",4))%>%
  rbind(createData("2022-01-01",5))%>%
  rbind(createData("2023-01-01",6))%>%
  rbind(createData("2024-01-01",7))%>%
  rbind(createData("2025-01-01",8))

Which I use to make the following chart:

options(gganimate.nframes = 8*length(unique(df$vintage)), gganimate.res = 30)
p<- ggplot(df) +
  aes(x = Dates, y = RLG, group = as.Date(vintage), colour = "RLG") +
  geom_line()+
  scale_y_continuous(labels = \(x) paste0(x, "%"))+
  theme(axis.title = element_blank(),legend.position="none")+
  transition_time(id)+
  exit_fade(alpha = 0.5)+
  shadow_mark(alpha = 0.2)

animate(p, end_pause = 30)

I would like to add a geom_rect which goes from vintage to max(Dates). At each frame, vintage will increase, so the geom_rect will shrink slightly. How can I do this without interfering with the shadow_mark and exit_fades which I am applying to the lines?


Solution

  • If you mean something like a progress bar you could do it like so:

    1. create an DF for the geom which is a subset of the original
    df_geom <- df |> 
      mutate(vintage = as.Date(vintage)) |> 
      group_by(id) |> 
      slice(n()) 
    
    1. Use geom_segment with the DF from above. If you want to leave shadow_mark in you can do shadow_mark(exclude_layer = 2).
    p <- ggplot(df) +
      aes(x = Dates, y = RLG, group = as.Date(vintage), colour = RLG) +
      geom_line()+
      scale_y_continuous(labels = \(x) paste0(x, "%"))+
      theme(axis.title = element_blank(),legend.position="none") +
      geom_segment(
        data = df_geom,
        mapping = aes(x=vintage, xend=Dates,
                      y = 18, yend = 18),
        size = 10, alpha =.4, color ='lightblue'
      ) +
      transition_time(id)+
      exit_fade(alpha = 0.5)
      # shadow_mark(alpha = 0.2)
    
    animate(p)
    

    enter image description here