Animation and Motion Graphics

It's more than just making beautiful graphs

Animated graphs can actually show more than regular static ones. Plotting more than two variables can quickly be difficult and can result in a messy graph.
Animating a graph allows to show one less variable on the graph. It also allows to see how the data evolves on the variable that is used for the animation. As the human eye is sensitive to movement, animations can be a good way to extract and share insightful information.
Plus, with animated graphs you can show data in the order you want which can be useful to illustrate your point.

1. R Studio Animation With GGAnimate

gganimate works with existing ggplot2 code syntax. It allows to animate plots with minimal code changes and additions. It provides useful grammar classes that can be added to animate graphs and tweak their behavior.

  • 1.1 Transitions

Transitions allow to set what variable is going to change in the animation, and how it is going to change.

  • 1.1.1 transition_state(var)

transition_state() cycles between the values of specified variable.

catdog.names <- seattlepets %>%  filter(species=="Cat" | species=="Dog") %>% filter(animal_name!="NA")  %>% count(animal_name) %>%top_n(30)  %>% mutate(Animal="Total")


allnames <- factor(catdog.names$animal_name, levels = catdog.names$animal_name)

cat.names <- seattlepets %>%  filter(species=="Cat" & animal_name %in% levels(allnames)) %>% filter(animal_name!="NA")  %>% count(animal_name) %>%top_n(30) %>%mutate(Animal="Cat")
dog.names <- seattlepets %>%  filter(species=="Dog" & animal_name %in% levels(allnames)) %>% filter(animal_name!="NA")  %>% count(animal_name) %>%top_n(30)  %>% mutate(Animal="Dog")

categories_name <- rbind(catdog.names,dog.names) %>% rbind(.,cat.names)
g4 <- ggplot(categories_name, aes(x = n, y = fct_reorder2(animal_name, Animal == "Total", n,
                                                   .desc = FALSE), color = Animal)) +
  geom_point(aes(colour = Animal, group = 1L)) +
  labs(title = "Now showing {closest_state}", x = "Occurences",  y = "Name")+
    transition_states(Animal, transition_length = 2, state_length = 2)+
    ease_aes('cubic-in-out')

# Save at gif:
animate(g4,duration = 10, fps = 10,  renderer = gifski_renderer(),end_pause=10)
anim_save("states.gif")
  • 1.1.2 transition_time()

This works similarly to transition_states(). It assumes that the variable states represent dates in time and it tries to change the transition times depending on the time difference of the dates. Time ranges can be added as parameters.


dat = WDI(indicator=c('NY.GDP.PCAP.KD','GC.TAX.TOTL.GD.ZS','MS.MIL.XPND.ZS','MS.MIL.XPND.CD','HF.UHC.NOPX.ZS.Q5'),country=c('US','CN','ES','GB','JP'))

dat <- dat %>%  mutate(gdp=NY.GDP.PCAP.KD * HF.UHC.NOPX.ZS.Q5 * 1000)

g3 <- ggplot(dat, aes(NY.GDP.PCAP.KD, MS.MIL.XPND.CD, size = 2, color = country)) +
  geom_point() +
  scale_x_log10() +
  scale_y_log10() +
  geom_text(aes(label=country),hjust=0.5, vjust=-0.9)+
  theme_bw() +
  theme(legend.position="none")+
  # animation code
  labs(title = 'Year: {frame_time}', x = 'Total GDP', y = 'Military Expenditure (% of GDP)') +
  transition_time(year,c(1970L,2017L)) +
  ease_aes('linear') 

# Save at gif:
animate(g3,duration = 10, fps = 15,  renderer = gifski_renderer(),end_pause=45)
anim_save("animatedcircles.gif")
WDIsearch('hapiness')

g2 <- dat %>%
  ggplot( aes(y=NY.GDP.PCAP.KD, x=country, color=country,fill=country), show.legend = FALSE) +
    geom_bar(stat="identity")+
    theme_ipsum() +
    theme(legend.position="none")+
    # animation code
    labs(title = 'GDP per capita - Year: {frame_time}', x = 'Country', y = 'GDP per capita') +
    transition_time(year, range = c(2000L,2019L))+
    ease_aes('linear')
    

# Save at gif:
animate(g2,duration = 10, fps = 15,  renderer = gifski_renderer(),end_pause=45)
anim_save("animatedbars.gif")
  • 1.1.3 transition_reveal()

This transition allows to show the data gradually.


g1 <- dat %>%
  ggplot( aes(y=NY.GDP.PCAP.KD, x=year, group=country, color=country)) +
    geom_line(size=1.5) +
    geom_point(size=5 ) +
    ggtitle("GDP per capita, PPP (constant 2005 international $), 1960-2020") +
    theme_ipsum() +
    ylab("GDP per capita") +
      # animation code
    transition_reveal(year,)+
    ease_aes('sine-in-out')
# Save at gif:
animate(g1, duration = 2, fps = 30, width = 500, height = 250, renderer = gifski_renderer())
anim_save("animatedlines1.gif")

animate(g1, duration = 10, fps = 15, width = 500, height = 250, renderer = gifski_renderer(),end_pause=45)
anim_save("animatedlines2.gif")
    • 1.2 Make it more readable
      • 1.2.1 ease_aes()

      ease_aes() changes the transition speed between states depending on the specified function. The '-in' and '-out' restrict the effect on the start or end of transitions.

      No ease_aes

      ease_aes('cubic-in-out')

      ease_aes('cubic-out')

      ease_aes('cubic-in')

      • 1.2.2 animation output

      By default the output is a series of PNGs. animate(renderer = gifski_renderer()) is used to render the animation to a gif file. end_pause parameter pauses the animation for a certain amount of frames. 'Duration' and Framarate can be changed with 'duration' and 'fps'

      Bad animation : it has no pause and the duration is too low.

      A better animation

    animate(g1,duration = 10, fps = 15,  renderer = gifski_renderer(),end_pause=45)
    anim_save("filename.gif")
    

2. From R studio to After Effects

Preview
  • 2.1 Exporting graphs

ggplot2 graphs can be saved in a vectorized .svg format with the svglite library.

library(svglite)
g1 <- dat %>%
  ggplot( aes(y=NY.GDP.PCAP.KD, x=year, group=country, color=country)) +
    geom_line(size=1.5) +
    geom_point(size=5,data=subset(dat, (year+1) %% 10 == 1) ) +
    ggtitle("GDP per capita, PPP (constant 2005 international $), 1960-2020") +
    theme_ipsum() +
    ylab("GDP per capita") 

#Saving the file 
ggsave(file="test.svg", plot=g1, width=10, height=8)

.svg files cannot be opened by After Effects, so they can to be converted to an illustrator file inside Adobe illustrator.

  • 2.1 Inside After Effects

The saved file can then be dragged into After Effects.

Because the layer is transparent, the backgroung color is going to be dark, this can be changed by adding a solid layer behind the graph.

To play with the shapes and lines, the different layers can be extracted by right clicking the graph layer and select create -> Create Shapres from Vector Layer

Inside the created vectorized outlines layer, the different shapes can be modified with standards After Effects tools.

For instance, adding trim path allows to animate the lines, a point's size can be changed with keyframes etc...

Final result after precomp and scale automation

Contact Me

an3078@columbia.edu