Problem with many (>50) states in gganimate

2020-04-05 08:20发布

问题:

I'm trying to create a GIF using gganimate for a data set covering 90 years, i.e. I want to have a GIF running through 90 states/years. However, it seems like gganimate is only able to deal with less than 50 states.

So here's an example:

library(tidyverse)
# devtools::install_github('thomasp85/gganimate')
library(gganimate)

df = expand.grid(  x = 1,
                   y = c(2,3),
                year = 1670:1760) %>% mutate( z = 0.03* year,
                                              u = .2 * year)

this all works fine for 49 years:

ggplot(data=df %>% filter(., year %in% 1670:1719) , aes()) + 
  geom_point( aes(x = x, y = y, fill = z, size = u), shape = 21 ) + 
  labs( title = 'Year: {closest_state}') +
  enter_appear() +
  transition_states(year, transition_length = 1, state_length = 2) 

Yet, it gets weird when I include 50 (or more) years:

ggplot(data=df %>% filter(., year %in% 1670:1720) , aes()) + 
  geom_point( aes(x = x, y = y, fill = z, size = u), shape = 21 ) + 
  labs( title = 'Year: {closest_state}') +
  enter_appear() +
  transition_states(year, transition_length = 1, state_length = 2) 

How can I create a GIF for all 90 years? Any ideas are welcome!
I'm still new to gganimate, am I using transition_states incorrectly?

回答1:

This has to do with the fact that gganmiate uses a fixed number of 100 frames for the animation. For up to 50 years (note that 1670:1719 has length 50, not 49), this is alright, but if you want to plot more years, you need more frames. You can control the number of frames by calling animate() explicitly.

For your example, this means that you should first store your plot in a variable:

p <- ggplot(df) + 
      geom_point(aes(x = x, y = y, fill = z, size = u), shape = 21) + 
      labs( title = 'Year: {closest_state}') +
      enter_appear() +
      transition_states(year, transition_length = 1, state_length = 2)

You can then start the animation by typing any of the following

p
animate(p)
animate(p, nframes = 100)

These three lines are equivalent. The first one is what you did in your example: this will implicitly call animate() to render the animation. The second line makes the call to animate() explicit and the third also explicitly sets the number of frames to 100. Since nframes = 100 is the default value, also this last line does the same as the others.

In order to make the animation work, you need to set a higher number of frames. 100 frames worked for 50 years, so 182 frames should work for the 91 years in your full data frame. Again, the following two lines are the same:

animate(p, nframes = 182)
animate(p, nframes = 2 * length(unique(df$year)))

And now it works:

I don't know for certain why you need twice the number of frames as you have years, but after reading the following statement from the documentation on transition_states()

It then tweens between the defined states and pauses at each state.

I would guess that one frame is used for the transition between two years and one frame is used to represent the date for a given year.

This would mean that you actually need one frame less than twice the number of years, because there is no frame needed for the transition after the last year. Indeed, the output from gganimate() for nframes = 100 and nframes = 182, respectively, is:

Frame 99 (100%)
Finalizing encoding... done!

Frame 181 (100%)
Finalizing encoding... done!

So it is indeed creating exactly the number of frames to be expected if my guess was correct.