grdn
grdn

Reputation: 93

How to animate grouped barplots with gganimate?

I would like to animate a grouped barplot, such that each series is plotted in turn and then remains visible. In the example plot below I would like the bars with id = 1 to be plotted first and remain while id = 2, id = 3, id = 4 are plotted in turn.

enter image description here

df <- data.frame(id = factor(c(1:4)),
                    var1 = c(0, 20,60, 80),
                    var2 = c(18, 64, 91, 100),
                    var3 = c(8, 73, 100, 100),
                    var4 = c(18, 48, 67, 85))

df_melt <- melt(df, id.var = "id")
df_melt <- df_melt %>% mutate(show_time = 1, reveal_time = cumsum(show_time))

ggplot(data = df_melt, aes(x = variable, y = value, fill = id)) + 
    geom_bar(stat = "identity", position = "dodge")

I have been able to generate animated line plots using transition_reveal as described here: https://www.datanovia.com/en/blog/gganimate-how-to-create-plots-with-beautiful-animation-in-r/

I have tried using transition_reveal and transition_states (alone and in combination) in order to accomplish my goal, but so far have been unsuccessful. For example: transition_states(id).

I have also tried adding a reveal_time column to my data and using transition_reveal(reveal_time) to no avail.

All the animations I generate plot the values for id = 2 on top of id = 1 rather than to the side. As such, the final frame is a barplot with four bars rather than four groups of four.

Any help would be much appreciated - thanks!

Upvotes: 3

Views: 1254

Answers (1)

Ben Nutzer
Ben Nutzer

Reputation: 1163

The idea is to specify in which time points the data exists. For example, the bars from id == 1 exist at four different points in time (namely in 1,2,3,4), id == 2 in three, and so on:

library(tidyr)
library(dplyr)
library(gganimate)
df <- data.frame(id = factor(c(1:4)),
                 var1 = c(0, 20,60, 80),
                 var2 = c(18, 64, 91, 100),
                 var3 = c(8, 73, 100, 100),
                 var4 = c(18, 48, 67, 85))

df$show_time <- 1:4
for(i in 1:nrow(df)){
          df$show_time[i] <- list(df$show_time[i][[1]]:4)
}
df <- unnest(df, show_time)

Here is what it looks like:

> head(df, 5)
  id show_time variable value
1  1         1     var1     0
2  1         2     var1     0
3  1         3     var1     0
4  1         4     var1     0
5  2         2     var1    20

From here I reshape the data in to the proposed format and plot the animation:

df <- gather(df, variable, value, -c(id,show_time))  # reshape

ggplot(data = df, aes(x = variable, y = value, fill = id)) + 
          geom_bar(stat = "identity", position = "dodge") +
          transition_states(show_time, wrap = F) 

This is the result:

enter image description here


EDIT One way (I am sure there are others) to reveal the bars slowly instead of having them appear suddenly is tuning the transition_length argument within the transition_states function and add enter_fade to the animation.

ggplot(data = df, aes(x = variable, y = value, fill = id)) + 
          geom_bar(stat = "identity", position = "dodge") +
          transition_states(show_time, wrap = F, transition_length = 5) +
          enter_fade()

Additionally, you could let the bars 'drift' into the plot:

ggplot(data = df, aes(x = variable, y = value, fill = id)) + 
          geom_bar(stat = "identity", position = "dodge") +
          transition_states(show_time, wrap = F, transition_length = 5) +
          enter_fade() +
          enter_drift(x_mod = 0, y_mod = -max(df$value))

Like I said, there are probably a lot of different ways to do it, but it is a start:

enter image description here

Upvotes: 3

Related Questions