Skip to content

Instantly share code, notes, and snippets.

@favstats
Created January 11, 2022 19:17
Show Gist options
  • Save favstats/a5b3f246b5e59a0a15ecde4e52a36287 to your computer and use it in GitHub Desktop.
Save favstats/a5b3f246b5e59a0a15ecde4e52a36287 to your computer and use it in GitHub Desktop.
## Create NYT Spiral Animations
## Most Code comes from here: https://bydata.github.io/nyt-corona-spiral-chart/
library(tidyverse)
library(lubridate)
library(gganimate)
library(viridis)
owid_url <- "https://github.com/owid/covid-19-data/blob/master/public/data/owid-covid-data.csv?raw=true"
covid <- read_csv(owid_url)
first_rows <- covid %>%
distinct(location) %>%
mutate(date = as_date("2020-01-01"),
new_cases = 0,
new_cases_smoothed = 0,
new_cases_per_million = 0,
new_cases_smoothed_per_million = 0,
new_deaths = 0,
new_deaths_smoothed = 0,
new_deaths_per_million = 0,
new_deaths_smoothed_per_million = 0)
covid_cases <- covid %>%
select(date,
new_cases,
new_cases_smoothed,
new_deaths,
new_deaths_smoothed,
new_cases_per_million,
new_cases_smoothed_per_million,
new_deaths_per_million,
new_deaths_smoothed_per_million,
location) %>%
# Add the dates before the 1st confirmed case
bind_rows(first_rows) %>%
arrange(date) %>%
group_by(location) %>%
complete(date = seq(min(.$date), max(.$date), by = 1),
fill = list(new_cases = 0,
new_cases_smoothed = 0,
new_cases_per_million = 0,
new_cases_smoothed_per_million = 0,
new_deaths = 0,
new_deaths_smoothed = 0,
new_deaths_per_million = 0,
new_deaths_smoothed_per_million = 0)) %>%
mutate(day_of_year = yday(date),
year = year(date)
) %>%
ungroup() %>%
# 2020 is a leap year, we could drop Feb 29, 2020 for the sake of 365-day years
filter(date != as_date("2020-02-29")) %>%
group_by(year, location) %>%
mutate(day_of_year = row_number()) %>%
ungroup()
saveRDS(covid_cases, file = "data/covid_cases.rds")
##### plot #####
size_factor <- 12000
# Colors
outline_color <- "#D97C86"
fill_color <- "#F0C0C1"
base_grey <- "grey28"
month_length <- c(31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31)
month_breaks <- cumsum(month_length) - 30
p <- covid_cases %>%
mutate(date2 = date) %>%
filter(location == "Netherlands") %>%
ggplot() +
## I am plotting a ton of lines here because geom_linerange doesn't seem to work
## properly with gganimate
geom_line(aes(x = day_of_year,
y = as.POSIXct(date),
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.9,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.8,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.70,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.6,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.5,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.4,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.3,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.2,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) - new_cases_smoothed_per_million * size_factor * 0.1,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.9,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.8,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.70,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.6,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.5,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.4,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.3,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.2,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
geom_line(aes(x = day_of_year,
y = as.POSIXct(date) + new_cases_smoothed_per_million * size_factor * 0.1,
group = year, color = new_cases_smoothed_per_million),
width = 0,
# color = outline_color,
size=1.75,
show.legend = T) +
# annotate("text", label = paste0(year_annotations$year, "\u2192"), x = year_annotations$x,
# y = year_annotations$y,
# family = "Arial",
# size = 1, vjust = 1.3, hjust = 0.15) +
# basic line
scale_x_continuous(minor_breaks = month_breaks,
breaks = month_breaks,
labels = c("Jan.", "Feb.", "March", "April", "May", "June", "July", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."),
limits = c(1, 365),
expand = c(0, 0)
) +
#' set the lower limit of the y-axis to a date before 2020
#' so that the spiral does not start in the center point
scale_y_continuous(limits = c(as.POSIXct("2019-07-01"), NA),
expand = c(0, 0)) +
coord_polar() +
theme_void() +
labs(title = "COVID-19 in the Netherlands",
subtitle="7-day Average COVID cases per illion people\n",
caption="Data: Our World in Data | Inspired by: NYT | Initial Code: Ansgar Wolsing (@_ansgar) | Animation: Fabio Votta (@favstats)") +
theme(
legend.position = "bottom",
plot.title = element_text(hjust = 0.5, size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 7),
plot.caption = element_text(hjust = 1, size = 3.5),
plot.background = element_rect(color = NA, fill = "white"),
panel.grid.major.x = element_line(color = "grey70", size = 0.2, linetype = "dotted"),
panel.grid.minor.x = element_line(color = "grey70", size = 0.2, linetype = "dotted"),
axis.text.x = element_text(color = base_grey, size = 5, hjust = 0.5)
) +
viridis::scale_color_viridis(option = "rocket", direction = -1) +
guides(color = guide_colourbar(title = "7-day Average COVID cases per million",
title.vjust = 1,
title.theme = element_text(size = 6.5),
label.theme = element_text(size = 3.5),
barwidth = 5, barheight = 0.5)) +
transition_reveal(date) +
ease_aes('linear')
p <- p %>%
animate(nframes = 300, fps = 20, #duration = 25,
width = 1000, height = 1000,
res = 300, end_pause = 60)
anim_save("netherlands.gif", animation = p)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment