Jesse
Jesse

Reputation: 244

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!

Upvotes: 0

Views: 444

Answers (2)

Allan Cameron
Allan Cameron

Reputation: 173793

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

Upvotes: 2

MarBlo
MarBlo

Reputation: 4524

You have to leave shadow_mark(past = TRUE,...) out. This keeps the lines from the past in the animation.

I have created an own DF which comes close to yours. (I couldn't figure out, how your variable temp was created.)

If you then leave group = time out you get a smooth animation.

library(gganimate)
library(dplyr)

depth  = rep( seq( 1, 10 ), 10 )
time = rep( 1:10, times = 1, each = 10 )
temp = depth + time

test.data <- data.frame(depth, time)
arrange( test.data, depth, time ) 

anim <- ggplot( test.data, aes( x = temp, y = depth)) +
  ylim( 10, 0 ) +
  labs( y = "Depth (km)", 
        x = "Temp (C)",
        color = "Time") +
  geom_path( aes( color = time ) ) +
  transition_time(time) 
  #shadow_mark(past = T) # leave this out

animate(anim)

enter image description here

Upvotes: 2

Related Questions