animated-line-graph.R
Code used to make the graph found within "Animated Line Graphs"
library(gganimate)
library(ggplot2)
library(dplyr)
library(hash)
covid <- readxl::read_excel("covid.xlsx")
covid$date <- as.Date(covid$date)
world <- covid |>
filter(location=="World") |>
filter(!is.na(total_cases)) |>
filter(date < "2023-01-01") |>
select(date, new_deaths_smoothed)
annotations <- data.frame(keys=list(), values=list())
annotations <- data.frame(keys='First U.S. Death', values='2020-02-06')
annotations <- add_row(annotations, keys='CDC Mask Recommendation', values='2020-04-03')
annotations <- add_row(annotations, keys='Vaccines Released in the U.S.', values='2020-12-14')
annotations <- add_row(annotations, keys='FDA Authorizes Booster Shots', values='2021-11-19')
annotations <- add_row(annotations, keys='WHO Declares Omnicron Variant of Concern', values='2021-11-26')
bullet_effect <- function(dates_to_slow, strength){
world$show_time = case_when(world$date %in% dates_to_slow ~ strength, TRUE~1)
world$reveal_time = cumsum(world$show_time)
return(world)
}
world <- bullet_effect(annotations$values, 100)
ylimit <- 15000
find_y_value <- function(data_value, y_lim, index){
if(index %% 2 == 1){
y_value = ifelse(data_value + y_lim/5 < y_lim, data_value + y_lim/5, data_value - y_lim/5)
}
else{
y_value = ifelse(data_value - y_lim/5 > 1000, data_value - y_lim/5, data_value + y_lim/5)
}
return(y_value)
}
plot_text_annotation <- function(){
text_list <- geom_label(y=0,x=0,label="")
for(i in 1:length(annotations$values)){
y_value <- find_y_value(world$new_deaths_smoothed[world$date==as.Date(annotations$values[i])], ylimit, i)
text_list <- c(text_list,geom_label(label=as.character(annotations$keys[i]),
color=scales::alpha('black',ifelse(world$date>=as.Date(annotations$values[i]), 1, 0)),
x=as.Date(annotations$values[i]),
y=y_value,
fill = alpha(c("white"),ifelse(world$date>=as.Date(annotations$values[i]), 1, 0))))
}
return(text_list)
}
plot_segment_annotation <- function(){
segment_list <- geom_segment(y=0,x=0,xend=0,yend=0)
for(i in 1:length(annotations$values)){
y_value <- find_y_value(world$new_deaths_smoothed[world$date==as.Date(annotations$values[i])], ylimit, i)
segment_list <- c(segment_list, geom_segment(xend=as.Date(annotations$values[i]),
yend=world$new_deaths_smoothed[world$date==as.Date(annotations$values[i])],
x=as.Date(annotations$values[i]),y=y_value,
alpha=ifelse(world$date>=as.Date(annotations$values[i]), 1, 0),
linetype="dashed"))
}
return(segment_list)
}
animation <- world |>
ggplot(aes(x=date, y=new_deaths_smoothed))+
theme_minimal()+
labs(title="New COVID-19 Worldwide Deaths",
subtitle="{world$date[min(which(world$reveal_time >= floor(frame_along)))]}",
caption="Nikhil Chinchalkar for Princeton University | OurWorldInData | 2024")+
xlab('Date')+
ylab('New Deaths Per Week')+
theme(plot.title = ggtext::element_markdown(size = 22, hjust =0.5, face = "bold"),
plot.subtitle = ggtext::element_markdown(size = 10, hjust =0.5, face = "bold"),
axis.text.x=element_text(size=10))+
ylim(0,ylimit)+
plot_segment_annotation()+
geom_line()+
plot_text_annotation()+
scale_alpha(guide='none')+
transition_reveal(reveal_time)
animate(animation, fps = 15, duration = 30, end_pause=75, height = 7,
width = 9, units = "in", res = 200)
Last updated