scripts/manuscript_figures.R

# How to make figures in manuscript
# 1. Download files from https://drive.google.com/open?id=150nv86_WLibdEAZDurlOe1X-TWV0sc8S
# (this is Data/vaxedemic_manuscript_data.zip in the vaxedemic google drive folder)
# 2. make a directory in your vaxedemic code main folder (so one down from the folder containing this script) called "outputs"
# 3. unzip the files there, maintaining data structure.  there should now be two directories outputs/deaths_only/ 
# and outputs/pd0no_vaccination/ containing
# e.g. outputs/deaths_only/pd0no_vaccination/no_vaccination_fixed_global_deaths.rds
# 4. set your working directory to the vaxedemic code main folder and run devtools::load_all()
# 5. change save_dir on line 20 of this script to a folder on your drive
# 6. source this script
# 7. run 
# make_Fig1(TRUE, TRUE)
# make_Fig2(TRUE, TRUE)
# make_Fig3(TRUE, TRUE)
# make_Fig3(FALSE, FALSE, TRUE, TRUE)
# make_FigS1(TRUE, TRUE)
# make_FigS2(TRUE, TRUE)
# the raw data for Fig 1 is in https://drive.google.com/open?id=1540gR4un0Dz-m3P3TB9JhdnFIR3iAqJi
# in case you want to revisualise
# (this is Data/no_vax_manuscript_data.zip in the vaxedemic google drive folder)
# contact Ada with any questions

# directory in which to save plots and tables
save_dir <- "~/overleaf/vaxedemic_manuscript/figs_delayed_protection/"

make_dirname <- function(strategy, production_delay, stockpile_size, free_param, seedCountries) {
  # no vaccination results are independent of production delay and stockpile size, so we only ran them once
  if(strategy == "no_vaccination") {
    production_delay <- stockpile_size <- 0 
  }
  dir_name <- paste0("outputs_delayed_protection/pd", production_delay, strategy,
                     "_stockpile", num2str(stockpile_size), "_", seedCountries, "/")
  if(!dir.exists(dir_name)) {
    message(dir_name)
    dir_name <- paste0("outputs/deaths_only/pd", production_delay, strategy, "/")
  }
  dir_name
}

read_median_global_deaths <- function(strategy, production_delay, stockpile_size, free_param, seedCountries) {
  
  dir_name <- make_dirname(strategy, production_delay, stockpile_size, free_param, seedCountries)
  print(dir_name)
  if(strategy %in% c("incidence", "curr_alloc", "no_vaccination")) {
    filename <- paste0(dir_name, strategy, "_fixed_median_deaths.rds")
  } else {
    filename <- paste0(dir_name, strategy, "_coverage_data_", 
                       num2str(free_param), "_median_deaths.rds")
  }
  if(file.exists(filename)) {
    readRDS(filename)
  } else {
    source_filename <- sub("_median", "", filename, fixed = TRUE)
    median_global_deaths <- calc_median_global_deaths(source_filename)
    saveRDS(median_global_deaths, filename)
    median_global_deaths
  }
}

read_global_deaths <- function(strategy, production_delay, stockpile_size, free_param, seedCountries,
                               alloc_split = "global") {
  dir_name <- make_dirname(strategy, production_delay, stockpile_size, free_param, seedCountries)
  
  if(strategy %in% c("incidence", "curr_alloc", "no_vaccination")) {
    filename <- paste0(dir_name, strategy, "_fixed_",
                       alloc_split, "_deaths.rds")
  } else {
    filename <- paste0(dir_name, strategy, "_coverage_data_", 
                       num2str(free_param), "_", alloc_split, "_deaths.rds")
  }
  if(file.exists(filename)) {
    readRDS(filename)
  } else {
    source_filename <- sub(paste0("_", alloc_split), "", filename, fixed = TRUE)
    global_deaths <- calc_global_deaths(source_filename, alloc_split)
    saveRDS(global_deaths, filename)
    global_deaths
  }
}

bootstrap_deaths_averted <- function(strategies, production_delays, 
                                     stockpile_sizes, free_params, 
                                     seedCountries, alloc_split = "global") {
  # set seed for reproducible bootstrapping
  set.seed(1)
  label_with_strategy <- function(global_deaths, strategy_label) {
    data.frame(deaths = global_deaths, 
               strategy = strategy_label)
  }
  
  global_deaths <- Map(read_global_deaths, strategies, production_delays, 
                       stockpile_sizes, free_params, seedCountries,
                       alloc_split) %>%
    Map(label_with_strategy, ., c(1,2)) %>%
    do.call(rbind, .)
  
  difference_medians <- function(data, indices) {
    d <- data[indices,1]
    d1 <- d[data$strategy == 1]
    d2 <- d[data$strategy == 2]
    median(d1) - median(d2)
  }
  
  boot::boot(global_deaths, difference_medians, 500, strata = global_deaths$strategy)
}

bootstrap_median_deaths <- function(strategy, production_delay, stockpile_size, 
                                    free_param, seedCountries, alloc_split = "global") {
  # set seed for reproducible bootstrapping
  set.seed(1)  
  global_deaths <- read_global_deaths(strategy, production_delay, stockpile_size,
                                      free_param, seedCountries, alloc_split)
  my_median <- function(data, indices) {
    median(data[indices])
  }
  
  boot::boot(global_deaths, my_median, 500)
}

