From 14f18298ca80d15f620a1dd375960d61889681dc Mon Sep 17 00:00:00 2001 From: Zoe Gibney Date: Wed, 29 Apr 2026 11:45:18 +0100 Subject: [PATCH 1/6] Adding pine countries to constants for impact plotting key countries --- R/constants.R | 8 ++++++++ man/constants.Rd | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/R/constants.R b/R/constants.R index e4c3532..90b4858 100644 --- a/R/constants.R +++ b/R/constants.R @@ -215,3 +215,11 @@ DEF_TOUCHSTONE_OLD_OLD <- "202110" #' #' @export COLOUR_VIMC <- "#008080" + +#' @name constants +#' +#' @examples +#' pine +#' +#' @export +pine <- c("PAK", "IND", "NGA", "ETH") \ No newline at end of file diff --git a/man/constants.Rd b/man/constants.Rd index 1d93a1f..9e08393 100644 --- a/man/constants.Rd +++ b/man/constants.Rd @@ -22,6 +22,7 @@ \alias{DEF_TOUCHSTONE_NEW} \alias{DEF_TOUCHSTONE_OLD_OLD} \alias{COLOUR_VIMC} +\alias{pine} \title{Package constants} \format{ An object of class \code{character} of length 5. @@ -61,6 +62,8 @@ An object of class \code{character} of length 1. An object of class \code{character} of length 1. An object of class \code{character} of length 1. + +An object of class \code{character} of length 4. } \usage{ file_dict_colnames @@ -100,6 +103,8 @@ DEF_TOUCHSTONE_NEW DEF_TOUCHSTONE_OLD_OLD COLOUR_VIMC + +pine } \description{ Constant values used in \emph{vimcheck}. See the \strong{Examples} section for the @@ -144,6 +149,8 @@ DEF_TOUCHSTONE_OLD_OLD COLOUR_VIMC +pine + } \keyword{constants} \keyword{datasets} From 0d446cd7b230138409f611b2017f5ad82150b51a Mon Sep 17 00:00:00 2001 From: Zoe Gibney Date: Wed, 29 Apr 2026 11:45:40 +0100 Subject: [PATCH 2/6] Adding plotting functions from rapid-model-run-impact report which plots central impact estimates, coverage and fvps. Associated documentation also added from attempts at roxygen! --- R/fn_plotting_impact.R | 240 ++++++++++++++++++++++++++++++++++++++ man/plot_coverage_fvps.Rd | 29 +++++ man/plot_impact.Rd | 35 ++++++ 3 files changed, 304 insertions(+) create mode 100644 R/fn_plotting_impact.R create mode 100644 man/plot_coverage_fvps.Rd create mode 100644 man/plot_impact.Rd diff --git a/R/fn_plotting_impact.R b/R/fn_plotting_impact.R new file mode 100644 index 0000000..c66027a --- /dev/null +++ b/R/fn_plotting_impact.R @@ -0,0 +1,240 @@ +#' Plot central impact estimates by cohort and year. +#' TODO: need to add importFrom ... to avoid package issues with testing? +#' +#' Produces faceted plots of central impact estimates for priority countries, +#' stratified either by birth cohort or by year of vaccination. +#' Impact metrics include cases, deaths, DALYs, and YLLs. +#' +#' @param data A tibble containing impact estimates. +#' @param burden_type Burden metric used to evaluate impact. burden_type can be: cases, deaths, dalys, yll. +#' @param title Title of the plot to be rendered +#' @param view Charactar scalar. The way impact is assigned, either by birth cohort ("cohort") or by year of vaccination ("year"). +#' +#' @return ggplot object showing central impact estimates +#' +#' @examples +#' plot_impact( +#' data = impact_data, +#' burden_type = "cases", +#' title = "Cases averted", +#' view = "year" +#' ) +#' +#' @export +plot_impact <- function( + data, + burden_type, + title, + view +){ + checkmate::assert_tibble(data, min.rows = 1L, min.cols = 1L) + checkmate::assert_character(burden_type, len = 1) + checkmate::assert_character(title, len = 1) + + checkmate::assert_choice( + burden_type, + choices = c("cases", "deaths", "dalys", "yll") + ) + + checkmate::assert_choice( + view, + choices = c("cohort", "year") + ) + + Impact <- + data %>% + dplyr::filter(.data$country %in% pine) %>% + dplyr::filter( + .data$burden_outcome == burden_type & .data$impact != 0) #%>% + if(nrow(Impact) > 0){ +# ---- Cohort view ---- + if(view == "cohort"){ + Impact <- Impact %>% dplyr::rename(cohort = .data$birth_cohort) %>% + dplyr::select( + .data$country, + .data$cohort, + .data$impact, + .data$short_name + ) + p <- ggplot( + Impact, + aes( + x = .data$cohort, + y = .data$impact, + ymin = .data$impact, + ymax = .data$impact, + fill = as.character(.data$short_name) + ) + ) + + ggplot::geom_ribbon(alpha = 0.3) + + ggplot::geom_line(aes(colour = .data$short_name), size = 0.5)+ + ggplot::geom_point(aes(colour = .data$short_name), size = 0.5)+ + theme_vimc() + #TODO: to check where the theme definition is saved as may not be right for this plot + facet_wrap(country~., scales = "free_y") + + labs( + x = "Birth cohort", + y = paste(burden_type, "averted"), + title = title + ) + + theme( + legend.position="bottom", + legend.key.size= unit(0.5, 'cm'), + legend.key.width = unit(0.3, 'cm') + ) + + } else { # ---- Year (non-cohort) view ---- + Impact <- Impact %>% + dplyr::select( + .data$country, + .data$year, + .data$impact, + .data$short_name + ) + + p <- ggplot ( + Impact, + aes( + x = .data$year, + y = .data$impact, + ymin = .data$impact, + ymax = .data$impact, + fill = .data$short_name + ) + ) + + ggplot::geom_ribbon(alpha = 0.3)+ + ggplot::geom_line(aes(colour = .data$short_name), size = 0.5)+ + ggplot::geom_point(aes(colour = .data$short_name), size = 0.5)+ + theme_vimc() + #TODO: same note as above re theme definition + facet_wrap(country~., scales = "free_y")+ + labs( + x = "Year", + y = paste(burden_type, "averted"), + title = title + ) + + theme( + legend.position="bottom", + legend.key.size= unit(0.5, 'cm'), + legend.key.width = unit(0.3, 'cm') + ) + } + } else { + p <- "No estimates in the data." #TODO: both here and in the below plot returning p may be an issue? Can you think of a better way? + } + return(p) + +} + +#' Plot coverage and fully vaccinated persons (FVPs) +#' +#' Generates plots of routine vaccine coverage and fully vaccinated +#' persons (FVPs) over time for selected countries. +#' +#' @param fvps A tibble showing the number of fvps (fully vaccinated persons) +#' by country, year and scenario/activity type. +#' +#' @return A named list with two ggplot objects: +#' \describe{ +#' \item{coverage}{A plot of routine vaccine coverage over time.} +#' \item{fvps}{A plot of fully vaccinated persons over time.} +#' } +#' @examples +#' plots <- plot_coverage_fvps(fvps) +#' plots$coverage +#' plots$fvps +#' +#' @export +plot_coverage_fvps <- function(fvps){ + checkmate::assert_tibble(fvps, min.rows = 1L, min.cols = 1L) + + fvps <- fvps %>% + dplyr::filter(.data$country %in% pine) + + cov <- fvps %>% + dplyr::filter(.data$activity_type == "routine") %>% + dplyr::mutate( + vaccine_delivery = paste(.data$scenario_type, .data$vaccine, sep = "_"), + coverage_adjusted = round(.data$coverage_adjusted*100, 2) + ) %>% + dplyr::select( + .data$country, + .data$vaccine_delivery, + .data$year, + .data$coverage_adjusted) %>% + dplyr::rename(coverage = .data$coverage_adjusted) + + fvp <- fvps %>% + dplyr::mutate( + vaccine_delivery = paste(.data$scenario_type, .data$activity_type, sep = "_") + ) %>% + dplyr::select( + .data$country, + .data$vaccine_delivery, + .data$year, + .data$fvps + ) %>% + dplyr::group_by( + .data$country, + .data$vaccine_delivery, + .data$year) %>% + dplyr::summarise( + fvps = round(sum(.data$fvps)/1e6, 2), + .groups = "drop" + ) + if(nrow(cov) > 0){ + p <- ggplot( + cov, + aes( + x = .data$year, + y = .data$coverage, + ymin = 0, + ymax = 1, + fill = .data$vaccine_delivery) + ) + + ggplot::geom_line(aes(colour = .data$vaccine_delivery), size = 0.5) + + theme_vimc() + #TODO: same note as above + facet_wrap(country~., scales = "free_y")+ + labs( + x = "Year", + y = "Coverage (%)", + title = "Routine vaccine coverage" + ) + + theme( + legend.position="bottom", + legend.key.size= unit(0.5, 'cm'), + legend.key.width = unit(0.3, 'cm') +) + + } else { + p <- "There is no routine coverage in the database." + } + + + q <- ggplot( + fvp, + aes( + x = .data$year, + y = .data$fvps, + ymin = .data$fvps, + ymax = .data$fvps, #TODO: min/max both here and above seem to be the same so may be irrelevant to define + fill = .data$vaccine_delivery + ) + ) + + geom_point(aes(colour = .data$vaccine_delivery), size = 0.5) + + theme_vimc()+ #TODO: same note above on theme + facet_wrap(country~., scales = "free_y") + + labs( + x = "Year", + y = "FVPs (in millions)", + title = "FVPs" + ) + + theme( + legend.position="bottom", + legend.key.size = unit(0.5, 'cm'), + legend.key.width = unit(0.3, 'cm') + ) + + return(list( + coverage = p, + fvps = q + )) +} diff --git a/man/plot_coverage_fvps.Rd b/man/plot_coverage_fvps.Rd new file mode 100644 index 0000000..4e389fc --- /dev/null +++ b/man/plot_coverage_fvps.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fn_plotting_impact.R +\name{plot_coverage_fvps} +\alias{plot_coverage_fvps} +\title{Plot coverage and fully vaccinated persons (FVPs)} +\usage{ +plot_coverage_fvps(fvps) +} +\arguments{ +\item{fvps}{A tibble showing the number of fvps (fully vaccinated persons) +by country, year and scenario/activity type.} +} +\value{ +A named list with two ggplot objects: +\describe{ +\item{coverage}{A plot of routine vaccine coverage over time.} +\item{fvps}{A plot of fully vaccinated persons over time.} +} +} +\description{ +Generates plots of routine vaccine coverage and fully vaccinated +persons (FVPs) over time for selected countries. +} +\examples{ +plots <- plot_coverage_fvps(fvps) +plots$coverage +plots$fvps + +} diff --git a/man/plot_impact.Rd b/man/plot_impact.Rd new file mode 100644 index 0000000..ef25df7 --- /dev/null +++ b/man/plot_impact.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fn_plotting_impact.R +\name{plot_impact} +\alias{plot_impact} +\title{Plot central impact estimates by cohort and year. +TODO: need to add importFrom ... to avoid package issues with testing?} +\usage{ +plot_impact(data, burden_type, title, view) +} +\arguments{ +\item{data}{A tibble containing impact estimates.} + +\item{burden_type}{Burden metric used to evaluate impact. burden_type can be: cases, deaths, dalys, yll.} + +\item{title}{Title of the plot to be rendered} + +\item{view}{Charactar scalar. The way impact is assigned, either by birth cohort ("cohort") or by year of vaccination ("year").} +} +\value{ +ggplot object showing central impact estimates +} +\description{ +Produces faceted plots of central impact estimates for priority countries, +stratified either by birth cohort or by year of vaccination. +Impact metrics include cases, deaths, DALYs, and YLLs. +} +\examples{ +plot_impact( + data = impact_data, + burden_type = "cases", + title = "Cases averted", + view = "year" +) + +} From fce44b85afce75892832f9f69744d5b9d6483159 Mon Sep 17 00:00:00 2001 From: Zoe Gibney Date: Mon, 1 Jun 2026 10:39:42 +0100 Subject: [PATCH 3/6] Fix for enabling package checks --- .github/workflows/R-CMD-check.yaml | 2 +- .github/workflows/lint-changed-files.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index e1c58b9..2909c4a 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -4,7 +4,7 @@ on: push: branches: [main, master] pull_request: - branches: [main, master] + branches: [*] name: R-CMD-check diff --git a/.github/workflows/lint-changed-files.yaml b/.github/workflows/lint-changed-files.yaml index cf5c34b..96e2368 100644 --- a/.github/workflows/lint-changed-files.yaml +++ b/.github/workflows/lint-changed-files.yaml @@ -3,7 +3,7 @@ on: workflow_dispatch: pull_request: - branches: [main, master] + branches: [*] paths: - '**.R' - '**.Rmd' From 291e905472516223f9e13cce7db2ffa4b1943f0f Mon Sep 17 00:00:00 2001 From: Zoe Gibney Date: Mon, 1 Jun 2026 12:31:48 +0100 Subject: [PATCH 4/6] Adding more meaningful checks and assertions --- R/fn_plotting_impact.R | 138 ++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 63 deletions(-) diff --git a/R/fn_plotting_impact.R b/R/fn_plotting_impact.R index c66027a..8f23acd 100644 --- a/R/fn_plotting_impact.R +++ b/R/fn_plotting_impact.R @@ -1,5 +1,4 @@ #' Plot central impact estimates by cohort and year. -#' TODO: need to add importFrom ... to avoid package issues with testing? #' #' Produces faceted plots of central impact estimates for priority countries, #' stratified either by birth cohort or by year of vaccination. @@ -23,39 +22,41 @@ #' @export plot_impact <- function( data, - burden_type, + burden_type = c("cases", "deaths", "dalys", "yll"), title, - view + view = c("cohort", "year") ){ checkmate::assert_tibble(data, min.rows = 1L, min.cols = 1L) - checkmate::assert_character(burden_type, len = 1) - checkmate::assert_character(title, len = 1) - checkmate::assert_choice( - burden_type, - choices = c("cases", "deaths", "dalys", "yll") - ) + required_cols <- c("country", "burden_outcome", "impact", "short_name") - checkmate::assert_choice( - view, - choices = c("cohort", "year") + checkmate::assert_names( + names(data), + must.include = required_cols ) - Impact <- - data %>% - dplyr::filter(.data$country %in% pine) %>% - dplyr::filter( - .data$burden_outcome == burden_type & .data$impact != 0) #%>% + checkmate::assert_character(title, len = 1) + + burden_type <- rlang::arg_match(burden_type) + view <- rlang::arg_match(view) + + Impact <- dplyr::filter(data, + .data$country %in% pine, + .data$burden_outcome == burden_type, + .data$impact != 0) + if(nrow(Impact) > 0){ # ---- Cohort view ---- if(view == "cohort"){ - Impact <- Impact %>% dplyr::rename(cohort = .data$birth_cohort) %>% - dplyr::select( - .data$country, - .data$cohort, - .data$impact, - .data$short_name - ) + + checkmate::assert_names(names(data), must.include = "birth_cohort") + + Impact <- Impact %>% dplyr::rename(Impact, cohort = .data$birth_cohort) + + cols_to_select <- c("country", "cohort", "impact", "short_name") + + Impact <- dplyr::select(Impact, all_of(cols_to_select)) + p <- ggplot( Impact, aes( @@ -83,13 +84,11 @@ plot_impact <- function( ) } else { # ---- Year (non-cohort) view ---- - Impact <- Impact %>% - dplyr::select( - .data$country, - .data$year, - .data$impact, - .data$short_name - ) + cols_to_select <- c("country", "year", "impact", "short_name") + + checkmate::assert_names(names(data), must.include = "year") + + Impact <- dplyr::select(Impact, all_of(cols_to_select)) p <- ggplot ( Impact, @@ -146,40 +145,53 @@ plot_impact <- function( plot_coverage_fvps <- function(fvps){ checkmate::assert_tibble(fvps, min.rows = 1L, min.cols = 1L) - fvps <- fvps %>% - dplyr::filter(.data$country %in% pine) + required_cols <- c( + "country", + "activity_type", + "scenario_type", + "vaccine", + "coverage_adjusted", + "year", + "fvps" + ) - cov <- fvps %>% - dplyr::filter(.data$activity_type == "routine") %>% - dplyr::mutate( + checkmate::assert_names( + names(fvps), + must.include = required_cols + ) + + + fvps <- dplyr::filter(fvps, .data$country %in% pine) + + cov <- dplyr::filter(fvps, .data$activity_type == "routine") + + cov <- dplyr::mutate(cov, vaccine_delivery = paste(.data$scenario_type, .data$vaccine, sep = "_"), coverage_adjusted = round(.data$coverage_adjusted*100, 2) - ) %>% - dplyr::select( - .data$country, - .data$vaccine_delivery, - .data$year, - .data$coverage_adjusted) %>% - dplyr::rename(coverage = .data$coverage_adjusted) - - fvp <- fvps %>% - dplyr::mutate( - vaccine_delivery = paste(.data$scenario_type, .data$activity_type, sep = "_") - ) %>% - dplyr::select( - .data$country, - .data$vaccine_delivery, - .data$year, - .data$fvps - ) %>% - dplyr::group_by( - .data$country, - .data$vaccine_delivery, - .data$year) %>% - dplyr::summarise( - fvps = round(sum(.data$fvps)/1e6, 2), - .groups = "drop" - ) + ) + + cols_to_select <- c("country", "vaccine_delivery", "year", "coverage_adjusted") + + cov <- dplyr::select(cov, all_of(cols_to_select)) + + cov <- dplyr::rename(cov, coverage = .data$coverage_adjusted) + + fvps <- dplyr::mutate(fvps, + vaccine_delivery = paste(.data$scenario_type, .data$activity_type, sep = "_") + ) + cols_to_select <- c("country", "vaccine_delivery", "year", "fvps") + + fvps <- dplyr::select(fvps, all_of(cols_to_select)) + + fvps <- dplyr::group_by(fvps, + .data$country, + .data$vaccine_delivery, + .data$year) + + fvps <- dplyr::summarise(fvps, + fvps = round(sum(.data$fvps)/1e6, 2), + .groups = "drop" + ) if(nrow(cov) > 0){ p <- ggplot( cov, @@ -210,7 +222,7 @@ plot_coverage_fvps <- function(fvps){ q <- ggplot( - fvp, + fvps, aes( x = .data$year, y = .data$fvps, From 8a1be98d2db5e211effc862216a95bcb607ce4dd Mon Sep 17 00:00:00 2001 From: Zoe Gibney Date: Mon, 1 Jun 2026 12:38:51 +0100 Subject: [PATCH 5/6] Defining example data and fvps dataframes --- R/fn_plotting_impact.R | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/R/fn_plotting_impact.R b/R/fn_plotting_impact.R index 8f23acd..cf1d24a 100644 --- a/R/fn_plotting_impact.R +++ b/R/fn_plotting_impact.R @@ -12,6 +12,16 @@ #' @return ggplot object showing central impact estimates #' #' @examples +#' +#' # Create example data +#' impact_data <- tibble::tibble( +#' country = c("A", "A", "B", "B"), +#' year = c(2020, 2021, 2020, 2021), +#' birth_cohort = c(2000, 2001, 2000, 2001), +#' burden_outcome = c("deaths", "cases", "deaths", "cases"), +#' impact = c(15, 5, 14, 8), +#' short_name = c("short1", "short2", "short3", "short4") +#' ) #' plot_impact( #' data = impact_data, #' burden_type = "cases", @@ -137,6 +147,18 @@ plot_impact <- function( #' \item{fvps}{A plot of fully vaccinated persons over time.} #' } #' @examples +#' +#' # Create example data +#' fvps <- tibble::tibble( + #' country = c("AGO", "AGO", "BEN", "BEN"), + #' year = c(2020, 2021, 2020, 2021), + #' activity_type = c("routine", "campaign", "routine", "campaign"), + #' scenario_type = c("default", "default", "default", "default"), + #' vaccine = c("measles", "measles", "measles", "measles"), + #' coverage_adjusted = c(0.8, 0.85, 0.4, 0.7), + #' fvps = c(1000000, 1200000, 800000, 900000) + #' ) + #' plots <- plot_coverage_fvps(fvps) #' plots$coverage #' plots$fvps From 876048ad9f3bdf17d75e7808bc269e9b3a29c8d9 Mon Sep 17 00:00:00 2001 From: Zoe Gibney Date: Mon, 1 Jun 2026 13:20:56 +0100 Subject: [PATCH 6/6] Adding impact plots to pkgdown documentation --- _pkgdown.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 40a29ee..f73c2cb 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -32,6 +32,12 @@ reference: - subtitle: Plot impact estimates contents: - plot_impact_diagnostics + - subtitle: Plot central impact estimates by cohort and year + contents: + - plot_impact + - subtitle: Plot coverage and fully vaccinated persons (FVPs) + contents: + - plot_coverage_fvps - title: Plotting helper functions contents: