Search code examples
rggplot2gganimate

placing transition data on stacked bars with gganimate


I'm trying to recreate this graph in R but I can't manage to have the transition data displayed in red stacked bars. I also don't know how to show the bar that decreases in value in another color as in the graph of the link.

Here's a sample code to work from:

df <- data.frame(group=c("A","B","C"), values=c(31,2,4,25,6,7,20,9,10,15,12,13,10,15,16,5,18,19), 
                frame=c(rep('a',3), rep('b',3), rep('c',3), rep('d',3), rep('e',3), rep('f',3)))

ggplot(df, aes(x=group, y=values, fill=group)) +
  coord_flip() +
  geom_bar(stat = 'identity') +
  geom_text(aes(label = values), vjust = -0.3, size = 3.5) +
  transition_manual(frame) +
  theme(legend.position = "none")

Solution

  • There are several approaches to get this kind of animation. Instead of using some kind of stacked bar chart I two geom_col layers to achieve the desired result.

    The first geom_col plots the values over time, whereby the fill is based on whether the values increase or decrease compared to the base value. The second geom_col plots the values over time, whereby the fill is based on whether the values increase or decrease compared to the base value.

    The seocnd geom_col simply plots the base values whereby in that case I use the alpha aes to get the transparency based on whether the values increase or decrease compared to the base value.

    library(ggplot2)
    library(gganimate)
    library(dplyr)
    
    df <- data.frame(group=c("A","B","C"), values=c(31,2,4,25,6,7,20,9,10,15,12,13,10,15,16,5,18,19), 
                     frame=c(rep('a',3), rep('b',3), rep('c',3), rep('d',3), rep('e',3), rep('f',3)))
    
    df1 <- df %>%
      group_by(group) %>% 
      mutate(base = values[frame == "a"],
             diff = values - base) %>% 
      ungroup()
    
    ggplot(df1, aes(x=group)) +
      coord_flip() +
      geom_col(aes(y=values, fill = diff > 0), position = "identity") +
      geom_col(aes(y=base, alpha = diff > 0), fill = "blue", position = "identity") +
      scale_fill_manual(values = c("blue", "red")) +
      scale_alpha_manual(values = c("TRUE" = 1, "FALSE" = .2)) +
      geom_text(aes(y=values, label = values), vjust = -0.3, size = 3.5) +
      transition_manual(frame) +
      theme(legend.position = "none")
    #> nframes and fps adjusted to match transition