bootstrap_median_deaths_wrapper <- function(strategy, production_delay, 
                                            stockpile_size = 0, free_param = 0, 
                                            seedCountries, alloc_split = "global") {
  production_delay <- as.numeric(production_delay)
  stockpile_size <- as.numeric(stockpile_size)
  free_param <- as.numeric(free_param)
  bootstrap_sol <- bootstrap_median_deaths(strategy, production_delay, 
                                           stockpile_size, free_param, 
                                           seedCountries, alloc_split)
  quantile(bootstrap_sol$t, probs = c(.025, .5, .975))
}

bootstrap_deaths_averted_wrapper <- function(strategy, production_delay, 
                                             stockpile_size = 0, free_param = 0, 
                                             seedCountries, alloc_split = "global") {
  production_delay <- as.numeric(production_delay)
  stockpile_size <- as.numeric(stockpile_size)
  free_param <- as.numeric(free_param)
  strategies <- c("no_vaccination", strategy)
  production_delays <- c(0, production_delay)
  stockpile_sizes <- rep(stockpile_size, 2)
  free_params <- c(0, free_param)
  seedCountries <- rep(seedCountries, 2)
  bootstrap_sol <- bootstrap_deaths_averted(strategies, production_delays, 
                                            stockpile_sizes, free_params, 
                                            seedCountries, alloc_split)
  quantile(bootstrap_sol$t, probs = c(.025, .5, .975))
}

print_table <- function(pars, filename, strategy) {
  bootstrap <- any(grepl("lower", colnames(pars)))
  
  if(bootstrap) {
    print(xtable::xtable(pars),
          sanitize.text.function = identity,
          file = filename)
    pars <- pars[,-grep("lower", colnames(pars))]
    pars <- pars[,-grep("upper", colnames(pars))]
  }
  
  if(missing(strategy)) {
    pars$strategy <- factor(pars$strategy, 
                            levels = c("No vaccination", "Current allocation", "Incidence"))
    pars <- pars[order(pars$strategy),]
  } else {
    pars <- pars[pars$strategy == strategy, -1]
  }  
  
  
  levels(pars$production_delay)[1] <- 0
  levels(pars$production_delay) <- c(levels(pars$production_delay), "NA")
  
  pars$stockpile_size <- pars$stockpile_size / 1e6
  
  round_colnames <- c("stockpile_size", "median_deaths", "deaths_averted")
  pars[,round_colnames] <- 
    t(apply(pars[, round_colnames], 1, function(x) as.character(round(x))))
  
  pars[pars$strategy == "No vaccination", c("production_delay", "stockpile_size", "deaths_averted")] <- "NA"
  
  alignment <- rep("r", ncol(pars) + 1) 
  if(missing(strategy)) {
    colnames(pars) <- c("Strategy", 
                        "Production delay (days)", 
                        "Stockpile size (million)",
                        "Median deaths",
                        "Deaths averted")
    alignment[2] <- "l"
  } else {
    if(strategy == "Top n countries") {
      free_param_name <- "$n$"
    } else {
      free_param_name <- "$\\alpha$"
    }
    colnames(pars) <- c("Production delay (days)", 
                        free_param_name,
                        "Stockpile size (million)",
                        "Median deaths",
                        "Deaths averted")
  }
  
  rownames(pars) <- NULL
  
  print(xtable::xtable(pars, align = alignment),
        sanitize.text.function = identity,
        file = filename, include.rownames=FALSE, append = bootstrap)
}

#' make Fig. 1 in the manuscript: Simulation results without vaccination: attack rates and peak times by country.
#' @param save_output logical: whether to save the output as a pdf as well as outputting the ggplot object
#' @output a list of two ggplot objects: attack_rates and peak_times
make_Fig1 <- function(save_output) {
  
  read_and_sort_data <- function(filename) {
    dat <- read.csv(filename)
    # sort countries by latitude
    dat$Location <- as.character(dat$Location)
    dat$Location <- factor(dat$Location, 
                           levels = as.character(dat$Location[order(dat$latitude)]))
    dat
  }
  
  # read in median and 95% CI for attack rates for each country
  attack_rates_data <- read_and_sort_data("outputs/pd0no_vaccination/no_vaccination_country_attack_rates_fixed_median_ci.csv")
  # plot attack rates
  attack_rates <- plot_country_attack_rates(attack_rates_data)
  
  # read in median and 95% CI for peak times for each country
  peak_times_data <- read_and_sort_data("outputs/pd0no_vaccination/no_vaccination_peakTimes_fixed_median_ci.csv")
  # plot peak times
  peak_times <- plot_peak_times(peak_times_data)
  
  # save output
  if(save_output) {
    png(paste0(save_dir, "no_vaccination_country_attack_rates_fixed_plot.png"),width=800,height=1200)
    plot(attack_rates)
    dev.off()
    png(paste0(save_dir, "no_vaccination_peakTimes_fixed_plot.png"),width=800,height=1200)
    plot(peak_times)
    dev.off()
  }
  
  list(attack_rates = attack_rates, peak_times = peak_times)
}

