diff --git a/DESCRIPTION b/DESCRIPTION index 13f82df..9076b29 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -51,7 +51,7 @@ Suggests: tidyr, roxygen2, usethis, - testthat, + testthat (>= 3.0.0), rcmdcheck, httptest VignetteBuilder: @@ -63,3 +63,4 @@ LazyData: true Remotes: hubverse-org/hubData BugReports: https://github.com/CDCgov/forecasttools/issues +Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index 741e9c1..0d2c123 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -18,10 +18,10 @@ export(nhsn_soda_query) export(nullable_comparison) export(pivot_hubverse_quantiles_wider) export(plot_coverage_by_date) -export(plot_forecast_quantiles) +export(plot_hubverse_file_quantiles) +export(plot_hubverse_loc_quant_ts) export(plot_hubverse_pointintervals) -export(plot_hubverse_quantiles) -export(plot_hubverse_quantiles_loc) +export(plot_quantile_timeseries) export(plots_to_pdf) export(pull_nhsn) export(quantile_table_to_scoreable) diff --git a/R/plot_hubverse_timeseries.R b/R/plot_hubverse_timeseries.R new file mode 100644 index 0000000..34b4a26 --- /dev/null +++ b/R/plot_hubverse_timeseries.R @@ -0,0 +1,311 @@ +#' Plot a hubverse formatted quantile forecast timeseries +#' for a single location. +#' +#' Given a tibble of data properly formatted +#' for a hubverse schema forecast hub submission, +#' plot a timeseries of quantile predictions for +#' a given location. +#' +#' @param location location to plot +#' @param forecast_data hubverse format quantile +#' forecast data, as a [`tibble`][tibble::tibble]. +#' @param observed_data observed data, +#' as a [`tibble`][tibble::tibble]. +#' @param location_format format of the provided location. +#' Permitted formats are `"abbr"` (state/territory +#' or nation two letter USPS abbreviation), `"hub"` ( +#' legacy 2-digit FIPS code for states and territories, `US` +#' for the USA as a whole), and `"long_name"` (full English +#' jurisdiction names; not recommended). Default `"abbr"`. +#' @param y_transform axis transform passed as the +#' `transform` argument to [ggplot2::scale_y_continuous()]. +#' Default `"log10"`. +#' @param linewidth `linewidth` parameter passed to +#' [ggplot2::geom_line()]. Default `2`. +#' @param pointsize `size` parameter passed to +#' [ggplot2::geom_point()]. Default `4`. +#' @param forecast_linecolor `color` parameter passed to +#' [ggplot2::geom_line()] for plotting forecasts. +#' Default `"darkblue"`. +#' @param forecast_pointcolor `color` parameter passed to +#' [ggplot2::geom_point()] for plotting forecasts. +#' Default `"darkblue"`. +#' @param obs_linecolor `color` parameter passed to +#' [ggplot2::geom_line()] for plotting observed data. +#' Default `"black"`. +#' @param obs_pointcolor `color` parameter passed to +#' [ggplot2::geom_point()] for plotting observed data. +#' Default `"black"`. +#' @param target_name Name of the forecast target, +#' for labeling the plot y-axis. Default `NULL`, +#' in which case a value from the `target` column +#' in `forecast_data` will be used. +#' @param autotitle Boolean. Generate an automatic +#' title for the plot from the location name +#' and reference date? Default `TRUE`. +#' @return the plot as a ggplot object +#' @export +plot_hubverse_loc_quant_ts <- function(location, + forecast_data, + observed_data, + location_format = "abbr", + y_transform = "log10", + linewidth = 2, + pointsize = 4, + forecast_linecolor = "darkblue", + forecast_pointcolor = "darkblue", + obs_linecolor = "black", + obs_pointcolor = "black", + target_name = NULL, + autotitle = TRUE) { + loc_table <- location_lookup(location, location_format) + loc_data <- forecast_data |> + dplyr::filter( + location == !!loc_table$location_code, + output_type == "quantile" + ) |> + dplyr::rename("date" = "target_end_date") + loc_obs <- observed_data |> + dplyr::filter(location == !!loc_table$location_code) + + + if (autotitle) { + loc_name <- loc_table$long_name[1] + plot_date <- loc_data$reference_date[1] + plot_title <- stringr::str_glue( + "{loc_name} forecasts of {plot_date}" + ) + } else { + plot_title <- NULL + } + + if (is.null(target_name)) { + target_name <- loc_data$target[1] + } + + plot <- loc_data |> + plot_quantile_timeseries( + time_column = "date", + value_column = "value", + quantile_level_column = "output_type_id", + linewidth = linewidth, + pointsize = pointsize, + linecolor = forecast_linecolor, + pointcolor = forecast_pointcolor + ) + + ggplot2::geom_line( + data = loc_obs, + mapping = ggplot2::aes( + x = .data$date, + y = .data$value + ), + alpha = 1, + linewidth = linewidth, + color = obs_linecolor, + inherit.aes = FALSE + ) + + ggplot2::geom_point( + data = loc_obs, + mapping = ggplot2::aes( + x = .data$date, + y = .data$value + ), + alpha = 1, + size = pointsize, + color = obs_pointcolor, + inherit.aes = FALSE + ) + + ggplot2::scale_y_continuous( + transform = y_transform + ) + + ggplot2::labs( + y = target_name, + x = "Date" + ) + + ggplot2::ggtitle(plot_title) + + theme_forecasttools() + + + return(plot) +} + + +#' Plot hubverse formatted forecasts +#' for all or a subset of forecasted +#' locations. +#' +#' Plot quantiles given hubverse +#' formatted data for all +#' locations in the dataset or +#' a subset of them. +#' +#' @param forecast_file_path path to hubverse- +#' formatted forecast data, as a single `.csv` file. +#' @param locations set of locations to plot. If NULL, +#' all locations are plotted. Otherwise, a vector +#' of location values to plot, as USPS-style +#' abbreviations (e.g. `c("US", "AL", "AK"`), +#' US hubverse submission location codes ( +#' e.g. `c("US", 01, 02)`), or full English +#' jurisdiction names +#' (e.g. `c("United States, "Alabama", "Alaska")`. +#' Default `NULL`. +#' @param location_input_format format of the provided location +#' vector if it is provided. +#' Permitted formats are `"abbr"` (state/territory +#' or nation two letter USPS abbreviation), `"hub"` ( +#' legacy 2-digit FIPS code for states and territories, `US` +#' for the USA as a whole), and `"long_name"` (full English +#' jurisdiction names; not recommended). Default `"abbr"`. +#' @param location_output_format how to code locations for +#' the output vector. +#' Permitted formats are `"abbr"` (state/territory +#' or nation two letter USPS abbreviation), `"hub"` ( +#' legacy 2-digit FIPS code for states and territories, `US` +#' for the USA as a whole), and `"long_name"` (full English +#' jurisdiction names; not recommended). Default `"abbr"`. +#' @param observed_data_path path to observed data +#' to plot alongside the forecast quantiles. If `NULL`, +#' only the forecast quantiles will be plotted. Default `NULL`. +#' @param start_date first date to plot. If NULL, defaults +#' to the earliest date found between the forecast timeseries ( +#' obtained from `forecast_file_path`) and the observed +#' data timeseries (obtained from `observed_data_path`, if +#' provided). Default NULL. +#' @param end_date final date to plot. If NULL, defaults +#' to the latest date found between the forecast timeseries ( +#' obtained from `forecast_file_path`) and the observed +#' data timeseries (obtained from `observed_data_path`, if +#' provided). Default NULL. +#' @param location_input_format format of the provided location +#' vector. Permitted formats are `"abbr"` (state/territory +#' or nation two letter USPS abbreviation), `"hub"` ( +#' legacy 2-digit FIPS code for states and territories, `US` +#' for the USA as a whole), and `"long_name"` (full English +#' jurisdiction names; not recommended). Default `"abbr"`. +#' @param location_output_format Location format for naming the +#' entries of the output list. Accepts the same string +#' keys as `location_input_format`. +#' @param y_transform axis transform passed as the `transform` +#' argument to [ggplot2::scale_y_continuous()]. Default `"log10"`. +#' @param linewidth `linewidth` parameter passed to +#' [ggplot2::geom_line()]. Default `2`. +#' @param pointsize `size` parameter passed to +#' [ggplot2::geom_point()]. Default `4`. +#' @param forecast_linecolor `color` parameter +#' passed to [ggplot2::geom_line()] for plotting forecasts. +#' Default `"darkblue"`. +#' @param forecast_pointcolor `color` parameter passed to +#' [ggplot2::geom_point()] for plotting forecasts. +#' Default `"darkblue"`. +#' @param obs_linecolor `color` parameter passed to [ggplot2::geom_line()] +#' for plotting observed data. Default `"black"`. +#' @param obs_pointcolor `color` parameter passed to +#' [ggplot2::geom_point()] for plotting observed data. Default `"black"`. +#' @param autotitle Generate a title for the individual +#' plots from the hubverse `reference_date` and the location +#' name? Boolean, default `TRUE`. +#' @return a list of ggplot objects of the plots created, +#' one for each location +#' @export +plot_hubverse_file_quantiles <- function(forecast_file_path, + locations = NULL, + observed_data_path = NULL, + start_date = NULL, + end_date = NULL, + location_input_format = "abbr", + location_output_format = "abbr", + y_transform = "log10", + linewidth = 2, + pointsize = 4, + forecast_linecolor = "darkblue", + forecast_pointcolor = "darkblue", + obs_linecolor = "black", + obs_pointcolor = "black", + autotitle = TRUE) { + start_date <- if (!is.null(start_date)) as.Date(start_date) else NULL + end_date <- if (!is.null(end_date)) as.Date(end_date) else NULL + hubverse_cols <- readr::cols( + reference_date = readr::col_date(), + target = readr::col_character(), + horizon = readr::col_integer(), + target_end_date = readr::col_date(), + location = readr::col_character(), + output_type = readr::col_character(), + output_type_id = readr::col_double(), + value = readr::col_double() + ) + forecast_data <- readr::read_csv( + forecast_file_path, + col_types = hubverse_cols + ) |> + dplyr::filter( + output_type == "quantile", + ) |> + dplyr::mutate(output_type_id = as.numeric(output_type_id)) + + if (!is.null(observed_data_path)) { + observed_cols <- readr::cols_only( + date = readr::col_date(), + location = readr::col_character(), + value = readr::col_double() + ) + obs_data <- readr::read_csv(observed_data_path, + col_types = observed_cols + ) + } else { + obs_data <- tibble::tibble( + date = as.Date(numeric(0)), + location = character(0), + value = numeric(0) + ) + } + + forecast_data <- forecast_data |> + dplyr::filter( + nullable_comparison(.data$target_end_date, ">=", !!start_date), + nullable_comparison(.data$target_end_date, "<=", !!end_date) + ) + + obs_data <- obs_data |> + dplyr::filter( + nullable_comparison(.data$date, ">=", !!start_date), + nullable_comparison(.data$date, "<=", !!end_date) + ) + + if (is.null(locations)) { + locations <- forecast_data |> + dplyr::distinct(location) |> + dplyr::pull() + loc_table <- location_lookup(locations, "hub") + } else { + locations <- base::unique(locations) + loc_table <- location_lookup(locations, location_input_format) + } + + location_vector <- loc_table |> + dplyr::pull(!!to_location_table_column(location_output_format)) |> + purrr::set_names() + + list_of_plots <- purrr::map( + location_vector, + \(loc) { + plot_hubverse_loc_quant_ts( + loc, + forecast_data = forecast_data, + observed_data = obs_data, + location_format = location_output_format, + y_transform = y_transform, + linewidth = linewidth, + pointsize = pointsize, + forecast_pointcolor = forecast_pointcolor, + forecast_linecolor = forecast_linecolor, + obs_pointcolor = obs_pointcolor, + obs_linecolor = obs_linecolor, + autotitle = autotitle + ) + } + ) + + return(list_of_plots) +} diff --git a/R/plot_quantiles.R b/R/plot_quantiles.R index e8a9289..d9c4503 100644 --- a/R/plot_quantiles.R +++ b/R/plot_quantiles.R @@ -1,44 +1,44 @@ -#' Plot a timeseries of quantiles +#' Plot a timeseries of quantiles. #' -#' @param data timeseries of quantiles as tidy data, -#' with one row per timepoint per quantile level -#' @param time_column name of the column in `data` -#' containing timepoints -#' @param observation_column name of the column -#' in data containing observed values at the -#' given quantile levels -#' @param quantile_level_column name of the column -#' in `data` giving the quantile level (e.g. -#' `0.01` for the 0.01 quantile / 1st percentile) -#' @param linesize `size` parameter passed to [ggplot2::geom_line()]. -#' Default 2. -#' @param pointsize `size` parameter passed to [ggplot2::geom_point()] -#' Default 4. -#' @param linecolor `color` parameter passed to [ggplot2::geom_line()]. -#' Default `"darkblue"`. -#' @param pointcolor `color` parameter passed to [ggplot2::geom_point()] -#' Default `"darkblue"`. -#' @return the resultant plot, as a ggplot object. +#' @param data Timeseries of quantiles as tidy data, +#' with one row per timepoint per quantile level. +#' @param time_column Name of the column in `data` +#' containing timepoint values, as a string. +#' @param value_column Name of the column +#' in data containing the timeseries values at the +#' given quantile levels, as a string. +#' @param quantile_level_column Name of the column in `data` +#' containing indicating which quantile level the row contains, +#' as a string. +#' @param linewidth `linewidth` parameter passed to +#' [ggplot2::geom_line()]. Default `2`. +#' @param pointsize `size` parameter passed to +#' [ggplot2::geom_point()] Default `4`. +#' @param linecolor `color` parameter passed to +#' [ggplot2::geom_line()]. Default `"darkblue"`. +#' @param pointcolor `color` parameter passed to +#' [ggplot2::geom_point()] Default `"darkblue"`. +#' @return The plot, as a ggplot object. #' @export -plot_forecast_quantiles <- function(data, - time_column, - observation_column, - quantile_level_column, - linesize = 2, - pointsize = 4, - pointcolor = "darkblue", - linecolor = "darkblue") { +plot_quantile_timeseries <- function(data, + time_column, + value_column, + quantile_level_column, + linewidth = 2, + pointsize = 4, + pointcolor = "darkblue", + linecolor = "darkblue") { return(ggplot2::ggplot( mapping = ggplot2::aes( - x = {{ time_column }}, - y = {{ observation_column }}, - group = {{ quantile_level_column }}, - alpha = 1 - abs({{ quantile_level_column }} - 0.5) + x = .data[[time_column]], + y = .data[[value_column]], + group = .data[[quantile_level_column]], + alpha = 1 - abs(.data[[quantile_level_column]] - 0.5) ), data = data ) + ggplot2::geom_line( - size = linesize, + linewidth = linewidth, color = linecolor ) + ggplot2::geom_point( @@ -47,356 +47,3 @@ plot_forecast_quantiles <- function(data, ) + ggplot2::scale_alpha_continuous(guide = NULL)) } - - -#' Plot hubverse formatted quantile forecasts for a given -#' location. -#' -#' Given a tibble of data properly formatted -#' for a hubverse schema forecast hub submission, -#' plot a timeseries quantile predictions for -#' a given location. -#' -#' @param location location to plot -#' @param forecast_data hubverse format quantile -#' forecast data, as a [`tibble`][tibble::tibble]. -#' @param truth_data hubverse format truth data, -#' as a [`tibble`][tibble::tibble]. -#' @param location_format format of the provided location. -#' Permitted formats are `"abbr"` (state/territory -#' or nation two letter USPS abbreviation), `"hub"` ( -#' legacy 2-digit FIPS code for states and territories, `US` -#' for the USA as a whole), and `"long_name"` (full English -#' jurisdiction names; not recommended). Default `"abbr"`. -#' @param ytrans axis transform passed to -#' [ggplot2::scale_y_continuous()]. Default `'log10'`. -#' @param linesize `size` parameter passed to -#' [ggplot2::geom_line()]. Default 2. -#' @param pointsize `size` parameter passed to -#' [ggplot2::geom_point()]. Default 4. -#' @param forecast_linecolor `color` parameter passed to -#' [ggplot2::geom_line()] for plotting forecasts. -#' Default "darkblue". -#' @param forecast_pointcolor `color` parameter passed to -#' [ggplot2::geom_point()] for plotting forecasts. -#' Default "darkblue". -#' @param truth_linecolor `color` parameter passed to -#' [ggplot2::geom_line()] for plotting truth data. -#' Default "black". -#' @param truth_pointcolor `color` parameter passed to -#' [ggplot2::geom_point()] for plotting truth data. -#' Default "black". -#' @param target_name Name of the forecast target, -#' for labeling the plot y-axis. Default `NULL`, -#' in which case a value from the `target` column -#' in `forecast_data` will be used. -#' @param autotitle Boolean. Generate an automatic -#' title for the plot from the location name -#' and reference date? Default `TRUE`. -#' @return the plot as a ggplot object -#' @export -plot_hubverse_quantiles_loc <- function(location, - forecast_data, - truth_data, - location_format = "abbr", - ytrans = "log10", - linesize = 2, - pointsize = 4, - forecast_linecolor = "darkblue", - forecast_pointcolor = "darkblue", - truth_linecolor = "black", - truth_pointcolor = "black", - target_name = NULL, - autotitle = TRUE) { - loc_table <- location_lookup(location, location_format) - loc_data <- forecast_data |> - dplyr::filter( - location == !!loc_table$location_code, - output_type == "quantile" - ) |> - dplyr::rename("date" = "target_end_date") - loc_truth <- truth_data |> - dplyr::filter(location == !!loc_table$location_code) - - - if (autotitle) { - loc_name <- loc_table$long_name[1] - plot_date <- loc_data$reference_date[1] - plot_title <- stringr::str_glue( - "{loc_name} forecasts of {plot_date}" - ) - } else { - plot_title <- NULL - } - - if (is.null(target_name)) { - target_name <- loc_data$target[1] - } - - plot <- ( - plot_forecast_quantiles( - loc_data, - date, - value, - output_type_id, - linesize = linesize, - pointsize = pointsize, - linecolor = forecast_linecolor, - pointcolor = forecast_pointcolor - ) + - ggplot2::geom_line( - data = loc_truth, - mapping = ggplot2::aes( - x = date, - y = value - ), - alpha = 1, - size = linesize, - color = truth_linecolor, - inherit.aes = FALSE - ) + - ggplot2::geom_point( - data = loc_truth, - mapping = ggplot2::aes( - x = date, - y = value - ), - alpha = 1, - size = pointsize, - color = truth_pointcolor, - inherit.aes = FALSE - ) + - ggplot2::scale_y_continuous( - trans = ytrans - ) + - ggplot2::labs( - y = target_name, - x = "Date" - ) + - ggplot2::ggtitle(plot_title) + - theme_forecasttools() - - ) - - return(plot) -} - - -#' Plot hubverse formatted forecasts -#' for all or a subset of forecasted -#' locations. -#' -#' Plot quantiles given hubverse -#' formatted data for all -#' locations in the dataset or -#' a subset of them. -#' -#' @param forecast_data_path path to hubverse- -#' formatted forecast data, as a single `.csv`. -#' @param locations set of locations to plot. If NULL, -#' all locations are plotted. Otherwise, a vector -#' of location values to plot, as USPS-style -#' abbreviations (e.g. `c("US", "AL", "AK"`), -#' US hubverse submission location codes ( -#' e.g. `c("US", 01, 02)`), or full English -#' jurisdiction names -#' (e.g. `c("United States, "Alabama", "Alaska")`. -#' Default `NULL`. -#' @param location_input_format format of the provided location -#' vector if it is provided. -#' Permitted formats are `"abbr"` (state/territory -#' or nation two letter USPS abbreviation), `"hub"` ( -#' legacy 2-digit FIPS code for states and territories, `US` -#' for the USA as a whole), and `"long_name"` (full English -#' jurisdiction names; not recommended). Default `"abbr"`. -#' @param location_output_format how to code locations for -#' the output vector. -#' Permitted formats are `"abbr"` (state/territory -#' or nation two letter USPS abbreviation), `"hub"` ( -#' legacy 2-digit FIPS code for states and territories, `US` -#' for the USA as a whole), and `"long_name"` (full English -#' jurisdiction names; not recommended). Default `"abbr"`. -#' @param truth_data_path path to hubverse formatted truth data -#' to plot alongside the forecast quantiles. If NULL, -#' only the forecast quantiles will be plotted. Default NULL. -#' @param start_date first date to plot. If NULL, defaults -#' to the earliest date found between the forecast timeseries ( -#' obtained from `forecast_data_path`) and the truth -#' data timeseries (obtained from `truth_data_path`, if -#' provided). Default NULL. -#' @param end_date final date to plot. If NULL, defaults -#' to the latest date found between the forecast timeseries ( -#' obtained from `forecast_data_path`) and the truth -#' data timeseries (obtained from `truth_data_path`, if -#' provided). Default NULL. -#' @param location_input_format format of the provided location -#' vector. Permitted formats are `"abbr"` (state/territory -#' or nation two letter USPS abbreviation), `"hub"` ( -#' legacy 2-digit FIPS code for states and territories, `US` -#' for the USA as a whole), and `"long_name"` (full English -#' jurisdiction names; not recommended). Default `"abbr"`. -#' @param location_output_format Location format for naming the -#' entries of the output list. Accepts the same string -#' keys as `location_input_format`. -#' @param ytrans axis transform passed to -#' [ggplot2::scale_y_continuous()]. Default `'log10'`. -#' @param linesize `size` parameter passed to -#' [ggplot2::geom_line()]. Default 2. -#' @param pointsize `size` parameter passed to -#' [ggplot2::geom_point()]. Default 4. -#' @param forecast_linecolor `color` parameter -#' passed to [ggplot2::geom_line()] for plotting forecasts. -#' Default `"darkblue"`. -#' @param forecast_pointcolor `color` parameter passed to -#' [ggplot2::geom_point()] for plotting forecasts. -#' Default "darkblue". -#' @param truth_linecolor `color` parameter passed to [ggplot2::geom_line()] -#' for plotting truth data. Default `"black"`. -#' @param truth_pointcolor `color` parameter passed to [ggplot2::geom_point()] -#' for plotting truth data. Default `"black"`. -#' @param autotitle Boolean. Generate a title for the individual -#' plots from the hubverse `reference_date` and the location -#' name? Default `TRUE`. -#' @return a list of ggplot objects of the plots created, -#' one for each location -#' @export -plot_hubverse_quantiles <- function(forecast_data_path, - locations = NULL, - truth_data_path = NULL, - start_date = NULL, - end_date = NULL, - location_input_format = "abbr", - location_output_format = "abbr", - ytrans = "log10", - linesize = 2, - pointsize = 4, - forecast_linecolor = "darkblue", - forecast_pointcolor = "darkblue", - truth_linecolor = "black", - truth_pointcolor = "black", - autotitle = TRUE) { - hubverse_cols <- readr::cols( - reference_date = readr::col_date(), - target = readr::col_character(), - horizon = readr::col_integer(), - target_end_date = readr::col_date(), - location = readr::col_character(), - output_type = readr::col_character(), - output_type_id = readr::col_double(), - value = readr::col_double() - ) - forecast_data <- readr::read_csv( - forecast_data_path, - col_types = hubverse_cols - ) |> - dplyr::filter( - output_type == "quantile", - ) |> - dplyr::mutate(output_type_id = as.numeric(output_type_id)) - - if (!is.null(truth_data_path)) { - truth_cols <- readr::cols_only( - date = readr::col_date(), - location = readr::col_character(), - value = readr::col_double() - ) - truth_data <- readr::read_csv(truth_data_path, - col_types = truth_cols - ) - } else { - truth_data <- tibble::tibble( - date = as.Date(numeric(0)), - location = character(0), - value = numeric(0) - ) - } - - if (is.null(locations)) { - locations <- forecast_data |> - dplyr::distinct(location) |> - dplyr::pull() - loc_table <- location_lookup(locations, "hub") - } else { - locations <- base::unique(locations) - loc_table <- location_lookup(locations, location_input_format) - } - - - if (!is.null(start_date)) { - truth_data <- truth_data |> - dplyr::filter(date >= as.Date(!!start_date)) - forecast_data <- forecast_data |> - dplyr::filter(target_end_date >= as.Date(!!start_date)) - } - - if (!is.null(end_date)) { - truth_data <- truth_data |> - dplyr::filter(date <= as.Date(!!end_date)) - forecast_data <- forecast_data |> - dplyr::filter(target_end_date <= as.Date(!!end_date)) - } - - location_vector <- loc_table |> - dplyr::pull(!!to_location_table_column(location_output_format)) - - result <- lapply( - location_vector, - plot_hubverse_quantiles_loc, - forecast_data = forecast_data, - truth_data = truth_data, - location_format = location_output_format, - ytrans = ytrans, - linesize = linesize, - pointsize = pointsize, - forecast_pointcolor = forecast_pointcolor, - forecast_linecolor = forecast_linecolor, - truth_pointcolor = truth_pointcolor, - truth_linecolor = truth_linecolor, - autotitle = autotitle - ) - names(result) <- location_vector - - return(result) -} - - -#' Save a list of plots as a PDF, with a -#' grid of `nrow` by `ncol` plots per page -#' -#' @param list_of_plots list of plots to save to PDF -#' @param save_path path to which to save the plots -#' @param nrow Number of rows of plots per page -#' (passed to [gridExtra::marrangeGrob()]) -#' Default `1`. -#' @param ncol Number of columns of plots per page -#' (passed to [gridExtra::marrangeGrob()]). -#' Default `1`. -#' @param width page width in device units (passed to -#' [ggplot2::ggsave()]). Default `8.5`. -#' @param height page height in device units (passed to -#' [ggplot2::ggsave()]). Default `11`. -#' @return `TRUE` on success. -#' @export -plots_to_pdf <- function(list_of_plots, - save_path, - nrow = 1, - ncol = 1, - width = 8.5, - height = 11) { - if (!stringr::str_ends( - save_path, ".pdf" - )) { - cli::cli_abort("Filepath must end with `.pdf`") - } - cli::cli_inform("Saving plots to {save_path}") - ggplot2::ggsave( - filename = save_path, - plot = gridExtra::marrangeGrob(list_of_plots, - nrow = nrow, - ncol = ncol - ), - width = width, - height = height - ) - return(TRUE) -} diff --git a/R/plot_utils.R b/R/plot_utils.R new file mode 100644 index 0000000..1b83411 --- /dev/null +++ b/R/plot_utils.R @@ -0,0 +1,42 @@ +#' Save a list of ggplot plots as a PDF, with a +#' grid of `nrow` by `ncol` plots per page +#' +#' @param list_of_plots List of plots to save to PDF. +#' @param save_path Path to which to save the plots. Must +#' end in `.pdf`. +#' @param nrow Number of rows of plots per page +#' (passed to [gridExtra::marrangeGrob()]) +#' Default `1`. +#' @param ncol Number of columns of plots per page +#' (passed to [gridExtra::marrangeGrob()]). +#' Default `1`. +#' @param width page width in device units (passed to +#' [ggplot2::ggsave()]). Default `8.5`. +#' @param height page height in device units (passed to +#' [ggplot2::ggsave()]). Default `11`. +#' @return Nothing, saving the plots as a side effect. +#' @export +plots_to_pdf <- function(list_of_plots, + save_path, + nrow = 1, + ncol = 1, + width = 8.5, + height = 11) { + save_ext <- fs::path_ext(save_path) + if (!save_ext == "pdf") { + cli::cli_abort(paste0( + "{save_path} file extension must ", + "be 'pdf', got '{save_ext}'" + )) + } + cli::cli_inform("Saving plots to {save_path}") + ggplot2::ggsave( + filename = save_path, + plot = gridExtra::marrangeGrob(list_of_plots, + nrow = nrow, + ncol = ncol + ), + width = width, + height = height + ) +} diff --git a/man/plot_forecast_quantiles.Rd b/man/plot_forecast_quantiles.Rd deleted file mode 100644 index 30022ed..0000000 --- a/man/plot_forecast_quantiles.Rd +++ /dev/null @@ -1,50 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plot_quantiles.R -\name{plot_forecast_quantiles} -\alias{plot_forecast_quantiles} -\title{Plot a timeseries of quantiles} -\usage{ -plot_forecast_quantiles( - data, - time_column, - observation_column, - quantile_level_column, - linesize = 2, - pointsize = 4, - pointcolor = "darkblue", - linecolor = "darkblue" -) -} -\arguments{ -\item{data}{timeseries of quantiles as tidy data, -with one row per timepoint per quantile level} - -\item{time_column}{name of the column in \code{data} -containing timepoints} - -\item{observation_column}{name of the column -in data containing observed values at the -given quantile levels} - -\item{quantile_level_column}{name of the column -in \code{data} giving the quantile level (e.g. -\code{0.01} for the 0.01 quantile / 1st percentile)} - -\item{linesize}{\code{size} parameter passed to \code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. -Default 2.} - -\item{pointsize}{\code{size} parameter passed to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} -Default 4.} - -\item{pointcolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} -Default \code{"darkblue"}.} - -\item{linecolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. -Default \code{"darkblue"}.} -} -\value{ -the resultant plot, as a ggplot object. -} -\description{ -Plot a timeseries of quantiles -} diff --git a/man/plot_hubverse_quantiles.Rd b/man/plot_hubverse_file_quantiles.Rd similarity index 58% rename from man/plot_hubverse_quantiles.Rd rename to man/plot_hubverse_file_quantiles.Rd index 0970b5f..28c68f9 100644 --- a/man/plot_hubverse_quantiles.Rd +++ b/man/plot_hubverse_file_quantiles.Rd @@ -1,32 +1,32 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plot_quantiles.R -\name{plot_hubverse_quantiles} -\alias{plot_hubverse_quantiles} +% Please edit documentation in R/plot_hubverse_timeseries.R +\name{plot_hubverse_file_quantiles} +\alias{plot_hubverse_file_quantiles} \title{Plot hubverse formatted forecasts for all or a subset of forecasted locations.} \usage{ -plot_hubverse_quantiles( - forecast_data_path, +plot_hubverse_file_quantiles( + forecast_file_path, locations = NULL, - truth_data_path = NULL, + observed_data_path = NULL, start_date = NULL, end_date = NULL, location_input_format = "abbr", location_output_format = "abbr", - ytrans = "log10", - linesize = 2, + y_transform = "log10", + linewidth = 2, pointsize = 4, forecast_linecolor = "darkblue", forecast_pointcolor = "darkblue", - truth_linecolor = "black", - truth_pointcolor = "black", + obs_linecolor = "black", + obs_pointcolor = "black", autotitle = TRUE ) } \arguments{ -\item{forecast_data_path}{path to hubverse- -formatted forecast data, as a single \code{.csv}.} +\item{forecast_file_path}{path to hubverse- +formatted forecast data, as a single \code{.csv} file.} \item{locations}{set of locations to plot. If NULL, all locations are plotted. Otherwise, a vector @@ -38,20 +38,20 @@ jurisdiction names (e.g. \verb{c("United States, "Alabama", "Alaska")}. Default \code{NULL}.} -\item{truth_data_path}{path to hubverse formatted truth data -to plot alongside the forecast quantiles. If NULL, -only the forecast quantiles will be plotted. Default NULL.} +\item{observed_data_path}{path to observed data +to plot alongside the forecast quantiles. If \code{NULL}, +only the forecast quantiles will be plotted. Default \code{NULL}.} \item{start_date}{first date to plot. If NULL, defaults to the earliest date found between the forecast timeseries ( -obtained from \code{forecast_data_path}) and the truth -data timeseries (obtained from \code{truth_data_path}, if +obtained from \code{forecast_file_path}) and the observed +data timeseries (obtained from \code{observed_data_path}, if provided). Default NULL.} \item{end_date}{final date to plot. If NULL, defaults to the latest date found between the forecast timeseries ( -obtained from \code{forecast_data_path}) and the truth -data timeseries (obtained from \code{truth_data_path}, if +obtained from \code{forecast_file_path}) and the observed +data timeseries (obtained from \code{observed_data_path}, if provided). Default NULL.} \item{location_input_format}{format of the provided location @@ -65,14 +65,14 @@ jurisdiction names; not recommended). Default \code{"abbr"}.} entries of the output list. Accepts the same string keys as \code{location_input_format}.} -\item{ytrans}{axis transform passed to -\code{\link[ggplot2:scale_continuous]{ggplot2::scale_y_continuous()}}. Default \code{'log10'}.} +\item{y_transform}{axis transform passed as the \code{transform} +argument to \code{\link[ggplot2:scale_continuous]{ggplot2::scale_y_continuous()}}. Default \code{"log10"}.} -\item{linesize}{\code{size} parameter passed to -\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. Default 2.} +\item{linewidth}{\code{linewidth} parameter passed to +\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. Default \code{2}.} \item{pointsize}{\code{size} parameter passed to -\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}. Default 4.} +\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}. Default \code{4}.} \item{forecast_linecolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_path]{ggplot2::geom_line()}} for plotting forecasts. @@ -80,17 +80,17 @@ Default \code{"darkblue"}.} \item{forecast_pointcolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} for plotting forecasts. -Default "darkblue".} +Default \code{"darkblue"}.} -\item{truth_linecolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_path]{ggplot2::geom_line()}} -for plotting truth data. Default \code{"black"}.} +\item{obs_linecolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_path]{ggplot2::geom_line()}} +for plotting observed data. Default \code{"black"}.} -\item{truth_pointcolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} -for plotting truth data. Default \code{"black"}.} +\item{obs_pointcolor}{\code{color} parameter passed to +\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} for plotting observed data. Default \code{"black"}.} -\item{autotitle}{Boolean. Generate a title for the individual +\item{autotitle}{Generate a title for the individual plots from the hubverse \code{reference_date} and the location -name? Default \code{TRUE}.} +name? Boolean, default \code{TRUE}.} } \value{ a list of ggplot objects of the plots created, diff --git a/man/plot_hubverse_quantiles_loc.Rd b/man/plot_hubverse_loc_quant_ts.Rd similarity index 64% rename from man/plot_hubverse_quantiles_loc.Rd rename to man/plot_hubverse_loc_quant_ts.Rd index 45c18ac..2206fc4 100644 --- a/man/plot_hubverse_quantiles_loc.Rd +++ b/man/plot_hubverse_loc_quant_ts.Rd @@ -1,22 +1,22 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plot_quantiles.R -\name{plot_hubverse_quantiles_loc} -\alias{plot_hubverse_quantiles_loc} -\title{Plot hubverse formatted quantile forecasts for a given -location.} +% Please edit documentation in R/plot_hubverse_timeseries.R +\name{plot_hubverse_loc_quant_ts} +\alias{plot_hubverse_loc_quant_ts} +\title{Plot a hubverse formatted quantile forecast timeseries +for a single location.} \usage{ -plot_hubverse_quantiles_loc( +plot_hubverse_loc_quant_ts( location, forecast_data, - truth_data, + observed_data, location_format = "abbr", - ytrans = "log10", - linesize = 2, + y_transform = "log10", + linewidth = 2, pointsize = 4, forecast_linecolor = "darkblue", forecast_pointcolor = "darkblue", - truth_linecolor = "black", - truth_pointcolor = "black", + obs_linecolor = "black", + obs_pointcolor = "black", target_name = NULL, autotitle = TRUE ) @@ -27,7 +27,7 @@ plot_hubverse_quantiles_loc( \item{forecast_data}{hubverse format quantile forecast data, as a \code{\link[tibble:tibble]{tibble}}.} -\item{truth_data}{hubverse format truth data, +\item{observed_data}{observed data, as a \code{\link[tibble:tibble]{tibble}}.} \item{location_format}{format of the provided location. @@ -37,30 +37,31 @@ legacy 2-digit FIPS code for states and territories, \code{US} for the USA as a whole), and \code{"long_name"} (full English jurisdiction names; not recommended). Default \code{"abbr"}.} -\item{ytrans}{axis transform passed to -\code{\link[ggplot2:scale_continuous]{ggplot2::scale_y_continuous()}}. Default \code{'log10'}.} +\item{y_transform}{axis transform passed as the +\code{transform} argument to \code{\link[ggplot2:scale_continuous]{ggplot2::scale_y_continuous()}}. +Default \code{"log10"}.} -\item{linesize}{\code{size} parameter passed to -\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. Default 2.} +\item{linewidth}{\code{linewidth} parameter passed to +\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. Default \code{2}.} \item{pointsize}{\code{size} parameter passed to -\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}. Default 4.} +\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}. Default \code{4}.} \item{forecast_linecolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_path]{ggplot2::geom_line()}} for plotting forecasts. -Default "darkblue".} +Default \code{"darkblue"}.} \item{forecast_pointcolor}{\code{color} parameter passed to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} for plotting forecasts. -Default "darkblue".} +Default \code{"darkblue"}.} -\item{truth_linecolor}{\code{color} parameter passed to -\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}} for plotting truth data. -Default "black".} +\item{obs_linecolor}{\code{color} parameter passed to +\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}} for plotting observed data. +Default \code{"black"}.} -\item{truth_pointcolor}{\code{color} parameter passed to -\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} for plotting truth data. -Default "black".} +\item{obs_pointcolor}{\code{color} parameter passed to +\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} for plotting observed data. +Default \code{"black"}.} \item{target_name}{Name of the forecast target, for labeling the plot y-axis. Default \code{NULL}, @@ -77,6 +78,6 @@ the plot as a ggplot object \description{ Given a tibble of data properly formatted for a hubverse schema forecast hub submission, -plot a timeseries quantile predictions for +plot a timeseries of quantile predictions for a given location. } diff --git a/man/plot_quantile_timeseries.Rd b/man/plot_quantile_timeseries.Rd new file mode 100644 index 0000000..14058f4 --- /dev/null +++ b/man/plot_quantile_timeseries.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plot_quantiles.R +\name{plot_quantile_timeseries} +\alias{plot_quantile_timeseries} +\title{Plot a timeseries of quantiles.} +\usage{ +plot_quantile_timeseries( + data, + time_column, + value_column, + quantile_level_column, + linewidth = 2, + pointsize = 4, + pointcolor = "darkblue", + linecolor = "darkblue" +) +} +\arguments{ +\item{data}{Timeseries of quantiles as tidy data, +with one row per timepoint per quantile level.} + +\item{time_column}{Name of the column in \code{data} +containing timepoint values, as a string.} + +\item{value_column}{Name of the column +in data containing the timeseries values at the +given quantile levels, as a string.} + +\item{quantile_level_column}{Name of the column in \code{data} +containing indicating which quantile level the row contains, +as a string.} + +\item{linewidth}{\code{linewidth} parameter passed to +\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. Default \code{2}.} + +\item{pointsize}{\code{size} parameter passed to +\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} Default \code{4}.} + +\item{pointcolor}{\code{color} parameter passed to +\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} Default \code{"darkblue"}.} + +\item{linecolor}{\code{color} parameter passed to +\code{\link[ggplot2:geom_path]{ggplot2::geom_line()}}. Default \code{"darkblue"}.} +} +\value{ +The plot, as a ggplot object. +} +\description{ +Plot a timeseries of quantiles. +} diff --git a/man/plots_to_pdf.Rd b/man/plots_to_pdf.Rd index 71a5038..2c8538e 100644 --- a/man/plots_to_pdf.Rd +++ b/man/plots_to_pdf.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plot_quantiles.R +% Please edit documentation in R/plot_utils.R \name{plots_to_pdf} \alias{plots_to_pdf} -\title{Save a list of plots as a PDF, with a +\title{Save a list of ggplot plots as a PDF, with a grid of \code{nrow} by \code{ncol} plots per page} \usage{ plots_to_pdf( @@ -15,9 +15,10 @@ plots_to_pdf( ) } \arguments{ -\item{list_of_plots}{list of plots to save to PDF} +\item{list_of_plots}{List of plots to save to PDF.} -\item{save_path}{path to which to save the plots} +\item{save_path}{Path to which to save the plots. Must +end in \code{.pdf}.} \item{nrow}{Number of rows of plots per page (passed to \code{\link[gridExtra:arrangeGrob]{gridExtra::marrangeGrob()}}) @@ -34,9 +35,9 @@ Default \code{1}.} \code{\link[ggplot2:ggsave]{ggplot2::ggsave()}}). Default \code{11}.} } \value{ -\code{TRUE} on success. +Nothing, saving the plots as a side effect. } \description{ -Save a list of plots as a PDF, with a +Save a list of ggplot plots as a PDF, with a grid of \code{nrow} by \code{ncol} plots per page } diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..a328e6d --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(forecasttools) + +test_check("forecasttools") diff --git a/tests/testthat/test_daily_to_epiweekly.R b/tests/testthat/test_daily_to_epiweekly.R new file mode 100644 index 0000000..42a74ab --- /dev/null +++ b/tests/testthat/test_daily_to_epiweekly.R @@ -0,0 +1,93 @@ +dat <- forecasttools::example_daily_forecast_flu + +test_that( + paste0( + "daily_to_epiweekly works identically to a ", + "on the example data (unit test based on the ", + "example in the hubverse formatting vignette)." + ), + { + expected <- dat |> + dplyr::mutate( + epiweek = lubridate::epiweek(date), + epiyear = lubridate::epiyear(date) + ) |> + dplyr::group_by( + epiweek, + epiyear, + .draw, + location + ) |> + dplyr::filter(dplyr::n() == 7) |> + dplyr::summarise( + weekly_hosp = sum(hosp), + .groups = "drop" + ) + + result <- daily_to_epiweekly( + dat, + value_col = "hosp", + id_cols = c(".draw", "location"), + weekly_value_name = "weekly_hosp" + ) + + expect_equal(result, expected) + + ## should be different with partial weeks + ## included + expected_with_partial <- dat |> + dplyr::mutate( + epiweek = lubridate::epiweek(date), + epiyear = lubridate::epiyear(date) + ) |> + dplyr::group_by( + epiweek, + epiyear, + .draw, + location + ) |> + dplyr::summarise( + weekly_hosp = sum(hosp), + .groups = "drop" + ) + + expect_true(nrow(result) < nrow(expected_with_partial)) + + result_with_partial <- daily_to_epiweekly( + dat, + value_col = "hosp", + id_cols = c(".draw", "location"), + weekly_value_name = "weekly_hosp", + strict = FALSE + ) + + expect_equal(result_with_partial, expected_with_partial) + } +) + +test_that(paste0( + "daily_to_epiweekly() errors by default if more than ", + "seven entries for a given epiweekly trajectory" +), { + dat_duplicate_row <- dat |> + dplyr::filter( + date == as.Date("2023-10-30"), + location == "KS", + .draw == 18 + ) + expect_equal(nrow(dat_duplicate_row), 1) + + ## duplicate only one row, otherwise data + ## still valid. Error should still occur. + dat_duplicated <- dplyr::bind_rows(dat, dat_duplicate_row) + + expect_error( + daily_to_epiweekly( + dat_duplicated, + value_col = "hosp", + id_cols = c(".draw", "location"), + weekly_value_name = "weekly_hosp" + ), + regexp = "repeated values" + ) +}) diff --git a/tests/testthat/test_epiweek_to_date.R b/tests/testthat/test_epiweek_to_date.R index 83e0d3e..1043b3c 100644 --- a/tests/testthat/test_epiweek_to_date.R +++ b/tests/testthat/test_epiweek_to_date.R @@ -4,56 +4,50 @@ schema <- tidyr::crossing( day_of_week = 1:7 ) -testthat::test_that(paste0( +test_that(paste0( "epiweek_to_date() function's internal ", "validation passes for USA epiweeks for ", "every epiweek in 1:52 for every epiyear ", "in 1800:2200, for every day of the epiweek" ), { - testthat::expect_no_error( - with_usa_dates <- schema |> - dplyr::mutate( - date = forecasttools::epiweek_to_date( - epiweek, - epiyear, - epiweek_standard = "USA", - day_of_week = day_of_week, - validate = TRUE - ) - ) + expect_no_warning( + epiweek_to_date( + schema$epiweek, + schema$epiyear, + epiweek_standard = "USA", + day_of_week = schema$day_of_week, + validate = TRUE + ) ) }) -testthat::test_that(paste0( +test_that(paste0( "epiweek_to_date() function's internal ", "validation passes for ISO (epi)weeks for ", "every epiweek in 1:52 for every epiyear ", "in 1800:2200, for every day of the epiweek" ), { - testthat::expect_no_error( - with_iso_dates <- schema |> - dplyr::mutate( - date = forecasttools::epiweek_to_date( - epiweek, - epiyear, - epiweek_standard = "ISO", - day_of_week = day_of_week, - validate = TRUE - ) - ) + expect_no_warning( + epiweek_to_date( + schema$epiweek, + schema$epiyear, + epiweek_standard = "ISO", + day_of_week = schema$day_of_week, + validate = TRUE + ) ) }) -testthat::test_that(paste0( +test_that(paste0( "epiweek_to_date() function's internal ", "validation fails if you try to get the ", "start of an epiweek that doesn't exist ", "but passes if you get a valid epiweek" ), { ## 2020 had an epiweek 53 - testthat::expect_no_error( - forecasttools::epiweek_to_date( + expect_no_error( + epiweek_to_date( 53, 2020, epiweek_standard = "USA", @@ -62,8 +56,8 @@ testthat::test_that(paste0( ) ## 2021 did not - testthat::expect_error( - forecasttools::epiweek_to_date( + expect_error( + epiweek_to_date( 53, 2021, epiweek_standard = "USA", @@ -72,8 +66,8 @@ testthat::test_that(paste0( ) ## a single failure should raise an error - testthat::expect_error( - forecasttools::epiweek_to_date( + expect_error( + epiweek_to_date( 53, c(2020, 2021), epiweek_standard = "USA", @@ -83,8 +77,8 @@ testthat::test_that(paste0( ## but the validation should be vectorized ## and succeed accordingly - testthat::expect_no_error( - forecasttools::epiweek_to_date( + expect_no_error( + epiweek_to_date( c(53, 52), c(2020, 2021), epiweek_standard = "USA", diff --git a/tests/testthat/test_inferencedata_dataframe_to_tidydraws.R b/tests/testthat/test_inferencedata_dataframe_to_tidydraws.R index def21b5..8a78b9e 100644 --- a/tests/testthat/test_inferencedata_dataframe_to_tidydraws.R +++ b/tests/testthat/test_inferencedata_dataframe_to_tidydraws.R @@ -1,11 +1,11 @@ -testthat::test_that("inferencedata_to_tidy_draws converts data correctly", { +test_that("inferencedata_to_tidy_draws converts data correctly", { data("ex_inferencedata_dataframe") result <- inferencedata_to_tidy_draws(ex_inferencedata_dataframe) - testthat::expect_setequal(colnames(result), c("group", "data")) - testthat::expect_setequal(result$group, c("posterior", "predictions")) + expect_setequal(colnames(result), c("group", "data")) + expect_setequal(result$group, c("posterior", "predictions")) - testthat::expect_equal( + expect_equal( colnames(result$data[[1]]), c( ".chain", ".iteration", ".draw", "a", "b[troll_shore]", "b[drawn]", @@ -17,7 +17,7 @@ testthat::test_that("inferencedata_to_tidy_draws converts data correctly", { ) ) - testthat::expect_equal( + expect_equal( colnames(result$data[[2]]), c( ".chain", ".iteration", ".draw", "obs[woken]", "obs[awash]", @@ -25,10 +25,10 @@ testthat::test_that("inferencedata_to_tidy_draws converts data correctly", { ) ) - testthat::expect_no_error( + expect_no_error( tidybayes::spread_draws(result$data[[1]], a, b[x], c[y, z]) ) - testthat::expect_no_error( + expect_no_error( tidybayes::spread_draws(result$data[[2]], obs[a]) ) }) diff --git a/tests/testthat/test_simple_bottom_up.R b/tests/testthat/test_simple_bottom_up.R index 3162c46..ee0e022 100644 --- a/tests/testthat/test_simple_bottom_up.R +++ b/tests/testthat/test_simple_bottom_up.R @@ -32,8 +32,8 @@ test_u_mat <- matrix(c(0.1, 0.3, 0.7), nrow = 1) location_names <- c("A", "B", "C") colnames(test_u_mat) <- location_names -testthat::test_that("`validate_base_forecasts` throws an error", { - testthat::expect_error(validate_base_forecasts(bad_test_base_forecasts, +test_that("`validate_base_forecasts` throws an error", { + expect_error(validate_base_forecasts(bad_test_base_forecasts, test_cp, value_to_aggregate_col = "hosps", rank_quantity_col = "rank_quantity", @@ -42,7 +42,7 @@ testthat::test_that("`validate_base_forecasts` throws an error", { )) }) -testthat::test_that("`count_trajectories` returns correct number of trajs", { +test_that("`count_trajectories` returns correct number of trajs", { result <- count_trajectories(test_base_forecasts, location_col = "location", date_col = "date" @@ -51,10 +51,10 @@ testthat::test_that("`count_trajectories` returns correct number of trajs", { location = c("A", "B", "C"), n_sample_trajs = c(2, 2, 2) ) - testthat::expect_equal(result, expected_output) + expect_equal(result, expected_output) }) -testthat::test_that("`copula2tbl` returns the expected output", { +test_that("`copula2tbl` returns the expected output", { i <- 1 location_col <- "location" @@ -65,10 +65,10 @@ testthat::test_that("`copula2tbl` returns the expected output", { location = location_names ) - testthat::expect_equal(result, expected_output) + expect_equal(result, expected_output) }) -testthat::test_that("`rank_sampled_trajectories` returns correct rankings", { +test_that("`rank_sampled_trajectories` returns correct rankings", { ranked_base_forecasts <- rank_sampled_trajectories(test_base_forecasts, location_col = "location", @@ -83,10 +83,10 @@ testthat::test_that("`rank_sampled_trajectories` returns correct rankings", { rank = c(1, 2, 1, 2, 1, 2) ) - testthat::expect_equal(ranked_base_forecasts, expected_rankings) + expect_equal(ranked_base_forecasts, expected_rankings) }) -testthat::test_that("sample_aggregated_trajectories", { +test_that("sample_aggregated_trajectories", { i <- 1 location_col <- "location" test_sample <- copula2tbl( @@ -123,5 +123,5 @@ testthat::test_that("sample_aggregated_trajectories", { forecast = c(123, 200) ) - testthat::expect_equal(result, expected_output) + expect_equal(result, expected_output) }) diff --git a/tests/testthat/test_to_hubverse.R b/tests/testthat/test_to_hubverse.R index 0a11854..048b239 100644 --- a/tests/testthat/test_to_hubverse.R +++ b/tests/testthat/test_to_hubverse.R @@ -1,17 +1,17 @@ -testthat::test_that( +test_that( paste0( "get_hubverse_table errors if reference date ", "is the wrong day of the week" ), { - testthat::expect_error( + expect_error( forecasttools::get_hubverse_table( tibble::tibble(), "2025-01-01" ), "which is day number 4" ) - testthat::expect_error( + expect_error( forecasttools::get_hubverse_table( tibble::tibble(), "2025-01-01", @@ -19,7 +19,7 @@ testthat::test_that( ), "which is day number 1" ) - testthat::expect_error( + expect_error( forecasttools::get_hubverse_table( tibble::tibble(), "2025-01-01", diff --git a/vignettes/plot-hub-submission.Rmd b/vignettes/plot-hub-submission.Rmd index 3fe07d3..83cbc80 100644 --- a/vignettes/plot-hub-submission.Rmd +++ b/vignettes/plot-hub-submission.Rmd @@ -31,16 +31,16 @@ library(forecasttools) ``` # Quantile timeseries -Much hubverse formatted output is organized into quantiles. An easy spotcheck plot shows how these quantiles evolve over the forecast horizon. We can make it using the `plot_hubverse_quantiles()` function. There is only one mandatory argument: the path to a properly hubverse-formatted `.csv` file. Let's plot some inflenza forecasts submitted to the 2023-24 FluSight Challenge by the `cfarenewal-cfaepimlight` team for the 2024-04-06 reference date: +Much hubverse formatted output is organized into quantiles. An easy spotcheck plot shows how these quantiles evolve over the forecast horizon. We can make it using the `plot_hubverse_file_quantiles()` function. There is only one mandatory argument: the path to a properly hubverse-formatted `.csv` file. Let's plot some inflenza forecasts submitted to the 2023-24 FluSight Challenge by the `cfarenewal-cfaepimlight` team for the 2024-04-06 reference date: ```{r, message = FALSE, echo = c(2, 4)} # nolint start path_to_formatted_forecast <- "https://raw.githubusercontent.com/cdcepi/FluSight-forecast-hub/refs/heads/main/model-output/cfarenewal-cfaepimlight/2024-04-06-cfarenewal-cfaepimlight.csv" # nolint end -plots <- plot_hubverse_quantiles(path_to_formatted_forecast) +plots <- plot_hubverse_file_quantiles(path_to_formatted_forecast) ``` -`plot_hubverse_quantiles()` returns a list of all the plots generated. By default, the list names (keys) are US Postal Service style two-letter abbreviations. Let's look at the national plot: +`plot_hubverse_file_quantiles()` returns a list of all the plots generated. By default, the list names (keys) are US Postal Service style two-letter abbreviations. Let's look at the national plot: ```{r} plots[["US"]] @@ -52,10 +52,10 @@ We can also look at the plot for Colorado: plots[["CO"]] ``` -Of course, you may not wish to generate plots for all locations in your hubverse-formatted file at once. `plot_hubverse_quantiles()` takes an optional `locations` argument that allows you to plot only a subset. For example, let's plot the ["Four Corners" states](https://en.wikipedia.org/wiki/Four_Corners): +Of course, you may not wish to generate plots for all locations in your hubverse-formatted file at once. `plot_hubverse_file_quantiles()` takes an optional `locations` argument that allows you to plot only a subset. For example, let's plot the ["Four Corners" states](https://en.wikipedia.org/wiki/Four_Corners): ```{r, message = FALSE} -four_corners <- plot_hubverse_quantiles(path_to_formatted_forecast, +four_corners <- plot_hubverse_file_quantiles(path_to_formatted_forecast, locations = c("AZ", "CO", "NM", "UT") ) @@ -63,33 +63,34 @@ four_corners <- plot_hubverse_quantiles(path_to_formatted_forecast, four_corners[["NM"]] ``` -Many hubs provide "truth data" of observed values of the forecasting target, and so `plot_hubverse_quantiles()` optionally allows you to plot this alongside the forecast data. Since this truth data often goes back years, it is useful to set a cutoff using the `start_date` argument. Here, we'll start in December 2023. +Many hubs provide "target data" or "truth data" of observed values of the forecasting target, and so `plot_hubverse_file_quantiles()` optionally allows you to plot this alongside the forecast data. Since this target data often goes back years, it is useful to set a cutoff using the `start_date` argument. Here, we'll start in December 2023. ```{r, message = FALSE, echo = c(2, 4:7)} # nolint start -truth_data <- "https://raw.githubusercontent.com/cdcepi/FluSight-forecast-hub/04e884dce942dd3b8766aee3d8ff1c333b4fb6fa/target-data/target-hospital-admissions.csv" +target_data_path <- "https://raw.githubusercontent.com/cdcepi/FluSight-forecast-hub/04e884dce942dd3b8766aee3d8ff1c333b4fb6fa/target-data/target-hospital-admissions.csv" # nolint end -plot_hubverse_quantiles(path_to_formatted_forecast, +plot_hubverse_file_quantiles(path_to_formatted_forecast, locations = "US", - truth_data_path = truth_data, + observed_data_path = target_data_path, start_date = "2023-12-01" ) ``` -The function provides some basic customization of line and point sizes and colors, via the `linesize`, `pointsize`, `forecast_linecolor`, `forecast_pointcolor`, `truth_pointcolor`, and `truth_linecolor` arguments. It also defaults to plotting a log10-scale y-axis, but this can be changed by passing a different string to `ytrans`; any valid value for the `transform = ` argument of `ggplot2::scale_y_continuous()` can be passed. +The function provides some basic customization of plotted lines and points via the `linewidth`, `pointsize`, `forecast_linecolor`, `forecast_pointcolor`, `obs_pointcolor`, and `obs_linecolor` arguments. It also defaults to plotting on a log10-scale y-axis, but this can be changed by passing a different string to `y_transform`; any valid value for the `transform = ` argument of `ggplot2::scale_y_continuous()` can be passed. ```{r, message = FALSE} ## plot forecast data in green, with smaller points and ## lines, and plot on a linear scale -my_custom_plot <- plot_hubverse_quantiles(path_to_formatted_forecast, +my_custom_plot <- plot_hubverse_file_quantiles( + path_to_formatted_forecast, locations = "US", - truth_data_path = truth_data, + observed_data_path = target_data_path, start_date = "2023-12-01", forecast_linecolor = "darkgreen", forecast_pointcolor = "darkgreen", pointsize = 1, - linesize = 1, - ytrans = "identity" + linewidth = 1, + y_transform = "identity" ) my_custom_plot[["US"]] ``` diff --git a/vignettes/scoring-flu-forecasts.Rmd b/vignettes/scoring-flu-forecasts.Rmd index 9fcf66a..a259e39 100644 --- a/vignettes/scoring-flu-forecasts.Rmd +++ b/vignettes/scoring-flu-forecasts.Rmd @@ -18,7 +18,7 @@ knitr::opts_chunk$set( ) ``` -```{r setup, messages = "hide"} +```{r setup, message = FALSE} library(forecasttools) library(scoringutils) library(dplyr)