Line chart

Used geometries

Main geometry:

  • geom_line

Secondary geometries:

  • geom_point
  • geom_text_repel
  • geom_abline
  • geom_segment
  • geom_star

We need to load the following packages:

We load the file covid_data.csv in R.

library(readr)
covid_data <- read_csv("data/covid_data.csv", col_types = cols(date = col_date(format = "%m/%d/%Y"))) 

head(covid_data)
# A tibble: 6 × 14
  iso3c country date       confirmed deaths recovered total_tests region  income
  <chr> <chr>   <date>         <dbl>  <dbl>     <dbl>       <dbl> <chr>   <chr> 
1 ABW   Aruba   2020-03-13        NA     NA        NA          NA Latin … High …
2 ABW   Aruba   2020-03-14        NA     NA        NA          NA Latin … High …
3 ABW   Aruba   2020-03-15        NA     NA        NA          NA Latin … High …
4 ABW   Aruba   2020-03-16        NA     NA        NA          NA Latin … High …
5 ABW   Aruba   2020-03-17        NA     NA        NA          NA Latin … High …
6 ABW   Aruba   2020-03-18        NA     NA        NA          NA Latin … High …
# ℹ 5 more variables: population <dbl>, pop_density <dbl>,
#   life_expectancy <dbl>, gdp_capita <dbl>, timestamp <dttm>

Let’s have a look at the types of variables:

glimpse(covid_data)
Rows: 132,236
Columns: 14
$ iso3c           <chr> "ABW", "ABW", "ABW", "ABW", "ABW", "ABW", "ABW", "ABW"…
$ country         <chr> "Aruba", "Aruba", "Aruba", "Aruba", "Aruba", "Aruba", …
$ date            <date> 2020-03-13, 2020-03-14, 2020-03-15, 2020-03-16, 2020-…
$ confirmed       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ deaths          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ recovered       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ total_tests     <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ region          <chr> "Latin America & Caribbean", "Latin America & Caribbea…
$ income          <chr> "High income", "High income", "High income", "High inc…
$ population      <dbl> 106766, 106766, 106766, 106766, 106766, 106766, 106766…
$ pop_density     <dbl> 593.1444, 593.1444, 593.1444, 593.1444, 593.1444, 593.…
$ life_expectancy <dbl> 76.293, 76.293, 76.293, 76.293, 76.293, 76.293, 76.293…
$ gdp_capita      <dbl> 26631.47, 26631.47, 26631.47, 26631.47, 26631.47, 2663…
$ timestamp       <dttm> 2021-10-09 02:10:32, 2021-10-09 02:10:32, 2021-10-09 …

The data frame contains 132236 rows and 14 variables. There are 8 numeric variables, 4 variables of character type, and 2 variables with dates (one of date type and the other of dttm type):

The data cover a period from 2019-12-31 to 2021-10-07.

focus_cn <- c("AUS", "BEL", "BRA","CAN","CHN", "FRA", "DEU","GBR",
              "IND", "IRN", "IRL","JPN","ITA", "NLD", "KOR",
               "ESP", "USA")

covid_deaths <- covid_data %>%
  select(date, country, iso3c, deaths) %>%
  group_by(iso3c) %>%
  arrange(date) %>%
  filter(deaths > 9, date < "2020-04-09") %>%
  mutate(days_elapsed = date - min(date),
         end_label = ifelse(date == max(date), country, NA),
         end_label = case_when(iso3c %in% focus_cn ~ end_label,
                      TRUE ~ NA_character_),
         cgroup = case_when(iso3c %in% focus_cn ~ country,
                   TRUE ~ "OTHER")) %>% 
  filter(days_elapsed < 45) |> 
  ungroup()

We also set particular colors for the selected countries:

# Colors

cgroup_cols <- c("gray70", "gray70", "gray70", "gray70", 
                 "#F69E2F", "#268EC1","gray70","gray70",
                 "gray60", "gray70", "gray30","#7CD6D7",
                 "gray70","#7CD6D7","#298DC3", "#B82E5D", 
                 "#EC5B8F")