#' make Fig. 2 in the manuscript: comparing deaths averted for allocation by incidence vs current allocation,
#' for different production delays
#' 
#' deaths averted = median deaths over n simulations of no vaccination,
#' minus median deaths over n simulations of vaccination
#' 
#' @param save_output logical: whether to save the output as a pdf as well as outputting the ggplot object
#' @param bootstrap logical: if TRUE, plot median and 95% CI for deaths averted, calculated using
#' bootstrap replicates of the stochastic simulations.  if FALSE, plot point
#' estimate of deaths averted only.
#' @output a list of three objects:
#' pars is a data frame containing the median deaths and deaths averted under each
#' vaccination strategy and production delay.  if bootsrap = TRUE, also contains 95% CI.
#' plot1 and plot2 are ggplot objects: two different visualisations of the deaths averted
make_Fig2 <- function(save_output = FALSE, bootstrap = TRUE) {
  # define vaccination strategies to plot
  strategy <- c("incidence",
                "curr_alloc")
  # define production delays to plot
  production_delay <- c(0, 0, 90, 180)
  # make grid of all combinations of vaccination strategies and production delays
  pars <- expand.grid(strategy = strategy, production_delay = production_delay,
                      stringsAsFactors = FALSE)
  pars <- rbind(pars, data.frame(strategy = "no_vaccination", production_delay = 0,
                                 stringsAsFactors = FALSE))
  # define other parameters (used to construct filename from which to read the data)
  pars$stockpile_size <- 0
  pars[seq_along(strategy),"stockpile_size"] <- 550e6
  pars$seedCountries <- "China"
  pars$free_param <- 0
  if(bootstrap) {
    # calculate median and 95% CI for the median deaths under each vaccination strategy
    # and production delay
    median_deaths <- t(apply_named_args(pars, 1, bootstrap_median_deaths_wrapper)) %>%
      as.data.frame
    # calculate median and 95% CI for the deaths averted under each vaccination strategy
    # and production delay
    deaths_averted <- t(apply_named_args(pars, 1, bootstrap_deaths_averted_wrapper)) %>%
      as.data.frame
    # do.call(rbind, .)
    
    # format stuff
    colnames(median_deaths) <- c("lower_deaths", "median_deaths", "upper_deaths")
    colnames(deaths_averted) <- c("lower_deaths_averted", "deaths_averted", "upper_deaths_averted")
    pars <- cbind(pars, as.data.frame(median_deaths), as.data.frame(deaths_averted))
    pars$strategy <- factor(pars$strategy, 
                            levels = c("no_vaccination", "curr_alloc", "incidence"))
    levels(pars$strategy) <- c("No vaccination", "Current allocation", "Incidence")
  } else {
    pars <- rbind(pars, data.frame(strategy = "no_vaccination",
                                   production_delay = 0,
                                   stockpile_size = 0,
                                   seedCountries = pars$seedCountries[1],
                                   stringsAsFactors = FALSE))
    # read in median deaths under each vaccination strategy
    # and production delay, as well as median deaths under no vaccination
    pars$median_deaths <- Map_vapply(read_median_global_deaths, numeric(1), 
                                     pars$strategy, 
                                     pars$production_delay,
                                     pars$stockpile_size,
                                     seedCountries = pars$seedCountries)
    # calculate deaths averted = median deaths with no vaccination - median deaths with vaccination
    pars$deaths_averted <- pars[pars$strategy == "no_vaccination", "median_deaths"] - pars$median_deaths
    # format stuff
    levels(pars$strategy) <- c("Incidence", "Current allocation", "No vaccination")
    pars$strategy <- factor(pars$strategy, 
                            levels = c("Current allocation", "Incidence", "No vaccination"))
    
  }

  pars[pars$stockpile_size > 0, "production_delay"] <- "stockpile"
  pars$production_delay <- factor(pars$production_delay, levels = unique(pars$production_delay))

  # make plots
  plot_wrapper <- function(production_delay_subset) {
    pars <- pars[pars$production_delay %in% production_delay_subset,]
    y_breaks <- seq(0, max(pars$deaths_averted) * 1.1, by = 1e5)
    plot1 <- ggplot(pars[pars$strategy != "No vaccination",], aes(x = production_delay, y = deaths_averted, fill = strategy)) +
      geom_bar(stat = "identity") +
      facet_wrap(~strategy, nrow = 1) +
      scale_y_continuous(breaks = y_breaks, 
                         labels = formatC(y_breaks / 1e5, digits = 2),
                         expand = expand_scale(mult = c(0, .1))) +
      xlab("Production delay (days)") +
      ylab("Deaths averted (x100,000)") +
      theme_bw() +
      theme(legend.position = "none",
            text = element_text(size = 12)) +
      scale_fill_manual(values = gg_color_hue(4)[c(1,4)])
    if(bootstrap) {
      plot1 <- plot1 + geom_errorbar(aes(ymin = lower_deaths_averted, ymax = upper_deaths_averted))
    }
    if(save_output) {
      width <- 20
      height <- 10
      filename_temp <- paste0(save_dir, "Fig2_", production_delay_subset[1])
      ggsave(paste0(filename_temp, ".pdf"),
             plot1, width = width, height = height, units = "cm")
      png(paste0(filename_temp, ".png"),width=width,height=height, units = "cm", res = 300)
      plot(plot1)
      dev.off()
      saveRDS(plot1, file = paste0(filename_temp, ".rds"))
    }
    plot1
  }
  production_delay_subset <- list(c("stockpile", 0),
                                  c(90, 180))
  plot1 <- lapply(production_delay_subset, plot_wrapper)
  # save output as files
  if(save_output) {
    print_table(pars, filename = paste0(save_dir, "Fig2.tex"))
  }
  
  list(table = pars, plot1 = plot1)
}

