I have a simple bar chart that I am trying to animate. I am not far from the intended result but I am out of ideas now.
I want to reveal one bar at a time and keep the previous ones using geom_col()
.
Here a sample df
:
fr<- structure(list(HOME = c("Verona", "Atalanta", "Genk"), AWAY = c("Inter",
"Fiorentina", "Gent"), Domicile = c(5.7034e-08, 0.9916, 0.37966
), Nul = c(0.0015489, 0.0083796, 0.39583), Défaite = c(0.99845,
2.0228e-05, 0.22451)), row.names = c(NA, -3L), class = c("tbl_df",
"tbl", "data.frame"))
My first intention is to add a "state-zero" of initiation for each group, so I change my df as such:
fr<-fr %>%
slice(1:nrow(.), row_number()) %>%
mutate(across(c((ncol(.)-3+1):(ncol(.))),~base::as.numeric(ifelse(row_number() <= 0.5*n(), 0, .x)))) %>%
group_by(HOME,AWAY) %>%
mutate(ID = seq_along(HOME)) %>%
pivot_longer(
cols=c(Domicile, Nul, Défaite),
values_to="prob",
names_to = "type") %>%
mutate(game=paste0(HOME," - ", AWAY))
fr$type <-factor(fr$type,levels=c("Domicile","Nul","Défaite"))
and then I plot as follows:
f <- ggplot(fr, aes(x = type, y = prob))
f<-f+geom_col(aes(fill = type,group=game)) +
geom_text(aes(label=ifelse(prob > 0,sprintf("%0.2f%%",prob*100),""),
y=prob+0.15,color=type),fontface = "bold",family="Oswald", size=4)+
facet_wrap(~game, scale="fixed",axes = "all_x",as.table = TRUE)+
labs(subtitle = "Estimations après simulation de Monte Carlo sur un paramètre interne")+
transition_states(type, wrap=FALSE)+
enter_grow()+
shadow_mark(past = TRUE)
f
However, two problems arise. First I have the fist bar corresponding to domicile which is already present meaning we don't see it grow. And finally, bars don't grow from the bottom and the percentage text label doesn't grow with the bar height but instead is already at its final value.
Here is the output I have managed to get so far:
Thank you for your help.
**EDIT 10/09/24: **
In the meantime I found a solution that is I believe the correct way around this issue. The first part is actually achieving the same result as @stefan's reply.
So first I added a frame
variable to match the transition_states()
I wanted by doing the following:
fr<- fr%>%
mutate(type=factor(type,levels=c("Domicile","Nul","Défaite"))) %>%
ungroup() %>%
arrange(ID, type) %>%
mutate(frame2 = letters[rep(1:nrow(.), each = 3, length.out = nrow(.))]) %>%
mutate(prob = round(prob, 4))
Then on the graph side, I transition using the new frame2
variable, and to have the geom_text()
follow the bar height, I found out we could add an enter_fly
parameter that does the job just fine.
I've also added some modification on the scaly_y_continous
.
f <- ggplot(fr, aes(x = type, y = prob,fill = type, group = type))
f<-f+geom_col() +
geom_text(aes(label = ifelse(prob > 0,paste0(" ",
scales::percent(prob, accuracy = 0.01)),""),
color = type),fontface = "bold",family = "Oswald", size = 4,vjust = -1)+
scale_y_continuous(labels = scales::percent_format(accuracy = 1),expand = expansion(add = c(0,0.05)))+
facet_wrap(~game, scale = "fixed",axes = "all_x",as.table = TRUE)+
labs(subtitle = "Estimations après simulation de Monte Carlo sur un paramètre interne")+
transition_states(frame2, wrap = FALSE)+
shadow_mark(past = TRUE)+
enter_fly(y_loc = 0)
f
This is only a partial solution as it fixes or achieves only two of your desired outcomes. First, I add a fake first category or level
to your factor
type
to grow the bar for "Domicile". Second, to grow the bars from zero map type
on the group
aes. Additionally I set the group
aes globally so that it applies to the geom_text
too. As a result, the labels now also grow in line with the bars but the growing is applied to size
instead of y
. Hence, I call my solution only partial. Unfortunately I wasn't able to find an option to fix that.
library(gganimate)
library(ggplot2)
library(dplyr, warn = FALSE)
# Add a fake first category to grow the bar for "Domicile"
fr$type <- factor(fr$type, levels = c("FOO", "Domicile", "Nul", "Défaite"))
# 1. group by type to grow the bars from zero
# 2. Set group globally for all geoms
ggplot(fr, aes(x = type, y = prob, group = type)) +
geom_col(aes(fill = type)) +
geom_text(aes(
label = ifelse(prob > 0, sprintf("%0.2f%%", prob * 100), ""),
y = prob + 0.15, color = type
), fontface = "bold", family = "sans") +
facet_wrap(~game, scale = "fixed", axes = "all_x", as.table = TRUE) +
labs(subtitle = "Estimations après simulation de Monte Carlo sur un paramètre interne") +
transition_states(type, wrap = FALSE) +
enter_grow() +
shadow_mark(past = TRUE)