Search code examples
rggplot2animationgifgganimate

How to animate geom_path plots with gganimate in R


I am trying to make a smooth animation of lines that move over time. Here is some example data edited to add x for completeness as I forgot that initially, apologies:

x <- c( 0, 10, 19, 27, 35, 41, 48, 52, 55, 56 )
test.data <- data.frame( depth  = rep( seq( 1, 10 ), 10 ), 
                         time = rep( 1:10, times = 1, each = 10 ),
                         temp = rep( x, 10 ) + rep( 0:9, each = length( x ) ) )

Now arrange the data so that geom_path links the data correctly

 arrange( test.data, depth, time )  ## arrange by depth for plotting

Now make the static plot with all the data shown:

ggplot( test.data, aes( x = temp, y = depth, group = time ) ) +
        ylim( 10, 0 ) +
        labs( y = "Depth (km)", 
              x = "Temp (C)",
              color = "Time") +
        geom_path( aes( color = time ) )

Here is the static plot: enter image description here

Now do the animation using gganimate

library(gganimate)

plot.for.gif <- test.data %>% 
   ggplot( aes( x = temp, y = depth, group = time ) ) +
   ylim( 10, 0 ) +
   labs( y = "Depth (km)", 
         x = "Temp (C)",
         color = "Time (Ma)") +
   geom_path( aes( color = time ) )

plot.animation = plot.for.gif +
   transition_time( time = time ) +
   labs( subtitle = "Time (Ma): {frame_time}" ) +
   shadow_mark( past = TRUE, future = FALSE, exclude_layer = NULL )

   animate( plot.animation, height = 1400, width = 800, fps = 10, duration = 15, res = 150 )

This is the resulting plot:

enter image description here

The problem is that the lines do not blend into one another, they jump from one frame to another. I'd like to get them to move smoothly between discrete frames.

I've tried playing with shadow_wake() and enter_fade() but neither work. It seems like gganimate() doesn't smooth lines connecting datapoints well, but I am perhaps missing an easy fix.

Any help would be appreciated!


Solution

  • You didn't provide x in your question, but presuming it's something like this:

    x <- seq(0, 9)^(2/3) * 15
    

    Then we can do:

    test.data <- data.frame( depth  = rep( seq( 1, 10 ), 10 ), 
                             time = rep( 1:10, times = 1, each = 10 ),
                             temp = rep(x, 10 ) + rep( 0:9, each = length( x ) ) )
    
    library(gganimate)
    
    plot.for.gif <- test.data %>% 
      mutate(time = factor(time)) %>%
      ggplot( aes(x = temp, y = depth, color = as.numeric(time)) ) +
      geom_path() +
      labs(color = "time") +
      scale_y_reverse() +
      transition_states(time, transition_length = 1, state_length = 0.1) 
    
    animate(plot.for.gif, fps = 30, duration = 3, detail = 3)
    

    enter image description here