#' make Fig. 3 in the manuscript: comparing deaths averted for allocation strategies by population size,
#' for different production delays
#' 
#' deaths averted = median deaths over m simulations of no vaccination,
#' minus median deaths over m simulations of vaccination
#' strategy 1 = vaccinate top n countries by population size,
#' with equal allocation to each of those countries by capita
#' strategy 2 = allocate vaccines per capita to each country
#' proportional to x^alpha where x in the population size and alpha is a parameter
#' 
#' @inheritParams make_Fig2
#' 
#' @output a list of three objects:
#' pars is a data frame containing the median deaths and deaths averted under each
#' vaccination strategy and production delay.  if bootsrap = TRUE, also contains 95% CI.
#' plot1 and plot2 are ggplot objects: two different visualisations of the deaths averted
make_Fig3 <- function(plot_reference_curr_alloc = FALSE, 
                      plot_reference_curr_alloc_separate_panel = FALSE,
                      save_output = FALSE, bootstrap = TRUE) {
  # values of n for strategy 1
  n_countries <- c(1, 2, 5, 10, 127)
  # values of alpha for strategy 2
  alpha <- c(.5, 1, 2, 3)
  
  # define production delays to plot
  production_delay <- c(0, 0, 90, 180)
  # make grid of all combinations of vaccination strategies and production delays
  pars <- expand.grid(strategy = "top_n_countries", 
                      production_delay = production_delay,
                      free_param = n_countries,
                      stringsAsFactors = FALSE)
  pars <- rbind(pars, expand.grid(strategy = "fn_pop_size", 
                                  production_delay = production_delay,
                                  free_param = alpha,
                                  stringsAsFactors = FALSE))
  # define other parameters (used to construct filename from which to read the data)
  pars$stockpile_size <- 0
  pars[seq(1, nrow(pars), length(production_delay)),"stockpile_size"] <- 550e6
  pars$seedCountries <- "China"
  
  pars_reference <- pars[seq_len(4),]
  pars_reference$strategy <- "curr_alloc"
  pars_reference$free_param <- 0
  
  if(bootstrap) {
    # calculate median and 95% CI for the median deaths under each vaccination strategy
    # and production delay
    median_deaths <- t(apply_named_args(pars, 1, bootstrap_median_deaths_wrapper)) %>%
      as.data.frame
    # calculate median and 95% CI for the deaths averted under each vaccination strategy
    # and production delay
    deaths_averted <- t(apply_named_args(pars, 1, bootstrap_deaths_averted_wrapper)) %>%
      as.data.frame
    # format stuff
    colnames(median_deaths) <- c("lower_deaths", "median_deaths", "upper_deaths")
    colnames(deaths_averted) <- c("lower_deaths_averted", "deaths_averted", "upper_deaths_averted")
    pars <- cbind(pars, median_deaths, deaths_averted)
    pars$strategy <- factor(pars$strategy, levels = c("top_n_countries", "fn_pop_size"))
    levels(pars$strategy) <- c("Top n countries", "Function of population size")
  } else {
    pars <- rbind(pars, data.frame(strategy = "no_vaccination",
                                   production_delay = 0,
                                   stockpile_size = 0,
                                   free_param = NA,
                                   seedCountries = "China"))
    # read in median deaths under each vaccination strategy
    # and production delay, as well as median deaths under no vaccination
    pars$median_deaths <- Map_vapply(read_median_global_deaths, 
                                     numeric(1), 
                                     pars$strategy, 
                                     pars$production_delay,
                                     pars$stockpile_size,
                                     pars$free_param,
                                     pars$seedCountries)
    # calculate deaths averted = median deaths with no vaccination - median deaths with vaccination
    pars$deaths_averted <- pars[pars$strategy == "no_vaccination", "median_deaths"] - pars$median_deaths
    
    # format stuff
    levels(pars$strategy) <- c("Top n countries", "Function of population size", "No vaccination")
  }
  
  pars[pars$stockpile_size > 0, "production_delay"] <- "stockpile"
  pars$production_delay <- factor(pars$production_delay, levels = unique(pars$production_delay))
  pars$free_param <- factor(pars$free_param)
  
  # get reference values
  if(plot_reference_curr_alloc) {
    if(bootstrap) {
      # calculate median and 95% CI for the deaths averted under each vaccination strategy
      # and production delay
      deaths_averted_curr_alloc <- t(apply_named_args(pars_reference, 1, bootstrap_deaths_averted_wrapper)) %>%
        as.data.frame
      # format stuff
      colnames(deaths_averted_curr_alloc) <- c("lower_deaths_averted", "deaths_averted", "upper_deaths_averted")
      deaths_averted_curr_alloc$production_delay <- production_delay
    } else {
      stop("Not yet implemented")
      # pars <- rbind(pars, data.frame(strategy = "no_vaccination",
      #                                production_delay = 0,
      #                                stockpile_size = 0,
      #                                seedCountries = pars$seedCountries[1]))
      # # read in median deaths under each vaccination strategy
      # # and production delay, as well as median deaths under no vaccination
      # pars$median_deaths <- Map_vapply(read_median_global_deaths, numeric(1), 
      #                                  pars$strategy, 
      #                                  pars$production_delay,
      #                                  pars$stockpile_size,
      #                                  seedCountries = pars$seedCountries)
      # # calculate deaths averted = median deaths with no vaccination - median deaths with vaccination
      # pars$deaths_averted <- pars[pars$strategy == "no_vaccination", "median_deaths"] - pars$median_deaths
      # 
      # # format stuff
      # levels(pars$strategy) <- c("Incidence", "Current allocation", "No vaccination")
      # pars$strategy <- factor(pars$strategy, 
      #                         levels = c("Current allocation", "Incidence", "No vaccination"))
      
    }
    
    deaths_averted_curr_alloc[pars_reference$stockpile_size > 0, "production_delay"] <- "stockpile"
    deaths_averted_curr_alloc$production_delay <- factor(deaths_averted_curr_alloc$production_delay, levels = unique(deaths_averted_curr_alloc$production_delay))

    if(plot_reference_curr_alloc_separate_panel) {
      deaths_averted_curr_alloc <- data.frame(strategy = factor("Current Allocation",
                                                                levels = c(levels(pars$strategy), "Current Allocation")),
                                              production_delay = deaths_averted_curr_alloc$production_delay,
                                              free_param = factor(1, levels = levels(pars$free_param)),
                                              stockpile_size = 0,
                                              seedCountries = "China",
                                              lower_deaths = 0,
                                              median_deaths = 0,
                                              upper_deaths = 0,
                                              lower_deaths_averted = deaths_averted_curr_alloc$lower_deaths_averted,
                                              deaths_averted = deaths_averted_curr_alloc$deaths_averted,
                                              upper_deaths_averted = deaths_averted_curr_alloc$upper_deaths_averted)
      levels(pars$strategy) <- levels(deaths_averted_curr_alloc$strategy)
      
      pars <- rbind(pars, deaths_averted_curr_alloc)
      
    }
  }
  
  # make plots
  plot_wrapper <- function(production_delay_subset) {
    pars <- pars[pars$production_delay %in% production_delay_subset,]
    pars$production_delay <- droplevels(pars$production_delay)
    deaths_averted_curr_alloc <- deaths_averted_curr_alloc[deaths_averted_curr_alloc$production_delay %in% production_delay_subset,]
    deaths_averted_curr_alloc$production_delay <- droplevels(deaths_averted_curr_alloc$production_delay)
    if("stockpile" %in% production_delay_subset) {
      interval <- 5e5
    } else {
      interval <- 1e5
    }
    y_breaks <- seq(0, max(pars$deaths_averted) * 1.1, by = interval)

    plot1 <- ggplot(pars[pars$strategy != "No vaccination",], aes(x = free_param, y = deaths_averted, fill = strategy)) +
      geom_bar(stat = "identity")
    if(plot_reference_curr_alloc && !plot_reference_curr_alloc_separate_panel) {
      plot1 <- plot1 + geom_hline(data = deaths_averted_curr_alloc, 
                                  aes(yintercept = deaths_averted),
                                  colour = gg_color_hue(4)[4],
                                  size = 1)
    }
    
    if(plot_reference_curr_alloc && plot_reference_curr_alloc_separate_panel) {
      xlab_string <- "n                                       alpha                            "
    } else {
      xlab_string <- "n                                             alpha"
    }
    plot1 <- plot1 + 
      facet_grid(production_delay~strategy, scales = "free_x", drop = TRUE) +
      scale_y_continuous(breaks = y_breaks, 
                         labels = formatC(y_breaks / 1e5, digits = 2),
                         expand = expand_scale(mult = c(0, .1))) +
      xlab(xlab_string) +
      ylab("Deaths averted (x100,000)") +
      theme_bw() +
      theme(legend.position = "none",
            text = element_text(size = 12)) +
      scale_fill_manual(values = gg_color_hue(4)[2:3])
    
    if(bootstrap) {
      plot1 <- plot1 + geom_errorbar(aes(ymin = lower_deaths_averted, ymax = upper_deaths_averted))
    }
    
    if(save_output) {
      width <- 15
      height <- 15
      filename_temp <- paste0(save_dir, "Fig3_", production_delay_subset[1])
      ggsave(paste0(filename_temp, ".pdf"),
             plot1, width = width, height = height, units = "cm")
      png(paste0(filename_temp, ".png"),width=width,height=height, units = "cm", res = 300)
      plot(plot1)
      dev.off()
      saveRDS(plot1, file = paste0(filename_temp, ".rds"))
    }
    plot1
  }
  
  production_delay_subset <- list(c("stockpile", 0),
                                  c(90, 180))
  plot1 <- lapply(production_delay_subset, plot_wrapper)
  
  # save output as files
  if(save_output) {
    print_table(pars, filename = paste0(save_dir, "deaths_averted_top_n_countries.tex"), "Top n countries")
    print_table(pars, filename = paste0(save_dir, "deaths_averted_fn_pop_size.tex"), 
                "Function of population size")
  }
  
  list(table = pars, plot1 = plot1)
}