# stars
df_stars <- data.frame(
  x_star = c(6.8, 9.7, 10.2, 15, 7.5, 6.5, 2.2, 0.25),
  y_star = c(200, 145, 385, 800, 120, 55, 30, 10),
  group_star = c("a", "a", "b", "c", "d", "d", "e", "d")
)

cgroup_cols2 <- c("#268EC1", "#B82E5D", "gray30", "gray60", "#F69E2F")


# line annotations
df_lines <- data.frame(
  x = c(10, 22, 35, 35),
  y = c(10^4, 2.5*10^4, 3.3*10^4, 350),
  labels = c("DEATHS DOUBLE \n EVERY DAY", "...EVERY \n 2 DAYS",
            "...EVERY \n 3 DAYS", "...EVERY WEEK")
)
death_log_curves <- covid_deaths %>% filter(cgroup != "OTHER") %>% 
  ggplot(mapping = aes(x = days_elapsed, y = deaths,
                       color = cgroup, label = end_label,
                       group = iso3c)) +
  geom_line(size = 1.2) +
  geom_point(data = covid_deaths |> 
               dplyr::group_by(cgroup) |> filter(days_elapsed==max(days_elapsed),
                                                 cgroup != "OTHER"),
             aes(x = days_elapsed, y = deaths, fill = cgroup), shape = 21, 
             size = 3.3, stroke = 1.0, color = "grey30") +
  geom_text_repel(nudge_x = 0.2,
                  nudge_y = 0.1, size = 4,
                  segment.color = NA) +
  scale_color_manual(values = cgroup_cols) +
  scale_fill_manual(values = cgroup_cols) +  
  geom_abline(intercept = log10(10), slope = log10(1.42), linetype = "dashed", color = "gray", linewidth = 0.8) +
  geom_abline(intercept = log10(10), slope = log10(1.26), linetype = "dashed", color = "gray", linewidth = 0.8) +
  geom_abline(intercept = log10(10), slope = log10(1.105), linetype = "dashed", color = "gray", linewidth = 0.8) +
  geom_segment(aes(x = 0, y = 10,
                   xend = 10, yend = 10000), linetype = "dashed", color = "gray", linewidth = 0.8) + 
  new_scale_fill() +
  geom_star(data = df_stars, aes(x = x_star, y = y_star, fill = group_star), starstroke = 0.9, size = 3.5, inherit.aes = F) +
  scale_fill_manual(values = cgroup_cols2) +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_log10(
    label = scales::comma, sec.axis = dup_axis(), limits = c(10, 33000),
    breaks = c(10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000)) +
  labs(x = "Number of days Since 10th death →",
       title = "Coronavirus deaths in Italy, Spain, the UK and US are increasing more rapidly than they did in China",
       subtitle = "Cumulative number of deaths, by number of days since 10th deaths \n \ \ \ \ Stars represent national lockdowns *",
       caption = "Data: https://coronavirus.jhu.edu/map.html") +
  theme(panel.background = element_rect(fill = "#FFF1E6"),
        plot.background = element_rect(fill = "#FFF1E6"),
        panel.grid.major = element_line(color = "#EEE0D5"),
        panel.grid.minor = element_blank(),
        plot.title = element_text(size = 16, hjust = -0.95),
        plot.subtitle = element_text(size = 13, hjust = -0.11, color = "grey30"),
        axis.title.y = element_blank(),
        axis.text = element_text(size = 12),
        axis.ticks = element_blank(),
        legend.position = "none"
        ) +
  annotate("text", x = df_lines$x, y = df_lines$y, label = df_lines$labels, color = "grey50") +
  annotate("text", x = 43, y = 2.5*1000, label = "China", color = "#F69E2F")

death_log_curves
Figure 1: Final chart
Back to top