#' make Fig S1 in manuscript: death averted for vaccination allocation
#' accoring to incidence or corrent allocation, for different
#' seeding countries of the epidemic, and no production delay, with a stockpile
#' 
#' @inheritParams make_Fig2
#' 
#' @output a list of two objects:
#' pars is a data frame containing the median deaths and deaths averted under each
#' vaccination strategy and seed country.  if bootsrap = TRUE, also contains 95% CI.
#' plot1 is a ggplot object: visualisation of the deaths averted
make_FigS1 <- function(save_output = FALSE, bootstrap = TRUE) {
  # define vaccination strategies to plot
  strategy <- c("incidence",
                "curr_alloc")
  # define seed countries to plot
  seedCountries <- c("Belgium", "Sao_Tome_and_Principe", "Singapore", "Uganda")
  # make grid of all combinations of vaccination strategies and seed countries
  pars <- expand.grid(strategy = strategy, seedCountries = seedCountries)
  # define other parameters (used to construct filename from which to read the data)
  pars$stockpile_size <- 550e6
  pars$production_delay <- 0
  pars <- pars[,c("strategy", "production_delay", "stockpile_size", "seedCountries")]
  
  if(bootstrap) {
    # calculate median and 95% CI for the median deaths under each vaccination strategy
    # and seed country
    median_deaths <- apply_named_args(pars, 1, bootstrap_median_deaths_wrapper)
    # calculate median and 95% CI for the deaths averted under each vaccination strategy
    # and seed country
    deaths_averted <- apply_named_args(pars, 1, bootstrap_deaths_averted_wrapper)
    # format stuff
    rownames(median_deaths) <- c("lower_deaths", "median_deaths", "upper_deaths")
    rownames(deaths_averted) <- c("lower_deaths_averted", "deaths_averted", "upper_deaths_averted")
    pars <- cbind(pars, as.data.frame(t(median_deaths)), as.data.frame(t(deaths_averted)))
    levels(pars$strategy) <- c("Incidence", "Current allocation")
    pars$strategy <- factor(pars$strategy,
                            levels = c("Current allocation", "Incidence"))
  } else {
    pars <- rbind(pars, data.frame(strategy = "no_vaccination",
                                   production_delay = 0,
                                   stockpile_size = pars$stockpile_size[1],
                                   seedCountries = seedCountries))
    # read in median deaths under each vaccination strategy
    # and seed country, as well as median deaths under no vaccination
    pars$median_deaths <- Map_vapply(read_median_global_deaths, numeric(1),
                                     pars$strategy,
                                     pars$production_delay,
                                     pars$stockpile_size,
                                     seedCountries = pars$seedCountries)
    # calculate deaths averted = median deaths with no vaccination - median deaths with vaccination
    pars$deaths_averted <- pars[pars$strategy == "no_vaccination", "median_deaths"] - pars$median_deaths
    
    # format stuff
    levels(pars$strategy) <- c("Incidence", "Current allocation", "No vaccination")
    pars$strategy <- factor(pars$strategy,
                            levels = c("Current allocation", "Incidence", "No vaccination"))
    
  }
  
  y_breaks <- seq(0, max(pars$deaths_averted) * 1.1, by = 2e5)
  
  # make plot
  
  plot1 <- ggplot(pars[pars$strategy != "No vaccination",], aes(x = strategy, y = deaths_averted)) +
    geom_bar(stat = "identity") +
    facet_wrap(~seedCountries, nrow = 1, drop = TRUE) +
    scale_y_continuous(breaks = y_breaks,
                       labels = formatC(y_breaks / 1e6, digits = 2),
                       expand = expand_scale(mult = c(0, .1))) +
    xlab("Vaccination strategy") +
    ylab("Deaths averted (million)") +
    theme_bw() +
    theme(legend.position = "none",
          text = element_text(size = 12),
          axis.text.x = element_text(angle = 90, hjust = 1))
  
  if(bootstrap) {
    plot1 <- plot1 + geom_errorbar(aes(ymin = lower_deaths_averted, ymax = upper_deaths_averted))
  }
  
  # save output as files
  if(save_output) {
    ggsave(paste0(save_dir, "deaths_averted_seedCountries_simple_allocation.pdf"),
           plot1, width = 20, height = 10, units = "cm")
    print_table(pars, filename = paste0(save_dir, "deaths_averted_seedCountries_simple_allocation.tex"))
  }
  
  list(table = pars, plot1 = plot1)
}

#' make Fig. S2 in the manuscript: comparing deaths averted for allocation strategies by population size,
#' for different seed countries and no production delay, with a stockpile
#' 
#' deaths averted = median deaths over m simulations of no vaccination,
#' minus median deaths over m simulations of vaccination
#' strategy 1 = vaccinate top n countries by population size,
#' with equal allocation to each of those countries by capita
#' strategy 2 = allocate vaccines per capita to each country
#' proportional to x^alpha where x in the population size and alpha is a parameter
#' 
#' @inheritParams make_Fig2
#' 
#' @output a list of three objects:
#' pars is a data frame containing the median deaths and deaths averted under each
#' vaccination strategy and seed country.  if bootsrap = TRUE, also contains 95% CI.
#' plot1 is a ggplot object: visualisation of the deaths averted
make_FigS2 <- function(save_output = FALSE, bootstrap = TRUE) {
  # values of n for strategy 1
  n_countries <- c(1, 2, 5, 10, 127)
  # values of alpha for strategy 2
  alpha <- c(.5, 1, 2, 3)
  
  stockpile_size <- 550e6
  # define seed countries to plot
  seedCountries <- c("Belgium", "Sao_Tome_and_Principe", "Singapore", "Uganda")
  # make grid of all combinations of vaccination strategies andseed countries
  pars <- expand.grid(strategy = "top_n_countries", 
                      production_delay = 0,
                      stockpile_size = stockpile_size,
                      free_param = n_countries,
                      seedCountries = seedCountries)
  pars <- rbind(pars, expand.grid(strategy = "fn_pop_size", 
                                  production_delay = 0,
                                  stockpile_size = stockpile_size,
                                  free_param = alpha,
                                  seedCountries = seedCountries))
  
  if(bootstrap) {
    # calculate median and 95% CI for the median deaths under each vaccination strategy
    # and seed country
    median_deaths <- apply_named_args(pars, 1, bootstrap_median_deaths_wrapper)
    # calculate median and 95% CI for the deaths averted under each vaccination strategy
    # and seed country
    deaths_averted <- apply_named_args(pars, 1, bootstrap_deaths_averted_wrapper)
    # format stuff
    rownames(median_deaths) <- c("lower_deaths", "median_deaths", "upper_deaths")
    rownames(deaths_averted) <- c("lower_deaths_averted", "deaths_averted", "upper_deaths_averted")
    pars <- cbind(pars, as.data.frame(t(median_deaths)), as.data.frame(t(deaths_averted)))
    levels(pars$strategy) <- c("Top n countries", "Function of population size")
  } else {
    # haven't written the non-bootstrap version for this yet
    stop("Not yet implemented")
    # pars <- rbind(pars, data.frame(strategy = "no_vaccination",
    #                                production_delay = 0,
    #                                stockpile_size = 0,
    #                                free_param = NA,
    #                                seedCountries = "China"))
    # pars$median_deaths <- Map_vapply(read_median_global_deaths, 
    #                                  numeric(1), 
    #                                  pars$strategy, 
    #                                  pars$production_delay,
    #                                  pars$stockpile_size,
    #                                  pars$free_param,
    #                                  pars$seedCountries)
    # pars$deaths_averted <- pars[pars$strategy == "no_vaccination", "median_deaths"] - pars$median_deaths
    # 
    # levels(pars$strategy) <- c("Top n countries", "Function of population size", "No vaccination")
  }
  
  # make plot
  pars$free_param <- factor(pars$free_param)
  y_breaks <- seq(0, max(pars$deaths_averted) * 1.1, by = 2e5)
  plot1 <- ggplot(pars[pars$strategy != "No vaccination",], aes(x = free_param, y = deaths_averted, fill = strategy)) +
    geom_bar(stat = "identity") +
    facet_grid(seedCountries~strategy, scales = "free_x") +
    scale_y_continuous(breaks = y_breaks, 
                       labels = formatC(y_breaks / 1e6, digits = 2),
                       expand = expand_scale(mult = c(0, .1))) +
    xlab("n                                             alpha") +
    ylab("Deaths averted (million)") +
    theme_bw() +
    theme(legend.position = "none",
          text = element_text(size = 12))
  
  if(bootstrap) {
    plot1 <- plot1 + geom_errorbar(aes(ymin = lower_deaths_averted, ymax = upper_deaths_averted))
  }
  # save output as files
  if(save_output) {
    ggsave(paste0(save_dir, "deaths_averted_seedCountries_complex_allocation.pdf"),
           plot1, width = 15, height = 15, units = "cm")
    print_table(pars, filename = paste0(save_dir, "deaths_averted_seedCountries_top_n_countries.tex"), "Top n countries")
    print_table(pars, filename = paste0(save_dir, "deaths_averted_seedCountries_fn_pop_size.tex"), 
                "Function of population size")
  }
  
  list(table = pars, plot1 = plot1)
}

gg_color_hue <- function(n) {
  hues = seq(15, 375, length = n + 1)
  hcl(h = hues, l = 65, c = 100)[1:n]
}

#' make Fig. 2 in the manuscript: comparing deaths averted for allocation by incidence vs current allocation,
#' for different production delays
#' 
#' deaths averted = median deaths over n simulations of no vaccination,
#' minus median deaths over n simulations of vaccination
#' 
#' @param save_output logical: whether to save the output as a pdf as well as outputting the ggplot object
#' @param bootstrap logical: if TRUE, plot median and 95% CI for deaths averted, calculated using
#' bootstrap replicates of the stochastic simulations.  if FALSE, plot point
#' estimate of deaths averted only.
#' @output a list of three objects:
#' pars is a data frame containing the median deaths and deaths averted under each
#' vaccination strategy and production delay.  if bootsrap = TRUE, also contains 95% CI.
#' plot1 and plot2 are ggplot objects: two different visualisations of the deaths averted
make_Fig2_split_alloc <- function(save_output = FALSE, bootstrap = TRUE) {
  # define production delays to plot
  production_delay <- c(0, 7, 90, 180)
  alloc_split <- c("with", "without")
  # make grid of all combinations of vaccination strategies and production delays
  pars <- expand.grid(strategy = "curr_alloc", production_delay = production_delay,
                      alloc_split = alloc_split,
                      stringsAsFactors = FALSE)
  pars <- rbind(pars, data.frame(strategy = "no_vaccination", production_delay = 0,
                                 alloc_split = alloc_split,
                                 stringsAsFactors = FALSE))
  # define other parameters (used to construct filename from which to read the data)
  pars$stockpile_size <- 550e6
  pars[pars$production_delay > 0,"stockpile_size"] <- 0
  pars$seedCountries <- "China"
  pars$free_param <- 0
  if(bootstrap) {
    # calculate median and 95% CI for the median deaths under each vaccination strategy
    # and production delay
    median_deaths <- t(apply_named_args(pars, 1, bootstrap_median_deaths_wrapper)) %>%
      as.data.frame
    # calculate median and 95% CI for the deaths averted under each vaccination strategy
    # and production delay
    deaths_averted <- t(apply_named_args(pars, 1, bootstrap_deaths_averted_wrapper)) %>%
      as.data.frame
    # do.call(rbind, .)
    
    # format stuff
    colnames(median_deaths) <- c("lower_deaths", "median_deaths", "upper_deaths")
    colnames(deaths_averted) <- c("lower_deaths_averted", "deaths_averted", "upper_deaths_averted")
    pars <- cbind(pars, as.data.frame(median_deaths), as.data.frame(deaths_averted))
    pars$strategy <- factor(pars$strategy, 
                            levels = c("no_vaccination", "curr_alloc", "incidence"))
    levels(pars$strategy) <- c("No vaccination", "Current allocation", "Incidence")
  } else {
    pars <- rbind(pars, data.frame(strategy = "no_vaccination",
                                   production_delay = 0,
                                   stockpile_size = 0,
                                   seedCountries = pars$seedCountries[1],
                                   stringsAsFactors = FALSE))
    # read in median deaths under each vaccination strategy
    # and production delay, as well as median deaths under no vaccination
    pars$median_deaths <- Map_vapply(read_median_global_deaths, numeric(1), 
                                     pars$strategy, 
                                     pars$production_delay,
                                     pars$stockpile_size,
                                     seedCountries = pars$seedCountries)
    # calculate deaths averted = median deaths with no vaccination - median deaths with vaccination
    pars$deaths_averted <- pars[pars$strategy == "no_vaccination", "median_deaths"] - pars$median_deaths
    # format stuff
    levels(pars$strategy) <- c("Incidence", "Current allocation", "No vaccination")
    pars$strategy <- factor(pars$strategy, 
                            levels = c("Current allocation", "Incidence", "No vaccination"))
    
  }
  pars$production_delay <- factor(pars$production_delay)
  levels(pars$production_delay) <- c("stockpile", production_delay[production_delay > 0])
  
  # make plots
  plot_wrapper <- function(production_delay_subset) {
    pars <- pars[pars$production_delay %in% production_delay_subset,]
    y_breaks <- seq(0, max(pars$deaths_averted) * 1.1, by = 1e5)
    plot1 <- ggplot(pars[pars$strategy != "No vaccination",], aes(x = production_delay, y = deaths_averted, fill = strategy)) +
      geom_bar(stat = "identity") +
      facet_wrap(~strategy, nrow = 1) +
      scale_y_continuous(breaks = y_breaks, 
                         labels = formatC(y_breaks / 1e5, digits = 2),
                         expand = expand_scale(mult = c(0, .1))) +
      xlab("Production delay (days)") +
      ylab("Deaths averted (x100,000)") +
      theme_bw() +
      theme(legend.position = "none",
            text = element_text(size = 12)) +
      scale_fill_manual(values = gg_color_hue(4)[c(1,4)])
    if(bootstrap) {
      plot1 <- plot1 + geom_errorbar(aes(ymin = lower_deaths_averted, ymax = upper_deaths_averted))
    }
    if(save_output) {
      width <- 20
      height <- 10
      filename_temp <- paste0(save_dir, "Fig2_", production_delay_subset[1])
      ggsave(paste0(filename_temp, ".pdf"),
             plot1, width = width, height = height, units = "cm")
      png(paste0(filename_temp, ".png"),width=width,height=height, units = "cm", res = 300)
      plot(plot1)
      dev.off()
      saveRDS(plot1, file = paste0(filename_temp, ".rds"))
    }
    plot1
  }
  production_delay_subset <- list(c("stockpile", 7),
                                  c(90, 180))
  plot1 <- lapply(production_delay_subset, plot_wrapper)
  # save output as files
  if(save_output) {
    print_table(pars, filename = paste0(save_dir, "Fig2.tex"))
  }
  
  list(table = pars, plot1 = plot1)
}

get_deaths_countries_without_alloc <- function(strategy, production_delay, stockpile_size, free_param, seedCountries) {
  dir_name <- make_dirname(strategy, production_delay, stockpile_size, free_param, seedCountries)
  filename <- paste0(dir_name, strategy, "_fixed_deaths.rds")
  deaths <- readRDS(filename)
  coverage <- read.csv("data/coverage_data_intersect.csv")
  deaths <- lapply(deaths,
                   function(x) x[coverage$dose_per_1000 == 0,] )
  deaths <- vapply(deaths, colSums, numeric(ncol(deaths[[1]])))
  deaths
}

plot_deaths_countries_without_alloc_stockpile <- function() {
  strategy <- c("no_vaccination", "curr_alloc")
  get_quantile_deaths_countries_without_alloc <- function(strategy) {
    deaths <- get_deaths_countries_without_alloc(strategy, 0, 550e6, 0, "China")%>%
      apply(1, quantile, probs = c(0.025, 0.5, 0.975)) %>%
      t %>%
      as.data.frame
    deaths$t <- as.numeric(rownames(deaths))
    deaths$strategy <- strategy
    deaths
  }
  deaths <- lapply(strategy, get_quantile_deaths_countries_without_alloc) %>%
    do.call(rbind, .)
  g <- ggplot(deaths, aes(x = t, group = strategy)) +
    geom_line(aes(y = `50%`, color = strategy)) +
    geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`, fill = strategy), alpha = 0.3) +
    theme_bw() +
    xlab("Time (days)") +
    ylab("Cumulative deaths")
}
jameshay218/vaxedemic documentation built on Jan. 30, 2020, 2:58 a.m.