From a628525ef71228b6a4a30ef5959b6721da7833e0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 31 Oct 2024 14:15:05 +0000 Subject: [PATCH 001/110] fix targets pipeline for new input fxns --- _targets_eval_postprocessing.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index c45d3067..7d77a5bf 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1455,7 +1455,7 @@ hub_comparison_plots <- list( # Benchmarking---------------------------------------------------------- benchmarks <- list( tar_target( - name = write_benchmark_table_full_run, + name = benchmark_table_full_run, command = benchmark_performance( ww_scores = all_ww_scores, hosp_scores = all_hosp_scores, @@ -1470,7 +1470,8 @@ benchmarks <- list( command = plot_benchmarks( grouping_var = "location", benchmark_scope = "all_forecasts", - benchmark_dir = benchmark_config$benchmark_dir + benchmark_dir = benchmark_config$benchmark_dir, + scores_list = benchmark_table_full_run ) ), tar_target( @@ -1478,7 +1479,8 @@ benchmarks <- list( command = plot_benchmarks( grouping_var = "forecast_date", benchmark_scope = "all_forecasts", - benchmark_dir = benchmark_config$benchmark_dir + benchmark_dir = benchmark_config$benchmark_dir, + scores_list = benchmark_table_full_run ) ) ) From d5a935cbc2a860ab3ab4804a74d889b9a8b4ce70 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 31 Oct 2024 15:41:41 +0000 Subject: [PATCH 002/110] keep eval_fit from failing when ww is missing --- wweval/R/eval_fit.R | 102 +++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 39 deletions(-) diff --git a/wweval/R/eval_fit.R b/wweval/R/eval_fit.R index 9f2c7168..8db71295 100644 --- a/wweval/R/eval_fit.R +++ b/wweval/R/eval_fit.R @@ -57,44 +57,59 @@ eval_fit_ww <- function(config_index, last_hosp_data_date <- get_last_hosp_data_date(input_hosp_data) - input_ww_data <- get_input_ww_data( - forecast_date_i = forecast_date, - location_i = location, - scenario_i = scenario, - scenario_dir = eval_config$scenario_dir, - ww_data_dir = eval_config$ww_data_dir, - calibration_time = eval_config$calibration_time, - last_hosp_data_date = last_hosp_data_date, - ww_data_mapping = eval_config$ww_data_mapping + input_ww_data <- tryCatch( + { + # Try to execute the risky function + get_input_ww_data( + forecast_date_i = forecast_date, + location_i = location, + scenario_i = scenario, + scenario_dir = eval_config$scenario_dir, + ww_data_dir = eval_config$ww_data_dir, + calibration_time = eval_config$calibration_time, + last_hosp_data_date = last_hosp_data_date, + ww_data_mapping = eval_config$ww_data_mapping + ) + }, + error = function(e) { + # Handle the error + message("Caught an error: ", e$message) + } ) + save_object("input_ww_data", output_file_suffix) ## Use wwinference to fit the model------------------------------------------ - ww_fit_obj <- wwinference::wwinference( - ww_data = input_ww_data, - count_data = input_hosp_data, - forecast_date = forecast_date, - calibration_time = eval_config$calibration_time, - forecast_horizon = eval_config$forecast_time, - model_spec = wwinference::get_model_spec( - generation_interval = eval_config$generation_interval, - inf_to_count_delay = wwinference::default_covid_inf_to_hosp, # eval_config$inf_to_hosp, - infection_feedback_pmf = eval_config$infection_feedback_pmf, - params = params - ), - fit_opts = list( - seed = eval_config$seed, - iter_sampling = eval_config$iter_sampling, - adapt_delta = eval_config$adapt_delta, - chains = eval_config$n_chains, - max_treedepth = eval_config$max_treedepth + if (!is.null(input_ww_data)) { + ww_fit_obj <- wwinference::wwinference( + ww_data = input_ww_data, + count_data = input_hosp_data, + forecast_date = forecast_date, + calibration_time = eval_config$calibration_time, + forecast_horizon = eval_config$forecast_time, + model_spec = wwinference::get_model_spec( + generation_interval = eval_config$generation_interval, + inf_to_count_delay = wwinference::default_covid_inf_to_hosp, # eval_config$inf_to_hosp, + infection_feedback_pmf = eval_config$infection_feedback_pmf, + params = params + ), + fit_opts = list( + seed = eval_config$seed, + iter_sampling = eval_config$iter_sampling, + adapt_delta = eval_config$adapt_delta, + chains = eval_config$n_chains, + max_treedepth = eval_config$max_treedepth + ) ) - ) + } else { + ww_fit_obj <- list(error = "missing ww data") + } save_object("ww_fit_obj", output_file_suffix) + # Get the evaluation data from the specified evaluation date ---------------- eval_hosp_data <- get_input_hosp_data( forecast_date_i = eval_config$eval_date, @@ -106,17 +121,26 @@ eval_fit_ww <- function(config_index, save_object("eval_hosp_data", output_file_suffix) - eval_ww_data <- get_input_ww_data( - forecast_date_i = eval_config$eval_date, - location_i = location, - scenario_i = "status_quo", - scenario_dir = eval_config$scenario_dir, - ww_data_dir = eval_config$ww_data_dir, - calibration_time = 365, # Grab sufficient data for eval - last_hosp_data_date = eval_config$eval_date, - ww_data_mapping = eval_config$ww_data_mapping - ) |> - dplyr::filter(date >= min(input_ww_data$date)) + eval_ww_data <- tryCatch( + { + # Try to execute the risky function + get_input_ww_data( + forecast_date_i = eval_config$eval_date, + location_i = location, + scenario_i = scenario, + scenario_dir = eval_config$scenario_dir, + ww_data_dir = eval_config$ww_data_dir, + calibration_time = 365, + last_hosp_data_date = eval_config$eval_date, + ww_data_mapping = eval_config$ww_data_mapping + ) |> + dplyr::filter(date >= min(input_ww_data$date)) + }, + error = function(e) { + # Handle the error + message("Caught an error: ", e$message) + } + ) save_object("eval_ww_data", output_file_suffix) From 6a0cd965283150c13af35cb9f8dddca649c5bcc8 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 31 Oct 2024 18:38:59 +0000 Subject: [PATCH 003/110] tweak fit to not error and work if model runs --- wweval/R/eval_fit.R | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wweval/R/eval_fit.R b/wweval/R/eval_fit.R index 8db71295..a98b4dbb 100644 --- a/wweval/R/eval_fit.R +++ b/wweval/R/eval_fit.R @@ -59,7 +59,7 @@ eval_fit_ww <- function(config_index, last_hosp_data_date <- get_last_hosp_data_date(input_hosp_data) input_ww_data <- tryCatch( { - # Try to execute the risky function + # Try to do peprocessing get_input_ww_data( forecast_date_i = forecast_date, location_i = location, @@ -103,7 +103,11 @@ eval_fit_ww <- function(config_index, ) ) } else { - ww_fit_obj <- list(error = "missing ww data") + # Format as expected from cmdstan object + ww_fit_obj <- list( + fit = + list(result = list(error = "missing ww data")) + ) } save_object("ww_fit_obj", output_file_suffix) From 990912a6a260bb0f136c8cc2f3ab74c94e0e7bf0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 31 Oct 2024 18:40:07 +0000 Subject: [PATCH 004/110] save the things that were saved even when model fails, for consistency with prev pipeline --- wweval/R/eval_post_process.R | 768 ++++++++++++++++++----------------- 1 file changed, 395 insertions(+), 373 deletions(-) diff --git a/wweval/R/eval_post_process.R b/wweval/R/eval_post_process.R index 57ec8fe1..1e0ed9a0 100644 --- a/wweval/R/eval_post_process.R +++ b/wweval/R/eval_post_process.R @@ -47,433 +47,455 @@ eval_post_process_ww <- function(config_index, ww_fit_obj_wwinference <- load_object("ww_fit_obj", output_file_suffix) ww_fit_obj <- ww_fit_obj_wwinference$fit$result - ww_raw_draws <- ww_fit_obj$draws() - save_object("ww_raw_draws", output_file_suffix) - ww_diagnostics <- ww_fit_obj$sampler_diagnostics(format = "df") - save_object("ww_diagnostics", output_file_suffix) - ww_diagnostic_summary <- ww_fit_obj$diagnostic_summary() - save_object("ww_diagnostic_summary", output_file_suffix) - errors <- ww_fit_obj$error - save_object("errors", output_file_suffix) - metadata <- ww_fit_obj$metadata() - raw_flags <- get_diagnostic_flags( - ww_fit_obj, - metadata$num_chains, - metadata$iter_sampling - ) - save_object("raw_flags", output_file_suffix) - - # Save some plots of the posterior parameters--------------------- - inf_feedback <- ww_raw_draws |> - tidybayes::spread_draws(!!str2lang("infection_feedback")) |> - dplyr::mutate( - draw = .data$`.draw`, - ) |> - dplyr::select("infection_feedback", "draw") - - p_inf <- ggplot( - inf_feedback, - aes(x = infection_feedback) - ) + - geom_histogram() - - eta_sd <- ww_raw_draws |> - tidybayes::spread_draws(!!str2lang("eta_sd")) |> - dplyr::mutate( - draw = .data$`.draw`, - ) |> - dplyr::select("eta_sd", "draw") - - p_eta_sd <- ggplot( - eta_sd, - aes(x = eta_sd) - ) + - geom_histogram() + # Format input hosp data in format the eval pipeline expects + input_hosp_data_wweval <- input_hosp_data |> + dplyr:::rename( + "daily_hosp_admits" = "count", + "pop" = "total_pop" + ) - ggsave(p_inf, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "inf_feedback.png" - ), - create.dir = TRUE - ) - ggsave(p_eta_sd, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "eta_sd.png" - ), - create.dir = TRUE + input_ww_data_wweval <- tryCatch( + { + input_ww_data |> + dplyr::mutate( + "ww" = exp(.data$log_genome_copies_per_ml), + "lod_sewage" = exp(.data$log_lod) + ) |> + dplyr::rename( + "ww_pop" = "site_pop", + "below_LOD" = "below_lod" + ) + }, + error = function(e) { + # Return an empty tibble if this errors + message("Caught an error: ", e$message) + return(tibble::tibble()) + } ) - save_table( - data_to_save = eta_sd, - type_of_output = "eta_sd", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - save_table( - data_to_save = inf_feedback, - type_of_output = "inf_feedback", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location + # Get table of wastewater data flags + ww_data_flags <- tryCatch( + { + get_ww_data_flags( + input_ww_data_wweval, + forecast_date + ) + }, + error = function(e) { + # Return an empty tibble if this errors + message("Caught an error: ", e$message) + return(tibble::tibble()) + } ) - # Make the data look like it did in wweval------------------------------- - input_hosp_data_wweval <- input_hosp_data |> - dplyr:::rename( - "daily_hosp_admits" = "count", - "pop" = "total_pop" + # If model fit failed, dont produce any of the below outputs + if (!is.null(ww_fit_obj$error)) { + errors <- ww_fit_obj$error + save_object("errors", output_file_suffix) + # Save errors + save_table( + data_to_save = errors, + type_of_output = "errors", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location ) - input_ww_data_wweval <- input_ww_data |> - dplyr::mutate( - "ww" = exp(.data$log_genome_copies_per_ml), - "lod_sewage" = exp(.data$log_lod) - ) |> - dplyr::rename( - "ww_pop" = "site_pop", - "below_LOD" = "below_lod" + } else { # model fit succeeded + + ww_raw_draws <- ww_fit_obj$draws() + save_object("ww_raw_draws", output_file_suffix) + ww_diagnostics <- ww_fit_obj$sampler_diagnostics(format = "df") + save_object("ww_diagnostics", output_file_suffix) + ww_diagnostic_summary <- ww_fit_obj$diagnostic_summary() + save_object("ww_diagnostic_summary", output_file_suffix) + + metadata <- ww_fit_obj$metadata() + raw_flags <- get_diagnostic_flags( + ww_fit_obj, + metadata$num_chains, + metadata$iter_sampling ) + save_object("raw_flags", output_file_suffix) - eval_ww_data_wweval <- eval_ww_data |> - dplyr::mutate( - "ww" = exp(.data$log_genome_copies_per_ml), - "lod_sewage" = exp(.data$log_lod) - ) |> - dplyr::rename( - "ww_pop" = "site_pop", - "below_LOD" = "below_lod" + flags <- raw_flags |> dplyr::mutate( + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) + # Save flags + save_table( + data_to_save = flags, + type_of_output = "flags", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location ) + # Save some plots of the posterior parameters--------------------- + inf_feedback <- ww_raw_draws |> + tidybayes::spread_draws(!!str2lang("infection_feedback")) |> + dplyr::mutate( + draw = .data$`.draw`, + ) |> + dplyr::select("infection_feedback", "draw") + + p_inf <- ggplot( + inf_feedback, + aes(x = infection_feedback) + ) + + geom_histogram() + + eta_sd <- ww_raw_draws |> + tidybayes::spread_draws(!!str2lang("eta_sd")) |> + dplyr::mutate( + draw = .data$`.draw`, + ) |> + dplyr::select("eta_sd", "draw") + + p_eta_sd <- ggplot( + eta_sd, + aes(x = eta_sd) + ) + + geom_histogram() + + ggsave(p_inf, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "inf_feedback.png" + ), + create.dir = TRUE + ) + ggsave(p_eta_sd, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "eta_sd.png" + ), + create.dir = TRUE + ) - # Get table of wastewater data flags - ww_data_flags <- get_ww_data_flags( - input_ww_data_wweval, - forecast_date - ) - # save the flags alongside the input wastewater data and admissions data - save_table( - data_to_save = ww_data_flags, - type_of_output = "ww_data_flags", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - save_table( - data_to_save = input_ww_data_wweval, - type_of_output = "input_ww_data", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - save_table( - data_to_save = input_hosp_data_wweval, - type_of_output = "input_hosp_data", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - - # Save errors - save_table( - data_to_save = errors, - type_of_output = "errors", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - # Get evaluation data from hospital admissions and wastewater - # Join draws and flags with data and metadata - flags <- raw_flags |> dplyr::mutate( - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - # Save flags - save_table( - data_to_save = flags, - type_of_output = "flags", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) - # Plots of overlaid exponential growth rates in ww vs hosp - plot_growth_rates <- get_growth_rate_plot(input_hosp_data_wweval, - input_ww_data_wweval, - location, - forecast_date, - rate = "weekly" - ) + save_table( + data_to_save = eta_sd, + type_of_output = "eta_sd", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) + save_table( + data_to_save = inf_feedback, + type_of_output = "inf_feedback", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) - ggsave(plot_growth_rates, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "plot_growth_rates.png" - ), - create.dir = TRUE - ) - hosp_draws <- { - if (!is.null(ww_fit_obj_wwinference$error)) { - NULL - } else { - # Call a function that uses wwinference::get_draws(), joins the - # evaluation data to it, and renames so everything looks the same - # as is expected by downstream wweval functions. - get_model_draws_w_data( - fit_obj_wwinference = ww_fit_obj_wwinference, - model_output = "hosp", - model_type = "ww", - forecast_date = forecast_date, - scenario = scenario, - location = location, - eval_data = eval_hosp_data + eval_ww_data_wweval <- eval_ww_data |> + dplyr::mutate( + "ww" = exp(.data$log_genome_copies_per_ml), + "lod_sewage" = exp(.data$log_lod) + ) |> + dplyr::rename( + "ww_pop" = "site_pop", + "below_LOD" = "below_lod" ) + + # Plots of overlaid exponential growth rates in ww vs hosp + plot_growth_rates <- get_growth_rate_plot(input_hosp_data_wweval, + input_ww_data_wweval, + location, + forecast_date, + rate = "weekly" + ) + + ggsave(plot_growth_rates, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "plot_growth_rates.png" + ), + create.dir = TRUE + ) + + hosp_draws <- { + if (!is.null(ww_fit_obj_wwinference$error)) { + NULL + } else { + # Call a function that uses wwinference::get_draws(), joins the + # evaluation data to it, and renames so everything looks the same + # as is expected by downstream wweval functions. + get_model_draws_w_data( + fit_obj_wwinference = ww_fit_obj_wwinference, + model_output = "hosp", + model_type = "ww", + forecast_date = forecast_date, + scenario = scenario, + location = location, + eval_data = eval_hosp_data + ) + } } - } - save_object("hosp_draws", output_file_suffix) - - ww_draws <- { - if (!is.null(ww_fit_obj_wwinference$error)) { - NULL - } else { - get_model_draws_w_data( - fit_obj_wwinference = ww_fit_obj_wwinference, - model_output = "ww", - model_type = "ww", - forecast_date = forecast_date, - scenario = scenario, - location = location, - eval_data = eval_ww_data - ) + save_object("hosp_draws", output_file_suffix) + + ww_draws <- { + if (!is.null(ww_fit_obj_wwinference$error)) { + NULL + } else { + get_model_draws_w_data( + fit_obj_wwinference = ww_fit_obj_wwinference, + model_output = "ww", + model_type = "ww", + forecast_date = forecast_date, + scenario = scenario, + location = location, + eval_data = eval_ww_data + ) + } } - } - save_object("ww_draws", output_file_suffix) - - full_hosp_quantiles <- { - if (is.null(hosp_draws)) { - NULL - } else { - get_state_level_quantiles( - draws = hosp_draws - ) + save_object("ww_draws", output_file_suffix) + + full_hosp_quantiles <- { + if (is.null(hosp_draws)) { + NULL + } else { + get_state_level_quantiles( + draws = hosp_draws + ) + } } - } - save_object("full_hosp_quantiles", output_file_suffix) + save_object("full_hosp_quantiles", output_file_suffix) - full_ww_quantiles <- { - if (is.null(ww_draws)) { - NULL - } else { - get_state_level_ww_quantiles( - ww_draws = ww_draws - ) + full_ww_quantiles <- { + if (is.null(ww_draws)) { + NULL + } else { + get_state_level_ww_quantiles( + ww_draws = ww_draws + ) + } } - } - save_object("full_ww_quantiles", output_file_suffix) - - hosp_quantiles <- { - if (is.null(full_hosp_quantiles)) { - NULL - } else { - full_hosp_quantiles |> - dplyr::filter(period != "calibration") + save_object("full_ww_quantiles", output_file_suffix) + + hosp_quantiles <- { + if (is.null(full_hosp_quantiles)) { + NULL + } else { + full_hosp_quantiles |> + dplyr::filter(period != "calibration") + } } - } - save_object("hosp_quantiles", output_file_suffix) - - ww_quantiles <- { - if (is.null(full_ww_quantiles)) { - NULL - } else { - full_ww_quantiles |> - dplyr::filter(period != "calibration") + save_object("hosp_quantiles", output_file_suffix) + + ww_quantiles <- { + if (is.null(full_ww_quantiles)) { + NULL + } else { + full_ww_quantiles |> + dplyr::filter(period != "calibration") + } } - } - save_object("ww_quantiles", output_file_suffix) - # Save forecasted quantiles locally as well as via - # targets caching just for backup - save_table( - data_to_save = full_hosp_quantiles, - type_of_output = "hosp_quantiles", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) + save_object("ww_quantiles", output_file_suffix) + # Save forecasted quantiles locally as well as via + # targets caching just for backup + save_table( + data_to_save = full_hosp_quantiles, + type_of_output = "hosp_quantiles", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) - save_table( - data_to_save = full_ww_quantiles, - type_of_output = "ww_quantiles", - output_dir = output_dir, - scenario = scenario, - forecast_date = forecast_date, - model_type = "ww", - location = location - ) + save_table( + data_to_save = full_ww_quantiles, + type_of_output = "ww_quantiles", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) - ### Plot the draw comparison------------------------------------- - plot_hosp_draws <- { - if (is.null(hosp_draws)) { - NULL - } else { - get_plot_hosp_data_comparison( - hosp_draws, - location, - model_type = "ww" - ) + ### Plot the draw comparison------------------------------------- + plot_hosp_draws <- { + if (is.null(hosp_draws)) { + NULL + } else { + get_plot_hosp_data_comparison( + hosp_draws, + location, + model_type = "ww" + ) + } } - } - ggsave(plot_hosp_draws, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "plot_hosp_draws.png" - ), - create.dir = TRUE - ) + ggsave(plot_hosp_draws, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "plot_hosp_draws.png" + ), + create.dir = TRUE + ) - plot_hosp_t <- make_fig2_hosp_t( - hosp_quantiles = full_hosp_quantiles, - loc_to_plot = location, - date_to_plot = forecast_date - ) + - ggtitle(glue::glue("{location} on {forecast_date}")) + - theme_bw() + plot_hosp_t <- make_fig2_hosp_t( + hosp_quantiles = full_hosp_quantiles, + loc_to_plot = location, + date_to_plot = forecast_date + ) + + ggtitle(glue::glue("{location} on {forecast_date}")) + + theme_bw() + + ggsave(plot_hosp_t, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "plot_hosp_t.png" + ), + create.dir = TRUE + ) - ggsave(plot_hosp_t, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "plot_hosp_t.png" - ), - create.dir = TRUE - ) + save_object("plot_hosp_draws", output_file_suffix) - save_object("plot_hosp_draws", output_file_suffix) + # Plots of R(t)s + draws <- wwinference::get_draws(ww_fit_obj_wwinference, what = "all") - # Plots of R(t)s - draws <- wwinference::get_draws(ww_fit_obj_wwinference, what = "all") + plot_state_rt <- wwinference::get_plot_global_rt( + draws$global_rt, + forecast_date + ) + ggsave(plot_state_rt, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "plot_state_rt.png" + ), + create.dir = TRUE + ) - plot_state_rt <- wwinference::get_plot_global_rt( - draws$global_rt, - forecast_date - ) - ggsave(plot_state_rt, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "plot_state_rt.png" - ), - create.dir = TRUE - ) + plot_subpop_rt <- wwinference::get_plot_subpop_rt( + draws$subpop_rt, + forecast_date + ) + ggsave(plot_subpop_rt, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "plot_subpop_rt.png" + ), + create.dir = TRUE + ) - plot_subpop_rt <- wwinference::get_plot_subpop_rt( - draws$subpop_rt, - forecast_date - ) - ggsave(plot_subpop_rt, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", location, - "plot_subpop_rt.png" - ), - create.dir = TRUE - ) + plot_ww_draws <- { + if (is.null(ww_draws)) { + NULL + } else { + get_plot_ww_data_comparison( + ww_draws, + location, + model_type = "ww" + ) + } + } + ggsave(plot_ww_draws, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", + location, "plot_ww_draws.png" + ), + create.dir = TRUE + ) + plot_ww_t <- make_fig2_ct( + full_ww_quantiles, + loc_to_plot = location, + date_to_plot = forecast_date, + max_n_site_labs_to_show = length(unique(full_ww_quantiles$lab_site_index)) + ) + + facet_wrap(~site_lab_name, scales = "free_y") + + ggtitle(glue::glue("{location} on {forecast_date}")) + + theme_bw() + + ggsave(plot_ww_t, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", + location, "plot_ww_t.png" + ), + create.dir = TRUE + ) - plot_ww_draws <- { - if (is.null(ww_draws)) { - NULL - } else { - get_plot_ww_data_comparison( - ww_draws, - location, - model_type = "ww" - ) - } + save_object("plot_ww_draws", output_file_suffix) + + ## Score hospital admissions forecasts---------------------------------- + hosp_scores <- get_full_scores(hosp_draws, scenario) + save_object("hosp_scores", output_file_suffix) + save_table( + data_to_save = hosp_scores, + type_of_output = "scores", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) + hosp_scores_quantiles <- get_scores_from_quantiles(hosp_quantiles, scenario) + save_object("hosp_scores_quantiles", output_file_suffix) + save_table( + data_to_save = hosp_scores_quantiles, + type_of_output = "scores_quantiles", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location + ) } - ggsave(plot_ww_draws, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", - location, "plot_ww_draws.png" - ), - create.dir = TRUE - ) - - plot_ww_t <- make_fig2_ct( - full_ww_quantiles, - loc_to_plot = location, - date_to_plot = forecast_date, - max_n_site_labs_to_show = length(unique(full_ww_quantiles$lab_site_index)) - ) + - facet_wrap(~site_lab_name, scales = "free_y") + - ggtitle(glue::glue("{location} on {forecast_date}")) + - theme_bw() - - ggsave(plot_ww_t, - filename = file.path( - output_dir, scenario, - forecast_date, "ww", - location, "plot_ww_t.png" - ), - create.dir = TRUE + # Things to save even if model run fails + # save the flags alongside the input wastewater data and admissions data + save_table( + data_to_save = ww_data_flags, + type_of_output = "ww_data_flags", + output_dir = output_dir, + scenario = scenario, + forecast_date = forecast_date, + model_type = "ww", + location = location ) - - save_object("plot_ww_draws", output_file_suffix) - - ## Score hospital admissions forecasts---------------------------------- - hosp_scores <- get_full_scores(hosp_draws, scenario) - save_object("hosp_scores", output_file_suffix) save_table( - data_to_save = hosp_scores, - type_of_output = "scores", + data_to_save = input_ww_data_wweval, + type_of_output = "input_ww_data", output_dir = output_dir, scenario = scenario, forecast_date = forecast_date, model_type = "ww", location = location ) - hosp_scores_quantiles <- get_scores_from_quantiles(hosp_quantiles, scenario) - save_object("hosp_scores_quantiles", output_file_suffix) save_table( - data_to_save = hosp_scores_quantiles, - type_of_output = "scores_quantiles", + data_to_save = input_hosp_data_wweval, + type_of_output = "input_hosp_data", output_dir = output_dir, scenario = scenario, forecast_date = forecast_date, model_type = "ww", location = location ) - # Get a subset of samples for plotting - # Get a subset of quantiles for plotting } #' Post Process Hospitalizations Model for Evaluation #' From 8539735afad5073b03c27f177dc2139989adcc07 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 31 Oct 2024 18:40:43 +0000 Subject: [PATCH 005/110] fix handling of model coloring --- wweval/R/ms_fig2.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/ms_fig2.R b/wweval/R/ms_fig2.R index 10da7214..4d098f21 100644 --- a/wweval/R/ms_fig2.R +++ b/wweval/R/ms_fig2.R @@ -161,7 +161,7 @@ make_fig2_ct <- function(ww_quantiles, colors <- plot_components() # Set ribbon and line color for model fit, in this case is always ww model - model_color <- colors$model_colors$ww + model_color <- as.character(colors$model_colors["ww"]) p <- ggplot(quantiles_wide) + geom_point(aes(x = date, y = log(eval_data)), From 8763cf8a3ab65d3a498a64c0e88985e14695c759 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 2 Nov 2024 15:55:00 +0000 Subject: [PATCH 006/110] for now use scoring utils v 1.2.0 --- wweval/DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wweval/DESCRIPTION b/wweval/DESCRIPTION index b10bc6b8..f5d09a85 100644 --- a/wweval/DESCRIPTION +++ b/wweval/DESCRIPTION @@ -90,5 +90,6 @@ Config/Needs/check: rcmdcheck, testthat RoxygenNote: 7.3.2 Remotes: stan-dev/cmdstanr, - wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod + wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod, + scoringutils=epiforecasts/scoringutils@v1.2.0 LazyData: true From 437fd05abe8da50d0dbf3909ff80c7adee55e061 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 5 Nov 2024 16:15:19 +0000 Subject: [PATCH 007/110] fix version of scoringutils" --- wweval/DESCRIPTION | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wweval/DESCRIPTION b/wweval/DESCRIPTION index f5d09a85..e624cb14 100644 --- a/wweval/DESCRIPTION +++ b/wweval/DESCRIPTION @@ -68,7 +68,7 @@ Imports: purrr, scales, soql, - scoringutils, + scoringutils (== 1.2.2), tibble, zoo, cmdstanr (>= 0.7.1), @@ -90,6 +90,5 @@ Config/Needs/check: rcmdcheck, testthat RoxygenNote: 7.3.2 Remotes: stan-dev/cmdstanr, - wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod, - scoringutils=epiforecasts/scoringutils@v1.2.0 + wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod LazyData: true From 4fe7325a942c18286d786e9254a992be23641cad Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 5 Nov 2024 16:16:16 +0000 Subject: [PATCH 008/110] other bug fixes from fix scoringutils branch --- _targets_eval_postprocessing.R | 4 +-- wweval/R/combine_and_summarize_ww_data.R | 8 +++--- wweval/R/combine_outputs.R | 31 ++++++------------------ 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 7d77a5bf..4467d92b 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1470,7 +1470,7 @@ benchmarks <- list( command = plot_benchmarks( grouping_var = "location", benchmark_scope = "all_forecasts", - benchmark_dir = benchmark_config$benchmark_dir, + benchmark_dir = eval_config$benchmark_dir, scores_list = benchmark_table_full_run ) ), @@ -1479,7 +1479,7 @@ benchmarks <- list( command = plot_benchmarks( grouping_var = "forecast_date", benchmark_scope = "all_forecasts", - benchmark_dir = benchmark_config$benchmark_dir, + benchmark_dir = eval_config$benchmark_dir, scores_list = benchmark_table_full_run ) ) diff --git a/wweval/R/combine_and_summarize_ww_data.R b/wweval/R/combine_and_summarize_ww_data.R index a8b472b3..e07325d7 100644 --- a/wweval/R/combine_and_summarize_ww_data.R +++ b/wweval/R/combine_and_summarize_ww_data.R @@ -67,12 +67,12 @@ combine_and_summarize_ww_data <- function(forecast_dates, ww_metadata <- rbind(ww_metadata, this_ww_metadata) } else { warning(glue::glue( - "File missing for {this_scenario}", + "File missing ", "in {this_location} on {this_forecast_date}" )) # Create a tibble of the combos that are missing, to save this_failed_output <- tibble( - scenario = this_scenario, + scenario = "status_quo", location = this_location, forecast_date = this_forecast_date ) @@ -84,13 +84,13 @@ combine_and_summarize_ww_data <- function(forecast_dates, # Save the missing files in a new subfolder in the eval_output_subdir wwinference::create_dir(file.path( eval_output_subdir, - "files_missing", model_type + "files_missing", "ww" )) readr::write_csv( flag_failed_output, file.path( - eval_output_subdir, "files_missing", model_type, + eval_output_subdir, "files_missing", "ww", "ww_data_metadata.csv" ) ) diff --git a/wweval/R/combine_outputs.R b/wweval/R/combine_outputs.R index 5d38616e..04c7fbaf 100644 --- a/wweval/R/combine_outputs.R +++ b/wweval/R/combine_outputs.R @@ -70,32 +70,17 @@ combine_outputs <- function(output_type = ) } else { warning(glue::glue( - "File missing for {this_scenario}", + "File missing for {this_scenario} ", "in {this_location} on {this_forecast_date}" )) - # Check that input data is present: - if (this_scenario == "status_quo") { - fp_ww_data <- get_filepath( - eval_output_subdir, - this_scenario, - this_forecast_date, - model_type, - this_location, - glue::glue("input_ww_data"), - "tsv" - ) - ww_data <- readr::read_tsv(fp_ww_data) - if (nrow(ww_data) != 0) { - # Create a tibble of the combos that are missing, to save - this_failed_output <- tibble( - scenario = this_scenario, - location = this_location, - forecast_date = this_forecast_date - ) - flag_failed_output <- rbind(flag_failed_output, this_failed_output) - } - } # end check for ww data + # Create a tibble of the combos that are missing, to save + this_failed_output <- tibble( + scenario = this_scenario, + location = this_location, + forecast_date = this_forecast_date + ) + flag_failed_output <- rbind(flag_failed_output, this_failed_output) } # end if file missing } From 6cf0c41a4fc697785bc017c7af54a1698c0c7419 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 5 Nov 2024 16:39:51 +0000 Subject: [PATCH 009/110] fix desc, remove from imports? --- wweval/DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wweval/DESCRIPTION b/wweval/DESCRIPTION index e624cb14..e9d9760a 100644 --- a/wweval/DESCRIPTION +++ b/wweval/DESCRIPTION @@ -68,7 +68,6 @@ Imports: purrr, scales, soql, - scoringutils (== 1.2.2), tibble, zoo, cmdstanr (>= 0.7.1), @@ -90,5 +89,6 @@ Config/Needs/check: rcmdcheck, testthat RoxygenNote: 7.3.2 Remotes: stan-dev/cmdstanr, - wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod + wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod, + scoringutils=epiforecasts/scoringutils@v1.2.2 LazyData: true From 16083533c781e26bf67506b66701c08bac18f731 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 5 Nov 2024 17:47:13 +0000 Subject: [PATCH 010/110] get a scoringutils version that works in container --- wweval/DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wweval/DESCRIPTION b/wweval/DESCRIPTION index e9d9760a..a3d4a9da 100644 --- a/wweval/DESCRIPTION +++ b/wweval/DESCRIPTION @@ -78,6 +78,7 @@ Imports: RColorBrewer, zoltr, wwinference, + scoringutils (>= 1.2.2), fs Suggests: httr, @@ -90,5 +91,5 @@ RoxygenNote: 7.3.2 Remotes: stan-dev/cmdstanr, wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod, - scoringutils=epiforecasts/scoringutils@v1.2.2 + github::epiforecasts/scoringutils@v1.2.2 LazyData: true From 2a70b2b69a5142c1a240d8cf1d7aab41c9e20f20 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 5 Nov 2024 19:53:16 +0000 Subject: [PATCH 011/110] attempt to fix get draws from ww data and ww eval data --- wweval/R/post_processing.R | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/wweval/R/post_processing.R b/wweval/R/post_processing.R index 55f3a757..351da5fb 100644 --- a/wweval/R/post_processing.R +++ b/wweval/R/post_processing.R @@ -69,12 +69,18 @@ get_model_draws_w_data <- function(fit_obj_wwinference, draws_w_data <- new_ww_draws |> dplyr::left_join( eval_data |> + dplyr::rename( + "below_lod_eval" = "below_lod", + "log_lod_eval" = "log_lod" + ) |> dplyr::select( "date", "log_genome_copies_per_ml", "lab", "site", - "exclude" + "exclude", + "below_lod_eval", + "log_lod_eval" ) |> unique(), by = c("date", "lab", "site") @@ -91,6 +97,7 @@ get_model_draws_w_data <- function(fit_obj_wwinference, "calib_data" = exp(.data$observed_value), "eval_data" = exp(.data$log_genome_copies_per_ml), "lod_sewage" = exp(.data$log_lod), + "lod_sewage_eval" = exp(.data$log_lod_eval), "forecast_date" = lubridate::ymd(!!forecast_date), "model_type" = !!model_type, "scenario" = !!scenario, @@ -100,7 +107,7 @@ get_model_draws_w_data <- function(fit_obj_wwinference, # Replace values below LOD with LOD in observations dplyr::mutate( "eval_data" = ifelse( - .data$below_LOD == 1, .data$lod_sewage, .data$eval_data + .data$below_lod_eval == 1, .data$lod_sewage_eval, .data$eval_data ), "calib_data" = ifelse( .data$below_LOD == 1, .data$lod_sewage, .data$eval_data @@ -109,6 +116,7 @@ get_model_draws_w_data <- function(fit_obj_wwinference, dplyr::select( "name", "lab_site_index", "value", "draw", "date", "site", "lab", "location", "ww_pop", "calib_data", "below_LOD", "lod_sewage", + "below_lod_eval", "flag_as_ww_outlier", "eval_data", "forecast_date", "model_type", "scenario", "site_lab_name" ) From ddd13715339592a6c35a7efabbbb6047ae5a0e9f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 5 Nov 2024 22:46:31 +0000 Subject: [PATCH 012/110] fix to put extra cols after scoring just in case --- wweval/R/score.R | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/wweval/R/score.R b/wweval/R/score.R index 69b6b175..476e9af2 100644 --- a/wweval/R/score.R +++ b/wweval/R/score.R @@ -44,12 +44,7 @@ get_full_scores <- function(draws, prediction, sample, model - ) |> - mutate( - period = ifelse(date <= forecast_date, "nowcast", "forecast"), - scenario = !!scenario ) - scores <- forecasted_draws |> data.table::as.data.table() |> scoringutils::transform_forecasts( @@ -57,7 +52,11 @@ get_full_scores <- function(draws, offset = 1 ) |> scoringutils::check_forecasts() |> - scoringutils::score(metrics = metrics) + scoringutils::score(metrics = metrics) |> + mutate( + period = ifelse(date <= forecast_date, "nowcast", "forecast"), + scenario = !!scenario + ) } @@ -105,10 +104,6 @@ get_scores_from_quantiles <- function(quantiles, prediction, quantile, model - ) |> - mutate( - period = ifelse(date <= forecast_date, "nowcast", "forecast"), - scenario = !!scenario ) @@ -119,7 +114,11 @@ get_scores_from_quantiles <- function(quantiles, offset = 1 ) |> scoringutils::check_forecasts() |> - scoringutils::score(metrics = metrics) + scoringutils::score(metrics = metrics) |> + mutate( + period = ifelse(date <= forecast_date, "nowcast", "forecast"), + scenario = !!scenario + ) } return(scores) } From e9bf12511fb4caedba9880bac7358a2cc2731497 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 6 Nov 2024 03:43:24 +0000 Subject: [PATCH 013/110] add benchmarks --- .../all_forecasts_by_forecast_date.tsv | 42 ++++-- .../all_forecasts_by_location.tsv | 125 +++++++++++++----- .../latest_all_forecasts_by_forecast_date.tsv | 44 +++--- .../latest_all_forecasts_by_location.tsv | 106 +++++++-------- .../plots/all_forecasts_by_forecast_date.png | Bin 0 -> 142344 bytes .../plots/all_forecasts_by_location.png | Bin 0 -> 228975 bytes .../plots/all_forecasts_overall.png | Bin 0 -> 70372 bytes 7 files changed, 196 insertions(+), 121 deletions(-) create mode 100644 output/benchmarking/plots/all_forecasts_by_forecast_date.png create mode 100644 output/benchmarking/plots/all_forecasts_by_location.png create mode 100644 output/benchmarking/plots/all_forecasts_overall.png diff --git a/output/benchmarking/all_forecasts_by_forecast_date.tsv b/output/benchmarking/all_forecasts_by_forecast_date.tsv index d3f05e55..3f164313 100644 --- a/output/benchmarking/all_forecasts_by_forecast_date.tsv +++ b/output/benchmarking/all_forecasts_by_forecast_date.tsv @@ -1,23 +1,45 @@ forecast_date crps_hosp crps_ww bias_hosp bias_ww ae_hosp ae_ww wweval_commit_hash wwinference_version time_stamp -2023-10-16 4.256933535461482 4.677370441094627 -0.020467990890688254 -0.10726857585139318 5.895361948275802 6.40167764415396 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-10-16 5.059832198025414 4.501664311215313 -0.0763335020242915 -0.056744279176201375 7.196846342932589 6.417293680713388 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-10-23 4.18242235006235 4.413074319173952 -0.11766093117408907 -0.11811315789473684 5.872168190751324 5.918167022644099 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-10-30 3.9219506958608275 3.5210321563246176 -0.1053626012145749 -0.08041593567251462 5.393236641297567 4.556872909525013 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-06 5.255322819720833 4.242950709531141 -0.2441136133603239 -0.20688696172248805 7.414134578598956 6.0135603392186425 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-13 7.012799991126642 4.998084614217982 -0.5118594382591093 -0.46080248205741625 9.64599332435846 6.824715861342708 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-20 6.690375498626213 4.569349653386474 -0.41770723684210526 -0.30216682330827066 9.214825658027166 6.337797225183365 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-27 5.367627142174053 5.031212394265873 -0.26671799089068826 -0.24200260097919216 7.5482110987083395 7.068444939700455 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-04 6.764647750371329 7.420530433101996 -0.31960437753036436 -0.3100663875598086 9.440455766083506 10.504710217364053 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-11 6.8594860507920785 5.4574081640829295 -0.16721419534412957 -0.17022117794486216 9.55203634898675 7.785618001707871 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-18 8.358376515160765 6.455104681756234 -0.12688347672064776 -0.17103555764411027 11.198803534577065 8.875209211526409 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-25 6.894327278046133 7.758221090506614 -0.10081376518218624 -0.013425675675675677 9.34975699525672 10.585508784012148 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-01 10.31738321239008 7.901786950597124 0.2344056174089069 0.1605827067669173 14.418033531994073 10.919645060776363 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-08 28.7932922854294 23.31310760445013 0.6610759109311741 0.7008788088642659 37.046751992777224 30.793527506859903 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-15 19.445812351084225 16.387511402770986 0.7812803643724696 0.7319326923076923 25.995676615059736 22.008691829376154 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-22 8.951908471135088 6.350654896121348 0.600787955465587 0.4347277327935223 12.903170731444915 8.784297320600754 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-29 5.099562638508678 6.354915264254163 0.08971103238866397 0.09217830634278003 7.255509012912055 8.999088732619368 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-05 5.1731132957947406 6.678920578971974 -0.14593003542510122 -0.029273355263157892 7.087254525265564 9.716560898845575 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-12 11.222311326853164 11.951289868227024 -0.070354504048583 0.02381831983805668 14.188932611966608 14.992837778794046 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-19 7.663909447407364 7.6769418153113 0.3177726467611336 0.3024981203007519 10.733195134321834 10.273287233821865 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-26 4.921266785280591 5.603520805103531 0.29640599696356273 0.3353181390977444 7.022260884531381 8.071790643313324 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-03-04 4.233753799775528 4.364753819915278 0.369924721659919 0.34656012851897183 5.919483809471711 6.114155205887852 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-03-11 3.357096806226528 3.3860785699505214 0.2889935475708502 0.14207775119617225 4.575087973170657 4.692928674471748 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-10-16 4.256933535461482 4.677370441094627 -0.02046799089068825 -0.10726857585139318 5.895361948275802 6.40167764415396 d23b28a v0.1.0 2024-10-24T17:48:45Z 2023-10-23 4.047315226528276 4.631789914889093 -0.09872773279352226 -0.16621130030959752 5.610628735112493 6.210695845766179 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-10-30 4.100770029594852 4.379587942220779 -0.14525657894736843 -0.19440208978328175 5.544465252465204 5.941233543544665 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-10-30 4.100770029594852 4.379587942220779 -0.14525657894736843 -0.19440208978328177 5.544465252465204 5.941233543544665 d23b28a v0.1.0 2024-10-24T17:48:45Z 2023-11-06 5.255407521988535 5.932679027358801 -0.29768509615384614 -0.29097226522187825 6.975464949424841 7.864106878051551 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-13 6.946577503431648 6.936479202826244 -0.4860530111336032 -0.49226186790505677 8.943972972771006 9.221247117807152 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-20 7.759903401522265 5.902333740557295 -0.49563879048583 -0.419578044375645 9.916515197242543 8.0139594342945 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-27 7.640750277248922 7.255636035039714 -0.5068352732793522 -0.42566498968008254 10.198548996354523 9.726490371356666 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-12-04 9.021347319079029 9.072298721634764 -0.5661029858299595 -0.5088498452012384 11.773734392455939 11.600043600429995 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-11-13 6.946577503431648 6.936479202826244 -0.4860530111336032 -0.4922618679050568 8.943972972771006 9.221247117807152 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-11-20 7.759903401522265 5.902333740557295 -0.49563879048583 -0.419578044375645 9.916515197242544 8.0139594342945 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-11-27 7.640750277248922 7.255636035039714 -0.5068352732793522 -0.42566498968008254 10.198548996354525 9.726490371356666 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-12-04 9.021347319079029 9.072298721634764 -0.5661029858299595 -0.5088498452012384 11.77373439245594 11.600043600429997 d23b28a v0.1.0 2024-10-24T17:48:45Z 2023-12-11 8.417316895980093 8.542035707872587 -0.45781313259109313 -0.42599513157894736 10.822920070978173 11.027416678451043 d23b28a v0.1.0 2024-10-24T17:48:45Z 2023-12-18 8.815867884856738 8.349023201732756 -0.36597988360323885 -0.37057855263157896 11.373181687982749 10.851875301875848 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-12-25 7.789253128499376 7.969011598093365 -0.27195976720647774 -0.20117733253588518 10.43430440859026 10.966165282778 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-01 7.592317000509569 6.536994643195594 0.03862095141700405 -0.025541353383458646 10.37069031741096 9.032050896441008 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-12-25 7.789253128499376 7.969011598093365 -0.27195976720647774 -0.2011773325358852 10.43430440859026 10.966165282778 d23b28a v0.1.0 2024-10-24T17:48:45Z +2024-01-01 7.592317000509569 6.536994643195594 0.03862095141700405 -0.02554135338345864 10.37069031741096 9.032050896441008 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-01-08 15.72873971884139 17.34649853791809 0.5114973431174089 0.5977302631578947 20.23980158633673 22.760906397690366 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-01-15 16.8368764606006 16.16988800060564 0.7335118927125506 0.7420599581339713 21.470723001323357 21.324997246737848 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-22 12.578120503174347 8.591867733854587 0.752081983805668 0.5869108187134503 16.745523991865298 11.962299845196963 d23b28a v0.1.0 2024-10-24T17:48:45Z +2024-01-22 12.578120503174349 8.591867733854587 0.752081983805668 0.5869108187134503 16.745523991865298 11.962299845196965 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-01-29 6.250229873276504 5.597408510283156 0.46447431680161944 0.3517020035885168 8.897102295171909 7.708389135822814 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-02-05 4.573424286089247 5.8253084042799985 0.12928175607287448 0.12520877192982455 6.391327797333847 7.939784670173955 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-02-12 4.104713553309723 6.313650246216045 0.11586000504032258 0.16542651255707763 5.819277416265341 8.622847250097367 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-02-19 6.860996913410704 7.869580159555713 0.3967626518218623 0.41254633258678614 9.385290651710555 10.540015575926462 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-02-26 5.701146824066562 7.33035510471486 0.4148002277327935 0.44525109649122807 7.9176729122140515 9.904555497601788 d23b28a v0.1.0 2024-10-24T17:48:45Z 2024-03-04 5.112789339042601 4.854152444626718 0.5130581983805668 0.4640028195488722 7.123287289921584 6.752411039873908 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-03-11 4.312835875935859 4.263065993475463 0.48293927125506075 0.3586044575725027 5.945585926634464 5.904156153397102 d23b28a v0.1.0 2024-10-24T17:48:45Z +2024-03-11 4.312835875935859 4.263065993475463 0.4829392712550607 0.3586044575725027 5.945585926634464 5.904156153397102 d23b28a v0.1.0 2024-10-24T17:48:45Z diff --git a/output/benchmarking/all_forecasts_by_location.tsv b/output/benchmarking/all_forecasts_by_location.tsv index a0b2832c..1e84d047 100644 --- a/output/benchmarking/all_forecasts_by_location.tsv +++ b/output/benchmarking/all_forecasts_by_location.tsv @@ -1,54 +1,107 @@ crps_hosp crps_ww bias_hosp bias_ww ae_hosp ae_ww location wweval_commit_hash wwinference_version time_stamp -1.0245932139677376 0.9913943382419593 -0.044675239234449764 -0.013038533834586467 1.4025499429326875 1.3650619629241825 AK d23b28a v0.1.0 2024-10-24T17:48:45Z +0.965387517442082 0.9356726549249403 -0.053803827751196166 -0.021681077694235586 1.3360690132743076 1.2971384472121235 AK 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +6.955739115298207 6.621319048559378 0.03897458133971292 0.0032456140350877152 9.783588779351387 9.344950063891512 AL 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.612949724477276 4.619899220775841 0.03404455741626795 0.06411812200956939 6.559294184742686 6.602107248445021 AR 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +6.139491770368693 6.2294582093970625 0.10818361244019138 0.18072816985645934 8.477386434918628 8.90310180752627 AZ 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +26.588534494916185 20.52040185556402 0.036293959330143545 -0.08157236842105263 37.30597767922585 28.48679419035798 CA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.0413080897736355 10.578064436431587 0.16108163875598086 0.07897631578947369 5.527137857761504 14.848360021470164 CO 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.015535369939763 5.0323365479988516 0.08661094497607656 0.11052272727272727 7.138672143335744 7.10257825825303 CT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.6398772474245782 1.537739218782322 0.03179156698564593 0.05669047619047619 2.3306428485950876 2.18006215101481 DC 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.8881972653043033 2.009117820817491 4.542464114832541e-4 0.03101691729323308 2.688161115244514 2.8139975492671847 DE 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +20.409297283433713 21.411315454487955 0.010642045454545456 0.0535921052631579 27.753851511910412 29.656633261469594 FL 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +15.905086019860233 14.927301179716123 0.02460944976076555 -0.02692042606516291 20.98441795749843 20.00012173843837 GA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.5552575174479188 1.5088897987051066 0.05280861244019139 0.060201127819548866 2.1794515505434604 2.076243353575278 HI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.717988564081217 4.50716558687924 -0.023177631578947363 -0.031551065162907274 6.459058358087138 6.203020208058825 IA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.664940427832129 2.6566164279440403 0.042231758373205745 0.05031429425837321 3.733885551762075 3.700885566935998 ID 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +15.66057551045102 26.563097854729186 0.05806997607655502 -0.9375964912280702 21.27280670343953 31.358615276374085 IL 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +11.804864260060622 9.292179707944472 0.1272903708133971 0.1593643483709273 16.103834361264273 12.155042953551764 IN 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.347825543314189 4.504948667657593 0.04685137559808612 0.04460974880382775 7.364884245020363 6.2397348261921 KS 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.909986697820656 5.533975988383646 -0.037652511961722486 0.6098421052631579 8.242839796436954 7.92432457450872 KY 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.909872993043222 3.9546312090926263 0.026304126794258375 -0.056122180451127816 7.00728123043053 5.762924665213887 LA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +11.737793357804062 10.226645165347154 0.18520873205741625 0.1803444976076555 15.977060923470379 13.965975170613289 MA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.21720610825874 5.302346105006481 0.022237141148325357 -0.008757177033492821 7.215859234306069 7.389007646648587 MD 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.6927457058276585 2.2588326160857846 0.036038277511961724 0.020204844497607656 3.8014047967180864 3.159837377035527 ME 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +14.730706891862104 22.7346423869701 -0.00844527511961723 0.7762631578947369 19.775809588058262 32.4709334824226 MI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.5302501738480165 15.112816373858022 0.024498504784688995 0.22898444976076557 7.547259761194644 20.279988949964995 MN 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +8.365791299143524 13.745538982597983 0.04102870813397129 -0.8615526315789473 11.647575781640057 17.699665482164928 MO 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.094162816472101 1.8973368741099579 0.014612141148325361 -0.3552078947368421 4.336421750902773 2.7830031494391134 MS 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.9599915333073132 1.9340943128178083 0.13829874401913875 0.09470238095238095 2.7431841632257683 2.695341283672515 MT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +8.742957676170628 9.41927742439938 0.021450956937799047 -0.006226562499999999 12.277549583611107 13.417373890415512 NC 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.2464157487377392 1.357870439694969 -0.07386154306220095 -0.2867447368421053 1.7346142614637663 1.8928829213958465 ND 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.6357708711269816 2.839546417942367 0.04913636363636364 0.10299461722488039 4.953808551539756 3.922232148443104 NE 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.2669651414052194 1.7423114838769374 0.011480562200956938 0.021594924812030073 3.1795950502230994 2.3966686186792816 NH 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +17.06495420067773 17.19952298890777 0.031207236842105263 0.02376106459330144 22.855018957302537 23.34979932568371 NJ 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.1114299268361734 2.003735102983464 0.05469736842105263 -0.039611019736842105 3.0073539794767554 2.8496542102035103 NM 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.445907816827532 2.603543511346354 -0.006664772727272728 0.018771531100478474 3.4919845652806667 3.686297298603071 NV 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +34.57766162002901 41.90428292784995 0.16256638755980862 0.2363684210526316 46.07384681680061 57.84859954209488 NY 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +17.11437871070843 26.663026055456843 0.009475179425837326 -0.9665921052631579 22.604039491972145 31.88850472623202 OH 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.975513723952207 4.685327690161878 0.07737948564593301 0.010185776942355887 7.092988058603186 6.6906360304346935 OK 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.2171984675312135 3.369291487721138 0.06290311004784689 0.10623534688995215 4.519335330589072 4.669746336730518 OR 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +21.143742672067187 18.96291755229285 0.14407147129186604 0.2945824561403509 27.958592258938772 25.645788714340473 PA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.6231257848944445 1.6029227660673095 0.17208522727272726 0.062144736842105266 4.983246210872801 2.171304143131584 PR 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.0036672725762763 1.7179351261692153 0.05545334928229665 0.060870514354066985 2.800240973911771 2.4016625334694717 RI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +6.299021651012965 6.44809830333831 -0.01875328947368421 0.045721177944862156 8.662279654460365 8.832640038919886 SC 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.5751364208218028 1.3630394938537413 0.04307505980861244 -0.09958808479532164 2.238577274679975 1.922608727311533 SD 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +8.50070363039982 8.496821218598857 -0.16921501196172248 -0.172252990430622 11.776124960369364 11.7773945748676 TN 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +44.38266193151503 52.13365436007212 0.17992793062200957 0.2682763157894737 58.31509334625342 68.35251694821251 TX 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.587089810259867 4.5789768812919585 0.02096172248803828 0.10678665413533835 3.5881706456749685 6.07099624798896 UT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +9.627103026017702 11.31885461995276 -0.0789659090909091 0.1479705513784461 13.149021877415093 15.535837157886133 VA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +0.9516676633744922 0.8638913394393114 0.03298056220095694 -0.08378148496240602 1.3508945843452176 1.2269036929560833 VT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.9688201351008816 6.3304501571561005 0.085876495215311 0.1224997009569378 5.552191578829858 8.765664845256408 WA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +7.698080478940572 5.996855465245554 0.10312739234449761 0.08111214114832536 10.341592698765059 8.121253437267779 WI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.10695469423953 4.0194445022588665 -0.037249401913875595 -0.0666238038277512 5.621040224639752 5.476177490096456 WV 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +0.9999845765227394 0.9554595452207291 0.1340278110047847 0.045077694235588966 1.4214779111537204 1.3693813585099321 WY 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +7.97938994135691 7.007810007322375 0.04408191479573058 0.03812017543859647 10.862355695567917 9.577604930147658 all 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:21Z +1.0245932139677376 0.9913943382419592 -0.04467523923444976 -0.01303853383458646 1.4025499429326875 1.3650619629241825 AK d23b28a v0.1.0 2024-10-24T17:48:45Z 6.2973367913173295 6.192682400370224 -0.03878678229665072 -0.06537312030075189 8.489186903031504 8.333960689048661 AL d23b28a v0.1.0 2024-10-24T17:48:45Z -3.9911150596101774 4.036037220576845 -0.012324162679425835 -0.0019174641148325348 5.487570048714099 5.5851838339781565 AR d23b28a v0.1.0 2024-10-24T17:48:45Z -5.494061035228348 6.253645689179519 0.12577212918660285 0.14063785885167462 7.692517734681003 8.650969083257658 AZ d23b28a v0.1.0 2024-10-24T17:48:45Z -28.27066280033458 21.93607622181548 0.02693450956937799 0.0046024436090225575 38.41093608479694 30.12777787819662 CA d23b28a v0.1.0 2024-10-24T17:48:45Z -4.266355755551796 5.507450335072049 0.2278758971291866 0.060432117224880386 5.808582812739105 7.449730504624001 CO d23b28a v0.1.0 2024-10-24T17:48:45Z +3.9911150596101774 4.036037220576845 -0.01232416267942583 -0.00191746411483253 5.487570048714099 5.5851838339781565 AR d23b28a v0.1.0 2024-10-24T17:48:45Z +5.494061035228348 6.253645689179519 0.12577212918660283 0.14063785885167462 7.692517734681003 8.650969083257658 AZ d23b28a v0.1.0 2024-10-24T17:48:45Z +28.27066280033458 21.93607622181548 0.02693450956937799 0.00460244360902255 38.41093608479694 30.12777787819662 CA d23b28a v0.1.0 2024-10-24T17:48:45Z +4.266355755551796 5.507450335072049 0.2278758971291866 0.06043211722488038 5.808582812739105 7.449730504624001 CO d23b28a v0.1.0 2024-10-24T17:48:45Z 5.675809214558925 5.590328180506943 0.09745394736842106 0.11458223684210526 7.895203593005671 7.776350350413904 CT d23b28a v0.1.0 2024-10-24T17:48:45Z -1.6341339983615357 1.595556000322384 0.1160005980861244 0.11490444862155388 2.2780983791627385 2.2276453664725517 DC d23b28a v0.1.0 2024-10-24T17:48:45Z -1.647896164765979 1.7576311317190145 0.005867523923444978 0.03555795739348371 2.3081115320095456 2.4397121106311683 DE d23b28a v0.1.0 2024-10-24T17:48:45Z -20.9745847035626 21.309299258022506 0.01895813397129186 0.08765288220551379 27.35031504551748 27.843829233436576 FL d23b28a v0.1.0 2024-10-24T17:48:45Z -14.246079346033854 13.784749176480657 -0.037579545454545456 -0.08648026315789474 18.26668590947028 17.62468400771157 GA d23b28a v0.1.0 2024-10-24T17:48:45Z -1.2685291989675689 1.2772794395553102 0.09037769138755981 0.07232581453634085 1.7818926731226852 1.7989016009979328 HI d23b28a v0.1.0 2024-10-24T17:48:45Z -5.1947667172122 4.919456006863106 -0.027432715311004784 -0.05068013784461153 6.616923506647085 6.272865371617346 IA d23b28a v0.1.0 2024-10-24T17:48:45Z -2.6917584717827103 2.70666632435346 0.059654007177033494 0.04381668660287081 3.7033527451393238 3.731358045069099 ID d23b28a v0.1.0 2024-10-24T17:48:45Z +1.6341339983615355 1.595556000322384 0.1160005980861244 0.11490444862155388 2.2780983791627385 2.2276453664725517 DC d23b28a v0.1.0 2024-10-24T17:48:45Z +1.647896164765979 1.7576311317190143 0.00586752392344497 0.03555795739348371 2.3081115320095456 2.4397121106311683 DE d23b28a v0.1.0 2024-10-24T17:48:45Z +20.9745847035626 21.309299258022502 0.01895813397129186 0.08765288220551379 27.35031504551748 27.843829233436576 FL d23b28a v0.1.0 2024-10-24T17:48:45Z +14.246079346033854 13.784749176480656 -0.03757954545454545 -0.08648026315789474 18.26668590947028 17.62468400771157 GA d23b28a v0.1.0 2024-10-24T17:48:45Z +1.2685291989675689 1.2772794395553102 0.0903776913875598 0.07232581453634085 1.7818926731226852 1.7989016009979328 HI d23b28a v0.1.0 2024-10-24T17:48:45Z +5.1947667172122 4.919456006863106 -0.02743271531100478 -0.05068013784461153 6.616923506647085 6.272865371617346 IA d23b28a v0.1.0 2024-10-24T17:48:45Z +2.6917584717827103 2.70666632435346 0.05965400717703349 0.04381668660287081 3.703352745139324 3.731358045069099 ID d23b28a v0.1.0 2024-10-24T17:48:45Z 16.51234888964669 15.029437072559894 -0.03727870813397129 -0.06539285714285714 21.786801323502324 19.61566035834812 IL d23b28a v0.1.0 2024-10-24T17:48:45Z -11.319234959606781 8.950594053434703 0.06199013157894737 0.047455827067669175 14.736819644395094 12.131902102353887 IN d23b28a v0.1.0 2024-10-24T17:48:45Z +11.31923495960678 8.950594053434703 0.06199013157894737 0.04745582706766917 14.736819644395094 12.131902102353887 IN d23b28a v0.1.0 2024-10-24T17:48:45Z 4.735709974474379 4.554763806661009 -0.03907894736842106 -0.05304336124401914 6.411162273432199 6.167865764567813 KS d23b28a v0.1.0 2024-10-24T17:48:45Z 6.087160684773657 5.213338501028242 -0.0848761961722488 0.6152675438596491 8.178993007078178 7.3132276990773795 KY d23b28a v0.1.0 2024-10-24T17:48:45Z 4.654039580040471 4.631081722074162 -0.04461034688995215 -0.09320526315789474 6.188500968146125 6.037647236309703 LA d23b28a v0.1.0 2024-10-24T17:48:45Z 11.702569548366563 10.800529123616966 0.18111124401913875 0.18163247607655503 15.321982133176324 14.33645741171139 MA d23b28a v0.1.0 2024-10-24T17:48:45Z 5.581192194841542 5.4806076066391265 0.04022846889952153 0.02348116028708134 7.527718152191338 7.397348248046321 MD d23b28a v0.1.0 2024-10-24T17:48:45Z -2.2107845326906364 2.075052461675859 0.13745035885167464 0.09685915071770335 3.1323245237045456 2.915724435431815 ME d23b28a v0.1.0 2024-10-24T17:48:45Z -13.95259850433921 11.763482001828006 -0.010866028708133975 -0.2632308897243108 18.058074388540586 16.529310467094348 MI d23b28a v0.1.0 2024-10-24T17:48:45Z -5.697391398241083 7.929183975619169 0.005695873205741621 0.12297188995215311 7.51087871508186 10.01770980745194 MN d23b28a v0.1.0 2024-10-24T17:48:45Z -8.532446104557419 12.62858140431652 -0.0017233851674641088 -0.06963931888544891 11.392358847422608 16.576228782735367 MO d23b28a v0.1.0 2024-10-24T17:48:45Z +2.2107845326906364 2.075052461675859 0.13745035885167464 0.09685915071770336 3.1323245237045456 2.915724435431815 ME d23b28a v0.1.0 2024-10-24T17:48:45Z +13.95259850433921 11.763482001828006 -0.01086602870813397 -0.2632308897243108 18.058074388540582 16.529310467094348 MI d23b28a v0.1.0 2024-10-24T17:48:45Z +5.697391398241083 7.929183975619169 0.00569587320574162 0.12297188995215312 7.51087871508186 10.01770980745194 MN d23b28a v0.1.0 2024-10-24T17:48:45Z +8.532446104557419 12.62858140431652 -0.0017233851674641 -0.06963931888544891 11.392358847422608 16.576228782735367 MO d23b28a v0.1.0 2024-10-24T17:48:45Z 2.868227438723672 2.3542130355847326 -0.0683444976076555 -0.5116828947368421 3.960336219102815 3.268465707668931 MS d23b28a v0.1.0 2024-10-24T17:48:45Z 1.8092339977929996 1.792138173886483 0.17317703349282296 0.15372556390977443 2.5598288304241064 2.522808654100039 MT d23b28a v0.1.0 2024-10-24T17:48:45Z -8.56352270755409 8.173334830161215 0.03532775119617225 0.035106829573934836 11.522226294413143 11.01439335027247 NC d23b28a v0.1.0 2024-10-24T17:48:45Z +8.56352270755409 8.173334830161215 0.03532775119617225 0.03510682957393483 11.522226294413144 11.01439335027247 NC d23b28a v0.1.0 2024-10-24T17:48:45Z 1.3607549940255612 1.5212783546471602 -0.07146561004784689 -0.4997717105263158 1.901082803729751 2.148158013958308 ND d23b28a v0.1.0 2024-10-24T17:48:45Z -3.489447911677376 2.896524173913666 -0.03079665071770335 0.023639354066985648 4.695626730946361 4.001703638214006 NE d23b28a v0.1.0 2024-10-24T17:48:45Z -2.185794837646797 1.8622396768839506 0.12105263157894737 0.09318859649122807 2.985529977657489 2.551918529223364 NH d23b28a v0.1.0 2024-10-24T17:48:45Z -15.898477720284601 15.526196598773701 0.08451824162679426 0.04625448564593301 20.6630021710342 20.091412606142235 NJ d23b28a v0.1.0 2024-10-24T17:48:45Z +3.489447911677376 2.896524173913666 -0.03079665071770335 0.02363935406698564 4.695626730946361 4.001703638214006 NE d23b28a v0.1.0 2024-10-24T17:48:45Z +2.185794837646797 1.8622396768839504 0.12105263157894736 0.09318859649122808 2.985529977657489 2.551918529223364 NH d23b28a v0.1.0 2024-10-24T17:48:45Z +15.8984777202846 15.5261965987737 0.08451824162679426 0.04625448564593301 20.6630021710342 20.091412606142235 NJ d23b28a v0.1.0 2024-10-24T17:48:45Z 2.379615471089599 2.261852214376928 0.08282984449760766 -0.108296875 3.317826151516665 3.132459090770379 NM d23b28a v0.1.0 2024-10-24T17:48:45Z -2.639337400936249 2.6900817287758234 0.00816357655502392 0.03644856459330144 3.7205706795144837 3.7986365057389593 NV d23b28a v0.1.0 2024-10-24T17:48:45Z -33.50388186046625 27.965268896899595 0.15547936602870813 -0.19675125313283207 43.62716897356692 37.73553975322001 NY d23b28a v0.1.0 2024-10-24T17:48:45Z -17.92110361325814 20.682296331103714 -0.007233552631578952 -0.07412844611528822 22.73899187850074 26.30850592777131 OH d23b28a v0.1.0 2024-10-24T17:48:45Z -4.902521345457254 4.713615245694379 0.033268540669856454 -0.01424436090225564 6.677019032072608 6.4477458197554425 OK d23b28a v0.1.0 2024-10-24T17:48:45Z -2.9364761351762785 2.8950224905470154 0.18295065789473683 0.16356549043062202 4.156916282564877 4.056688790333076 OR d23b28a v0.1.0 2024-10-24T17:48:45Z -17.50366417275519 15.606524932718033 0.1030933014354067 0.1038438995215311 23.02121631799656 21.028808194233758 PA d23b28a v0.1.0 2024-10-24T17:48:45Z -3.093392245788411 1.2663025455539536 0.08266058612440191 -0.004555098684210526 4.14732349142619 1.725527009546006 PR d23b28a v0.1.0 2024-10-24T17:48:45Z +2.639337400936249 2.6900817287758234 0.00816357655502392 0.03644856459330144 3.720570679514484 3.7986365057389593 NV d23b28a v0.1.0 2024-10-24T17:48:45Z +33.50388186046625 27.965268896899595 0.15547936602870813 -0.1967512531328321 43.62716897356692 37.73553975322001 NY d23b28a v0.1.0 2024-10-24T17:48:45Z +17.92110361325814 20.68229633110371 -0.00723355263157895 -0.07412844611528822 22.73899187850074 26.30850592777131 OH d23b28a v0.1.0 2024-10-24T17:48:45Z +4.902521345457254 4.713615245694379 0.03326854066985645 -0.01424436090225564 6.677019032072608 6.4477458197554425 OK d23b28a v0.1.0 2024-10-24T17:48:45Z +2.9364761351762785 2.895022490547015 0.18295065789473683 0.16356549043062202 4.156916282564877 4.056688790333076 OR d23b28a v0.1.0 2024-10-24T17:48:45Z +17.50366417275519 15.606524932718033 0.1030933014354067 0.1038438995215311 23.02121631799656 21.02880819423376 PA d23b28a v0.1.0 2024-10-24T17:48:45Z +3.093392245788411 1.2663025455539536 0.08266058612440191 -0.00455509868421052 4.14732349142619 1.725527009546006 PR d23b28a v0.1.0 2024-10-24T17:48:45Z 2.0362671896849207 1.7934476015378913 0.1280319976076555 0.08800807416267943 2.803457296436414 2.487143067632154 RI d23b28a v0.1.0 2024-10-24T17:48:45Z -5.839786326323818 6.200270482232246 -0.044833433014354065 0.034053571428571426 7.6028703438159 8.04232097843762 SC d23b28a v0.1.0 2024-10-24T17:48:45Z -1.8207329005040773 1.732223366881065 0.04118301435406698 -0.08219627192982457 2.5527691225250875 2.4177734724652686 SD d23b28a v0.1.0 2024-10-24T17:48:45Z -8.079474888587658 8.288811153812468 -0.22617822966507176 -0.23663337320574163 10.874040806880243 11.099932188522361 TN d23b28a v0.1.0 2024-10-24T17:48:45Z +5.839786326323818 6.200270482232246 -0.04483343301435406 0.03405357142857142 7.6028703438159 8.04232097843762 SC d23b28a v0.1.0 2024-10-24T17:48:45Z +1.820732900504077 1.732223366881065 0.04118301435406698 -0.08219627192982457 2.5527691225250875 2.4177734724652686 SD d23b28a v0.1.0 2024-10-24T17:48:45Z +8.079474888587658 8.288811153812468 -0.22617822966507176 -0.23663337320574163 10.874040806880243 11.09993218852236 TN d23b28a v0.1.0 2024-10-24T17:48:45Z 24.461374568412893 23.24082356655801 0.1297760663507109 0.12861128428927682 33.17701247248963 31.69455404480563 TX d23b28a v0.1.0 2024-10-24T17:48:45Z -2.8178204263036792 3.7589203794567805 0.05878379186602871 0.12130576441102757 3.902915045558864 5.100773220063728 UT d23b28a v0.1.0 2024-10-24T17:48:45Z +2.8178204263036792 3.758920379456781 0.05878379186602871 0.12130576441102756 3.902915045558864 5.100773220063728 UT d23b28a v0.1.0 2024-10-24T17:48:45Z 9.31066356925296 9.940102304634978 -0.07661692583732058 0.06005513784461153 12.235677254614664 13.131355747406833 VA d23b28a v0.1.0 2024-10-24T17:48:45Z -1.0389099873376009 0.9969658075902401 0.015654605263157893 -0.07509210526315789 1.4404654732416546 1.3798339239587663 VT d23b28a v0.1.0 2024-10-24T17:48:45Z -3.7624827105477645 4.382015883523629 0.13199671052631579 0.16073444976076556 5.339287881752803 6.080921102596778 WA d23b28a v0.1.0 2024-10-24T17:48:45Z +1.0389099873376009 0.99696580759024 0.01565460526315789 -0.07509210526315789 1.4404654732416546 1.3798339239587665 VT d23b28a v0.1.0 2024-10-24T17:48:45Z +3.762482710547765 4.382015883523629 0.1319967105263158 0.16073444976076556 5.339287881752803 6.080921102596778 WA d23b28a v0.1.0 2024-10-24T17:48:45Z 7.677845751651603 6.296739092318949 0.02635855263157895 0.0356258971291866 10.270036785209731 8.446609072660827 WI d23b28a v0.1.0 2024-10-24T17:48:45Z -4.15809732217813 3.9349108543294924 -0.033649222488038276 -0.06905023923444976 5.48328148028716 5.30293106613696 WV d23b28a v0.1.0 2024-10-24T17:48:45Z +4.15809732217813 3.934910854329493 -0.03364922248803827 -0.06905023923444976 5.48328148028716 5.30293106613696 WV d23b28a v0.1.0 2024-10-24T17:48:45Z 1.018993069295358 0.9336290878638694 0.13486543062200956 0.05128070175438596 1.4132670568083936 1.2955844605503093 WY d23b28a v0.1.0 2024-10-24T17:48:45Z -7.44046036475585 7.397705990484652 0.038212850735970576 0.012653495266693801 9.899039297421002 9.905349094532156 all d23b28a v0.1.0 2024-10-24T17:48:44Z +7.44046036475585 7.397705990484652 0.03821285073597057 0.0126534952666938 9.899039297421002 9.905349094532156 all d23b28a v0.1.0 2024-10-24T17:48:44Z diff --git a/output/benchmarking/latest_all_forecasts_by_forecast_date.tsv b/output/benchmarking/latest_all_forecasts_by_forecast_date.tsv index d3f05e55..c331352a 100644 --- a/output/benchmarking/latest_all_forecasts_by_forecast_date.tsv +++ b/output/benchmarking/latest_all_forecasts_by_forecast_date.tsv @@ -1,23 +1,23 @@ forecast_date crps_hosp crps_ww bias_hosp bias_ww ae_hosp ae_ww wweval_commit_hash wwinference_version time_stamp -2023-10-16 4.256933535461482 4.677370441094627 -0.020467990890688254 -0.10726857585139318 5.895361948275802 6.40167764415396 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-10-23 4.047315226528276 4.631789914889093 -0.09872773279352226 -0.16621130030959752 5.610628735112493 6.210695845766179 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-10-30 4.100770029594852 4.379587942220779 -0.14525657894736843 -0.19440208978328175 5.544465252465204 5.941233543544665 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-06 5.255407521988535 5.932679027358801 -0.29768509615384614 -0.29097226522187825 6.975464949424841 7.864106878051551 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-13 6.946577503431648 6.936479202826244 -0.4860530111336032 -0.49226186790505677 8.943972972771006 9.221247117807152 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-20 7.759903401522265 5.902333740557295 -0.49563879048583 -0.419578044375645 9.916515197242543 8.0139594342945 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-11-27 7.640750277248922 7.255636035039714 -0.5068352732793522 -0.42566498968008254 10.198548996354523 9.726490371356666 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-12-04 9.021347319079029 9.072298721634764 -0.5661029858299595 -0.5088498452012384 11.773734392455939 11.600043600429995 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-12-11 8.417316895980093 8.542035707872587 -0.45781313259109313 -0.42599513157894736 10.822920070978173 11.027416678451043 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-12-18 8.815867884856738 8.349023201732756 -0.36597988360323885 -0.37057855263157896 11.373181687982749 10.851875301875848 d23b28a v0.1.0 2024-10-24T17:48:45Z -2023-12-25 7.789253128499376 7.969011598093365 -0.27195976720647774 -0.20117733253588518 10.43430440859026 10.966165282778 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-01 7.592317000509569 6.536994643195594 0.03862095141700405 -0.025541353383458646 10.37069031741096 9.032050896441008 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-08 15.72873971884139 17.34649853791809 0.5114973431174089 0.5977302631578947 20.23980158633673 22.760906397690366 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-15 16.8368764606006 16.16988800060564 0.7335118927125506 0.7420599581339713 21.470723001323357 21.324997246737848 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-22 12.578120503174347 8.591867733854587 0.752081983805668 0.5869108187134503 16.745523991865298 11.962299845196963 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-01-29 6.250229873276504 5.597408510283156 0.46447431680161944 0.3517020035885168 8.897102295171909 7.708389135822814 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-02-05 4.573424286089247 5.8253084042799985 0.12928175607287448 0.12520877192982455 6.391327797333847 7.939784670173955 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-02-12 4.104713553309723 6.313650246216045 0.11586000504032258 0.16542651255707763 5.819277416265341 8.622847250097367 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-02-19 6.860996913410704 7.869580159555713 0.3967626518218623 0.41254633258678614 9.385290651710555 10.540015575926462 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-02-26 5.701146824066562 7.33035510471486 0.4148002277327935 0.44525109649122807 7.9176729122140515 9.904555497601788 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-03-04 5.112789339042601 4.854152444626718 0.5130581983805668 0.4640028195488722 7.123287289921584 6.752411039873908 d23b28a v0.1.0 2024-10-24T17:48:45Z -2024-03-11 4.312835875935859 4.263065993475463 0.48293927125506075 0.3586044575725027 5.945585926634464 5.904156153397102 d23b28a v0.1.0 2024-10-24T17:48:45Z +2023-10-16 5.059832198025414 4.501664311215313 -0.0763335020242915 -0.056744279176201375 7.196846342932589 6.417293680713388 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-10-23 4.18242235006235 4.413074319173952 -0.11766093117408907 -0.11811315789473684 5.872168190751324 5.918167022644099 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-10-30 3.9219506958608275 3.5210321563246176 -0.1053626012145749 -0.08041593567251462 5.393236641297567 4.556872909525013 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-06 5.255322819720833 4.242950709531141 -0.2441136133603239 -0.20688696172248805 7.414134578598956 6.0135603392186425 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-13 7.012799991126642 4.998084614217982 -0.5118594382591093 -0.46080248205741625 9.64599332435846 6.824715861342708 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-20 6.690375498626213 4.569349653386474 -0.41770723684210526 -0.30216682330827066 9.214825658027166 6.337797225183365 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-11-27 5.367627142174053 5.031212394265873 -0.26671799089068826 -0.24200260097919216 7.5482110987083395 7.068444939700455 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-04 6.764647750371329 7.420530433101996 -0.31960437753036436 -0.3100663875598086 9.440455766083506 10.504710217364053 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-11 6.8594860507920785 5.4574081640829295 -0.16721419534412957 -0.17022117794486216 9.55203634898675 7.785618001707871 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-18 8.358376515160765 6.455104681756234 -0.12688347672064776 -0.17103555764411027 11.198803534577065 8.875209211526409 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2023-12-25 6.894327278046133 7.758221090506614 -0.10081376518218624 -0.013425675675675677 9.34975699525672 10.585508784012148 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-01 10.31738321239008 7.901786950597124 0.2344056174089069 0.1605827067669173 14.418033531994073 10.919645060776363 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-08 28.7932922854294 23.31310760445013 0.6610759109311741 0.7008788088642659 37.046751992777224 30.793527506859903 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-15 19.445812351084225 16.387511402770986 0.7812803643724696 0.7319326923076923 25.995676615059736 22.008691829376154 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-22 8.951908471135088 6.350654896121348 0.600787955465587 0.4347277327935223 12.903170731444915 8.784297320600754 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-01-29 5.099562638508678 6.354915264254163 0.08971103238866397 0.09217830634278003 7.255509012912055 8.999088732619368 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-05 5.1731132957947406 6.678920578971974 -0.14593003542510122 -0.029273355263157892 7.087254525265564 9.716560898845575 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-12 11.222311326853164 11.951289868227024 -0.070354504048583 0.02381831983805668 14.188932611966608 14.992837778794046 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-19 7.663909447407364 7.6769418153113 0.3177726467611336 0.3024981203007519 10.733195134321834 10.273287233821865 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-02-26 4.921266785280591 5.603520805103531 0.29640599696356273 0.3353181390977444 7.022260884531381 8.071790643313324 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-03-04 4.233753799775528 4.364753819915278 0.369924721659919 0.34656012851897183 5.919483809471711 6.114155205887852 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2024-03-11 3.357096806226528 3.3860785699505214 0.2889935475708502 0.14207775119617225 4.575087973170657 4.692928674471748 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z diff --git a/output/benchmarking/latest_all_forecasts_by_location.tsv b/output/benchmarking/latest_all_forecasts_by_location.tsv index a0b2832c..0a4e30e1 100644 --- a/output/benchmarking/latest_all_forecasts_by_location.tsv +++ b/output/benchmarking/latest_all_forecasts_by_location.tsv @@ -1,54 +1,54 @@ crps_hosp crps_ww bias_hosp bias_ww ae_hosp ae_ww location wweval_commit_hash wwinference_version time_stamp -1.0245932139677376 0.9913943382419593 -0.044675239234449764 -0.013038533834586467 1.4025499429326875 1.3650619629241825 AK d23b28a v0.1.0 2024-10-24T17:48:45Z -6.2973367913173295 6.192682400370224 -0.03878678229665072 -0.06537312030075189 8.489186903031504 8.333960689048661 AL d23b28a v0.1.0 2024-10-24T17:48:45Z -3.9911150596101774 4.036037220576845 -0.012324162679425835 -0.0019174641148325348 5.487570048714099 5.5851838339781565 AR d23b28a v0.1.0 2024-10-24T17:48:45Z -5.494061035228348 6.253645689179519 0.12577212918660285 0.14063785885167462 7.692517734681003 8.650969083257658 AZ d23b28a v0.1.0 2024-10-24T17:48:45Z -28.27066280033458 21.93607622181548 0.02693450956937799 0.0046024436090225575 38.41093608479694 30.12777787819662 CA d23b28a v0.1.0 2024-10-24T17:48:45Z -4.266355755551796 5.507450335072049 0.2278758971291866 0.060432117224880386 5.808582812739105 7.449730504624001 CO d23b28a v0.1.0 2024-10-24T17:48:45Z -5.675809214558925 5.590328180506943 0.09745394736842106 0.11458223684210526 7.895203593005671 7.776350350413904 CT d23b28a v0.1.0 2024-10-24T17:48:45Z -1.6341339983615357 1.595556000322384 0.1160005980861244 0.11490444862155388 2.2780983791627385 2.2276453664725517 DC d23b28a v0.1.0 2024-10-24T17:48:45Z -1.647896164765979 1.7576311317190145 0.005867523923444978 0.03555795739348371 2.3081115320095456 2.4397121106311683 DE d23b28a v0.1.0 2024-10-24T17:48:45Z -20.9745847035626 21.309299258022506 0.01895813397129186 0.08765288220551379 27.35031504551748 27.843829233436576 FL d23b28a v0.1.0 2024-10-24T17:48:45Z -14.246079346033854 13.784749176480657 -0.037579545454545456 -0.08648026315789474 18.26668590947028 17.62468400771157 GA d23b28a v0.1.0 2024-10-24T17:48:45Z -1.2685291989675689 1.2772794395553102 0.09037769138755981 0.07232581453634085 1.7818926731226852 1.7989016009979328 HI d23b28a v0.1.0 2024-10-24T17:48:45Z -5.1947667172122 4.919456006863106 -0.027432715311004784 -0.05068013784461153 6.616923506647085 6.272865371617346 IA d23b28a v0.1.0 2024-10-24T17:48:45Z -2.6917584717827103 2.70666632435346 0.059654007177033494 0.04381668660287081 3.7033527451393238 3.731358045069099 ID d23b28a v0.1.0 2024-10-24T17:48:45Z -16.51234888964669 15.029437072559894 -0.03727870813397129 -0.06539285714285714 21.786801323502324 19.61566035834812 IL d23b28a v0.1.0 2024-10-24T17:48:45Z -11.319234959606781 8.950594053434703 0.06199013157894737 0.047455827067669175 14.736819644395094 12.131902102353887 IN d23b28a v0.1.0 2024-10-24T17:48:45Z -4.735709974474379 4.554763806661009 -0.03907894736842106 -0.05304336124401914 6.411162273432199 6.167865764567813 KS d23b28a v0.1.0 2024-10-24T17:48:45Z -6.087160684773657 5.213338501028242 -0.0848761961722488 0.6152675438596491 8.178993007078178 7.3132276990773795 KY d23b28a v0.1.0 2024-10-24T17:48:45Z -4.654039580040471 4.631081722074162 -0.04461034688995215 -0.09320526315789474 6.188500968146125 6.037647236309703 LA d23b28a v0.1.0 2024-10-24T17:48:45Z -11.702569548366563 10.800529123616966 0.18111124401913875 0.18163247607655503 15.321982133176324 14.33645741171139 MA d23b28a v0.1.0 2024-10-24T17:48:45Z -5.581192194841542 5.4806076066391265 0.04022846889952153 0.02348116028708134 7.527718152191338 7.397348248046321 MD d23b28a v0.1.0 2024-10-24T17:48:45Z -2.2107845326906364 2.075052461675859 0.13745035885167464 0.09685915071770335 3.1323245237045456 2.915724435431815 ME d23b28a v0.1.0 2024-10-24T17:48:45Z -13.95259850433921 11.763482001828006 -0.010866028708133975 -0.2632308897243108 18.058074388540586 16.529310467094348 MI d23b28a v0.1.0 2024-10-24T17:48:45Z -5.697391398241083 7.929183975619169 0.005695873205741621 0.12297188995215311 7.51087871508186 10.01770980745194 MN d23b28a v0.1.0 2024-10-24T17:48:45Z -8.532446104557419 12.62858140431652 -0.0017233851674641088 -0.06963931888544891 11.392358847422608 16.576228782735367 MO d23b28a v0.1.0 2024-10-24T17:48:45Z -2.868227438723672 2.3542130355847326 -0.0683444976076555 -0.5116828947368421 3.960336219102815 3.268465707668931 MS d23b28a v0.1.0 2024-10-24T17:48:45Z -1.8092339977929996 1.792138173886483 0.17317703349282296 0.15372556390977443 2.5598288304241064 2.522808654100039 MT d23b28a v0.1.0 2024-10-24T17:48:45Z -8.56352270755409 8.173334830161215 0.03532775119617225 0.035106829573934836 11.522226294413143 11.01439335027247 NC d23b28a v0.1.0 2024-10-24T17:48:45Z -1.3607549940255612 1.5212783546471602 -0.07146561004784689 -0.4997717105263158 1.901082803729751 2.148158013958308 ND d23b28a v0.1.0 2024-10-24T17:48:45Z -3.489447911677376 2.896524173913666 -0.03079665071770335 0.023639354066985648 4.695626730946361 4.001703638214006 NE d23b28a v0.1.0 2024-10-24T17:48:45Z -2.185794837646797 1.8622396768839506 0.12105263157894737 0.09318859649122807 2.985529977657489 2.551918529223364 NH d23b28a v0.1.0 2024-10-24T17:48:45Z -15.898477720284601 15.526196598773701 0.08451824162679426 0.04625448564593301 20.6630021710342 20.091412606142235 NJ d23b28a v0.1.0 2024-10-24T17:48:45Z -2.379615471089599 2.261852214376928 0.08282984449760766 -0.108296875 3.317826151516665 3.132459090770379 NM d23b28a v0.1.0 2024-10-24T17:48:45Z -2.639337400936249 2.6900817287758234 0.00816357655502392 0.03644856459330144 3.7205706795144837 3.7986365057389593 NV d23b28a v0.1.0 2024-10-24T17:48:45Z -33.50388186046625 27.965268896899595 0.15547936602870813 -0.19675125313283207 43.62716897356692 37.73553975322001 NY d23b28a v0.1.0 2024-10-24T17:48:45Z -17.92110361325814 20.682296331103714 -0.007233552631578952 -0.07412844611528822 22.73899187850074 26.30850592777131 OH d23b28a v0.1.0 2024-10-24T17:48:45Z -4.902521345457254 4.713615245694379 0.033268540669856454 -0.01424436090225564 6.677019032072608 6.4477458197554425 OK d23b28a v0.1.0 2024-10-24T17:48:45Z -2.9364761351762785 2.8950224905470154 0.18295065789473683 0.16356549043062202 4.156916282564877 4.056688790333076 OR d23b28a v0.1.0 2024-10-24T17:48:45Z -17.50366417275519 15.606524932718033 0.1030933014354067 0.1038438995215311 23.02121631799656 21.028808194233758 PA d23b28a v0.1.0 2024-10-24T17:48:45Z -3.093392245788411 1.2663025455539536 0.08266058612440191 -0.004555098684210526 4.14732349142619 1.725527009546006 PR d23b28a v0.1.0 2024-10-24T17:48:45Z -2.0362671896849207 1.7934476015378913 0.1280319976076555 0.08800807416267943 2.803457296436414 2.487143067632154 RI d23b28a v0.1.0 2024-10-24T17:48:45Z -5.839786326323818 6.200270482232246 -0.044833433014354065 0.034053571428571426 7.6028703438159 8.04232097843762 SC d23b28a v0.1.0 2024-10-24T17:48:45Z -1.8207329005040773 1.732223366881065 0.04118301435406698 -0.08219627192982457 2.5527691225250875 2.4177734724652686 SD d23b28a v0.1.0 2024-10-24T17:48:45Z -8.079474888587658 8.288811153812468 -0.22617822966507176 -0.23663337320574163 10.874040806880243 11.099932188522361 TN d23b28a v0.1.0 2024-10-24T17:48:45Z -24.461374568412893 23.24082356655801 0.1297760663507109 0.12861128428927682 33.17701247248963 31.69455404480563 TX d23b28a v0.1.0 2024-10-24T17:48:45Z -2.8178204263036792 3.7589203794567805 0.05878379186602871 0.12130576441102757 3.902915045558864 5.100773220063728 UT d23b28a v0.1.0 2024-10-24T17:48:45Z -9.31066356925296 9.940102304634978 -0.07661692583732058 0.06005513784461153 12.235677254614664 13.131355747406833 VA d23b28a v0.1.0 2024-10-24T17:48:45Z -1.0389099873376009 0.9969658075902401 0.015654605263157893 -0.07509210526315789 1.4404654732416546 1.3798339239587663 VT d23b28a v0.1.0 2024-10-24T17:48:45Z -3.7624827105477645 4.382015883523629 0.13199671052631579 0.16073444976076556 5.339287881752803 6.080921102596778 WA d23b28a v0.1.0 2024-10-24T17:48:45Z -7.677845751651603 6.296739092318949 0.02635855263157895 0.0356258971291866 10.270036785209731 8.446609072660827 WI d23b28a v0.1.0 2024-10-24T17:48:45Z -4.15809732217813 3.9349108543294924 -0.033649222488038276 -0.06905023923444976 5.48328148028716 5.30293106613696 WV d23b28a v0.1.0 2024-10-24T17:48:45Z -1.018993069295358 0.9336290878638694 0.13486543062200956 0.05128070175438596 1.4132670568083936 1.2955844605503093 WY d23b28a v0.1.0 2024-10-24T17:48:45Z -7.44046036475585 7.397705990484652 0.038212850735970576 0.012653495266693801 9.899039297421002 9.905349094532156 all d23b28a v0.1.0 2024-10-24T17:48:44Z +0.965387517442082 0.9356726549249403 -0.053803827751196166 -0.021681077694235586 1.3360690132743076 1.2971384472121235 AK 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +6.955739115298207 6.621319048559378 0.03897458133971292 0.0032456140350877152 9.783588779351387 9.344950063891512 AL 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.612949724477276 4.619899220775841 0.03404455741626795 0.06411812200956939 6.559294184742686 6.602107248445021 AR 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +6.139491770368693 6.2294582093970625 0.10818361244019138 0.18072816985645934 8.477386434918628 8.90310180752627 AZ 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +26.588534494916185 20.52040185556402 0.036293959330143545 -0.08157236842105263 37.30597767922585 28.48679419035798 CA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.0413080897736355 10.578064436431587 0.16108163875598086 0.07897631578947369 5.527137857761504 14.848360021470164 CO 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.015535369939763 5.0323365479988516 0.08661094497607656 0.11052272727272727 7.138672143335744 7.10257825825303 CT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.6398772474245782 1.537739218782322 0.03179156698564593 0.05669047619047619 2.3306428485950876 2.18006215101481 DC 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.8881972653043033 2.009117820817491 4.542464114832541e-4 0.03101691729323308 2.688161115244514 2.8139975492671847 DE 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +20.409297283433713 21.411315454487955 0.010642045454545456 0.0535921052631579 27.753851511910412 29.656633261469594 FL 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +15.905086019860233 14.927301179716123 0.02460944976076555 -0.02692042606516291 20.98441795749843 20.00012173843837 GA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.5552575174479188 1.5088897987051066 0.05280861244019139 0.060201127819548866 2.1794515505434604 2.076243353575278 HI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.717988564081217 4.50716558687924 -0.023177631578947363 -0.031551065162907274 6.459058358087138 6.203020208058825 IA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.664940427832129 2.6566164279440403 0.042231758373205745 0.05031429425837321 3.733885551762075 3.700885566935998 ID 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +15.66057551045102 26.563097854729186 0.05806997607655502 -0.9375964912280702 21.27280670343953 31.358615276374085 IL 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +11.804864260060622 9.292179707944472 0.1272903708133971 0.1593643483709273 16.103834361264273 12.155042953551764 IN 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.347825543314189 4.504948667657593 0.04685137559808612 0.04460974880382775 7.364884245020363 6.2397348261921 KS 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.909986697820656 5.533975988383646 -0.037652511961722486 0.6098421052631579 8.242839796436954 7.92432457450872 KY 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.909872993043222 3.9546312090926263 0.026304126794258375 -0.056122180451127816 7.00728123043053 5.762924665213887 LA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +11.737793357804062 10.226645165347154 0.18520873205741625 0.1803444976076555 15.977060923470379 13.965975170613289 MA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.21720610825874 5.302346105006481 0.022237141148325357 -0.008757177033492821 7.215859234306069 7.389007646648587 MD 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.6927457058276585 2.2588326160857846 0.036038277511961724 0.020204844497607656 3.8014047967180864 3.159837377035527 ME 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +14.730706891862104 22.7346423869701 -0.00844527511961723 0.7762631578947369 19.775809588058262 32.4709334824226 MI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +5.5302501738480165 15.112816373858022 0.024498504784688995 0.22898444976076557 7.547259761194644 20.279988949964995 MN 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +8.365791299143524 13.745538982597983 0.04102870813397129 -0.8615526315789473 11.647575781640057 17.699665482164928 MO 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.094162816472101 1.8973368741099579 0.014612141148325361 -0.3552078947368421 4.336421750902773 2.7830031494391134 MS 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.9599915333073132 1.9340943128178083 0.13829874401913875 0.09470238095238095 2.7431841632257683 2.695341283672515 MT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +8.742957676170628 9.41927742439938 0.021450956937799047 -0.006226562499999999 12.277549583611107 13.417373890415512 NC 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.2464157487377392 1.357870439694969 -0.07386154306220095 -0.2867447368421053 1.7346142614637663 1.8928829213958465 ND 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.6357708711269816 2.839546417942367 0.04913636363636364 0.10299461722488039 4.953808551539756 3.922232148443104 NE 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.2669651414052194 1.7423114838769374 0.011480562200956938 0.021594924812030073 3.1795950502230994 2.3966686186792816 NH 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +17.06495420067773 17.19952298890777 0.031207236842105263 0.02376106459330144 22.855018957302537 23.34979932568371 NJ 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.1114299268361734 2.003735102983464 0.05469736842105263 -0.039611019736842105 3.0073539794767554 2.8496542102035103 NM 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.445907816827532 2.603543511346354 -0.006664772727272728 0.018771531100478474 3.4919845652806667 3.686297298603071 NV 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +34.57766162002901 41.90428292784995 0.16256638755980862 0.2363684210526316 46.07384681680061 57.84859954209488 NY 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +17.11437871070843 26.663026055456843 0.009475179425837326 -0.9665921052631579 22.604039491972145 31.88850472623202 OH 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.975513723952207 4.685327690161878 0.07737948564593301 0.010185776942355887 7.092988058603186 6.6906360304346935 OK 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.2171984675312135 3.369291487721138 0.06290311004784689 0.10623534688995215 4.519335330589072 4.669746336730518 OR 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +21.143742672067187 18.96291755229285 0.14407147129186604 0.2945824561403509 27.958592258938772 25.645788714340473 PA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.6231257848944445 1.6029227660673095 0.17208522727272726 0.062144736842105266 4.983246210872801 2.171304143131584 PR 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.0036672725762763 1.7179351261692153 0.05545334928229665 0.060870514354066985 2.800240973911771 2.4016625334694717 RI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +6.299021651012965 6.44809830333831 -0.01875328947368421 0.045721177944862156 8.662279654460365 8.832640038919886 SC 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +1.5751364208218028 1.3630394938537413 0.04307505980861244 -0.09958808479532164 2.238577274679975 1.922608727311533 SD 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +8.50070363039982 8.496821218598857 -0.16921501196172248 -0.172252990430622 11.776124960369364 11.7773945748676 TN 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +44.38266193151503 52.13365436007212 0.17992793062200957 0.2682763157894737 58.31509334625342 68.35251694821251 TX 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +2.587089810259867 4.5789768812919585 0.02096172248803828 0.10678665413533835 3.5881706456749685 6.07099624798896 UT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +9.627103026017702 11.31885461995276 -0.0789659090909091 0.1479705513784461 13.149021877415093 15.535837157886133 VA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +0.9516676633744922 0.8638913394393114 0.03298056220095694 -0.08378148496240602 1.3508945843452176 1.2269036929560833 VT 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +3.9688201351008816 6.3304501571561005 0.085876495215311 0.1224997009569378 5.552191578829858 8.765664845256408 WA 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +7.698080478940572 5.996855465245554 0.10312739234449761 0.08111214114832536 10.341592698765059 8.121253437267779 WI 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +4.10695469423953 4.0194445022588665 -0.037249401913875595 -0.0666238038277512 5.621040224639752 5.476177490096456 WV 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +0.9999845765227394 0.9554595452207291 0.1340278110047847 0.045077694235588966 1.4214779111537204 1.3693813585099321 WY 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:22Z +7.97938994135691 7.007810007322375 0.04408191479573058 0.03812017543859647 10.862355695567917 9.577604930147658 all 2a70b2b 227-inf-feedback-posterior-mod-eta 2024-11-05T21:00:21Z diff --git a/output/benchmarking/plots/all_forecasts_by_forecast_date.png b/output/benchmarking/plots/all_forecasts_by_forecast_date.png new file mode 100644 index 0000000000000000000000000000000000000000..6bbf86d3212b8a4eb5873293aff59031583b98a4 GIT binary patch literal 142344 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 kzQwpc~6@XOXBrSbOd&yX}?5C>ND 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 z zLK41+KhbWM5X<6sh%9))TsTs}vlBA{N~4 zt%l~!Sw;$LUP83tnG|n5)ajc{^D33X8GJI-mu@31L1*jBc6OP)bfj~X;e3ae!DpY) z2MC&tHa&Z`gaatIjnJB!dc9IWdI6GMzD*K65pPfL!RR3!nQ$!M`!~3b>f-G|ZVDK@ zybmX1t9J7?c>?lBI4V%;(257~p$`xkVSPpTg02W08OBg>Q{%&2B7l#0kyW>)WmLJ) z$mitjh2Zaw>$;HRv0zsbPL*A*Ln!3QIyv7#xWJ*p)`$+b1vWj-<&o)6z=I;(rk*tG zM@9c6ISDuec!1@LN^c!Gd*MR=JgLbJ2RAYoh3;xX-@1A37Zwq|8FSj{*P3B6IiXJC z4#9gG%Q{>IP-Y5SY2=kGs7c^VPC}T;{83M~<7ptPoMD+Pn#edoHt}iOL5Sh}c@`}R zUj1j#^|ct9e8pH8-Z$(hd{ZGM!C(802!HS1z0$>}khVXA{TOcLVv&a1>e1&-5O=j!EU4!PwwFHx6?1v>pa@HGmfQ$f%_p z1>ONQsB2Mn|F8DWJ*vh;4dZ3zjEO^%n9Rg9X6rT~4QB6@n3ygG5t}YH4b=>xJxM9W zG%XSnNs-*8R?*g^rpqRmq6?Cw%ZbL+PD)XvX>>WikJef1{B_Pce;REg^v?XQC`C1W-e+-pc_fT<>f z_{93F4obg}o@Pn#5Dg72-JosTHcO6XeP^iHL#sbDyE#W^-T*!H4oZ)$4LOlO^;D#h zR%3%L82_QQtqLwgkhMM~z)knADcmwkCaVL6+@(L8FU~3Zy@sC1;-3t;6XtKGiyG4f zaci{;53A(m4p;d+>yv^a(E_Juou`F`wr0UH-(bgkPkr5+u5-Nw^{mTYm43BjgFNfn zDIOVlRQm|jpWH($?3AN+E@=W+Mb}`hr1Rr^~)V^m_0Xl^F}OcU0Y~oaAP>Ts-`O#4@a8=wb1X zXXCxVIpsByBooFc>F^IlUW>t03?%R$%_EwF^fxNo=V4nyzgnRu^M4$6z+mC-gwSWW zKCEWMR-Q0P)UB1L`f@g&P`)|97fH7?UelWyp1z;ylXWmV#kHiT7Gsx|dK%9A4;ScInPh zB`43Sx3#xlyx@ZbC&N3=-P)f`ow`_jxB|VGfPLBOZ;+n_=vcu_>cavZkk^i|~>W2S!ZGj*l@AiHvS~P?|n?Fl@*soq+Bw;?^}5{exN2feE~vKn5EPt$!QE zOpKx997QD}J!DF$jL`{<0e_{@O=RWv%Pv!BLUDRgKy(}5pogh z#QqVZ8|?Ox6k_?#2M-<`xOMAaZ{Boa$p`}r-22w=Lk|#-^fX>i&yqc&bZZ0}e5+u2 zZXci3Ph3@8dL0+4^P;_-i|eH0rroZgWFT-B9X-eVpg>n6ixgUDn=6+pdIs#Go zNNLpQImt%A`(k|kEat0Q?+}d5Rv5SwF#xDimgGNzpJ9;CW3n(fz$0$+%RTz1>`J*B%QTz}`a^|rfb%gvC6`{ES7$t*SWWYJA#sTE1)U>(ukGp= z5DNSYkjL+{2w)_kiAy2TyE5TUMMmYvpfOBz&lCuhluLh>#*4q}>W*0Sdx*>~YT3Ev zX72ePvT1kPy6J=xLHW->?xdy3(MTshxBDPe-_*2~!jiZF%CKAMz@9Nz*Z2z0)xQK) zt)=;55l>dt`uj;`h!MwWX|d;Z-Irrw-B=4_jz>UQS2CCb{GfZV_(|!*_RQA5*FR4a z%O;mbMrE8y>A6^0WyfHTTALT|gIp;%=ezf=R>M-crhSQBb>xto(RU={92JK{_Qx5k zG0fm-p|+t|ei0GuC2!M}QWRw1iN@pC*+;#yS?Dp%%2i)blwor~ga;z94Hi)tOr6?s z+*Lc5MBoQ4!^_6-WT67NsQ_pP7$z@*bu57SE)V#R<~4Z|>)(CLY^rY-JTpZ*yl>wqJib6U8T0r-qWTf7N-E zUeH_WB&_SiU>2@QC0clN23kNa3{)t&p{%8onlf_lULA*PZ)d|6`J2fHZ9ihn6Xk1T z)-&Ivx%}J9&@077ZD43EcXpci`bymRk_poBctTK@^{}XkpGLY7jLi=%6P8?n{n*{G z1ad5-(%7-iTqXU&nAW%|nDsPad`Z{55uq@kAbP|m!EKvo!8|D!hzkU=p3`Jt;Y-%k zluj%#68S!_0PwKCicM7bmLc?N!VSajV>H`N{CSKEWtqO2iR7V`}4% zXkW?97OT7d(fIxq(Xj!`*~P+^I{xe%Da`2pZhW)eXOG#97iYEAu4sn8vzoECA8@+) z_n&1JA{yHp7eC3-n3UG8H`R5*c-Q*f16DX^^4~f2e425@5)u8$&2Be8N`LD(6I6fv zKOQ)=iZib5`14|5;PFd;IG6NZf2N^!W&F$bzj^|!N>}=vkIl`k*4{qM`Nl`-GlcV3 zQ|sU5`PS#--DwH`@~=}64HyC$4Xhoo{jaX<|A!Fn!2fhRWe%CqR$n{)5GfqMZten` J)H$nu`X>b77&ia_ literal 0 HcmV?d00001 diff --git a/output/benchmarking/plots/all_forecasts_overall.png b/output/benchmarking/plots/all_forecasts_overall.png new file mode 100644 index 0000000000000000000000000000000000000000..df281580c4c9f1331c7aae7d17322d04dde3312d GIT binary patch literal 70372 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 literal 0 HcmV?d00001 From c6cfb15252db08f8e10dc8621cedae658b59d4fd Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 12 Nov 2024 18:40:25 +0000 Subject: [PATCH 014/110] make legend two rows using guides --- wweval/R/benchmarking.R | 1 + 1 file changed, 1 insertion(+) diff --git a/wweval/R/benchmarking.R b/wweval/R/benchmarking.R index d1ac3379..11820e66 100644 --- a/wweval/R/benchmarking.R +++ b/wweval/R/benchmarking.R @@ -274,6 +274,7 @@ plot_benchmarks <- function(grouping_var, position = "dodge" ) + facet_wrap(~score_type, scales = "free_y") + + guides(fill = guide_legend(nrow = 2, byrow = TRUE)) + theme( legend.position = "bottom", panel.background = element_rect(fill = "white") From a4771bf2ba56751a1db2c4c19d8cd95764148780 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 12 Nov 2024 18:41:58 +0000 Subject: [PATCH 015/110] add sigma_rt plots to post process --- wweval/R/eval_post_process.R | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/wweval/R/eval_post_process.R b/wweval/R/eval_post_process.R index 1e0ed9a0..3920b168 100644 --- a/wweval/R/eval_post_process.R +++ b/wweval/R/eval_post_process.R @@ -151,6 +151,19 @@ eval_post_process_ww <- function(config_index, ) + geom_histogram() + sigma_rt <- ww_raw_draws |> + tidybayes::spread_draws(!!str2lang("sigma_rt")) |> + dplyr::mutate( + draw = .data$`.draw`, + ) |> + dplyr::select("sigma_rt", "draw") + + p_sigma <- ggplot( + sigma_rt, + aes(x = sigma_rt) + ) + + geom_histogram() + eta_sd <- ww_raw_draws |> tidybayes::spread_draws(!!str2lang("eta_sd")) |> dplyr::mutate( @@ -172,6 +185,14 @@ eval_post_process_ww <- function(config_index, ), create.dir = TRUE ) + ggsave(p_sigma, + filename = file.path( + output_dir, scenario, + forecast_date, "ww", location, + "sigma_rt.png" + ), + create.dir = TRUE + ) ggsave(p_eta_sd, filename = file.path( output_dir, scenario, From 22b139d35b94da46c0022ca01ea2daff842462ba Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 12 Nov 2024 20:50:38 +0000 Subject: [PATCH 016/110] tweak handling of rerunning failed jobs --- scratch/get_config_for_failed_postprocess.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scratch/get_config_for_failed_postprocess.R b/scratch/get_config_for_failed_postprocess.R index 858b6295..8ec4a449 100644 --- a/scratch/get_config_for_failed_postprocess.R +++ b/scratch/get_config_for_failed_postprocess.R @@ -16,7 +16,7 @@ scenario_vec <- table_missing$scenario # Load in the eval_config eval_config <- yaml::read_yaml(file.path( "input", "config", - "eval", "eval_config_rerun.yaml" + "eval", "eval_config.yaml" )) config_dir <- file.path("input", "config", "eval") @@ -31,5 +31,5 @@ new_eval_config$forecast_date_hosp <- "2023-10-16" yaml::write_yaml(new_eval_config, file = file.path( config_dir, - glue::glue("eval_config_rerun.yaml") + glue::glue("eval_config.yaml") )) From 68e03b4e59c6758350038c62694ea351e2ddfbdb Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 13 Nov 2024 15:01:39 +0000 Subject: [PATCH 017/110] replace MA with CA for example, add option to specify sites for the figures --- _targets_eval_postprocessing.R | 2 +- wweval/R/ms_fig2.R | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 4467d92b..e7d13544 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -526,7 +526,7 @@ manuscript_figures <- list( ## Figure specifications---------------------------------------- tar_target( name = locs_to_plot, - command = c("MA", "VA", "WA") + command = c("CA", "VA", "WA") ), tar_target( name = forecast_date_to_plot, diff --git a/wweval/R/ms_fig2.R b/wweval/R/ms_fig2.R index 4d098f21..631b8689 100644 --- a/wweval/R/ms_fig2.R +++ b/wweval/R/ms_fig2.R @@ -111,6 +111,9 @@ make_fig2_hosp_t <- function(hosp_quantiles, #' calibration data for, default is `90` #' @param max_n_site_labs_to_show An integer indicating the maximum number #' of site-labs to show in the figure, default is `3` +#' @param site_lab_names_to_show a vector of character strings indicating +#' the site lab names to be displayed in the plot. If NULL, the first +#' `max_n_site_labs_to_show` or all are displayed. Default is `NULL`. #' #' @return A ggplot object containing a faceted horizontal plot of the #' calibrated and forecasted wastewater concentrations for 3 or fewer @@ -121,7 +124,13 @@ make_fig2_ct <- function(ww_quantiles, date_to_plot, n_forecast_days = 28, n_calib_days = 90, - max_n_site_labs_to_show = 3) { + max_n_site_labs_to_show = 3, + site_lab_names_to_show = NULL) { + if (!is.null(site_lab_names_to_show)) { + ww_quantiles <- ww_quantiles |> + dplyr::filter(lab_site_name %in% c(site_lab_names_to_show)) + } + ww <- ww_quantiles |> dplyr::filter(location == !!loc_to_plot) |> dplyr::filter(forecast_date == !!date_to_plot) |> From f82287e401472ac8994cd44a23c91207314dccca Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 13 Nov 2024 16:38:27 +0000 Subject: [PATCH 018/110] update docs --- wweval/man/make_fig2_ct.Rd | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wweval/man/make_fig2_ct.Rd b/wweval/man/make_fig2_ct.Rd index 333e9e04..c2d17dce 100644 --- a/wweval/man/make_fig2_ct.Rd +++ b/wweval/man/make_fig2_ct.Rd @@ -10,7 +10,8 @@ make_fig2_ct( date_to_plot, n_forecast_days = 28, n_calib_days = 90, - max_n_site_labs_to_show = 3 + max_n_site_labs_to_show = 3, + site_lab_names_to_show = NULL ) } \arguments{ @@ -32,6 +33,10 @@ calibration data for, default is \code{90}} \item{max_n_site_labs_to_show}{An integer indicating the maximum number of site-labs to show in the figure, default is \code{3}} + +\item{site_lab_names_to_show}{a vector of character strings indicating +the site lab names to be displayed in the plot. If NULL, the first +\code{max_n_site_labs_to_show} or all are displayed. Default is \code{NULL}.} } \value{ A ggplot object containing a faceted horizontal plot of the From d56e8790c5a60e94364e31cb05a7c25094f5239a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 13 Nov 2024 16:55:00 +0000 Subject: [PATCH 019/110] add specific sites for CA --- _targets_eval_postprocessing.R | 7 ++++++- wweval/R/ms_fig2.R | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index e7d13544..417f2de4 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -585,7 +585,12 @@ manuscript_figures <- list( command = make_fig2_ct( ww_quants_plot, loc_to_plot = locs_to_plot[1], - date_to_plot = forecast_date_to_plot + date_to_plot = forecast_date_to_plot, + site_lab_names_to_show = c( + "Site: 2590, Lab: 34", + "Site: 2487, Lab: 34", + "Site: 2490, Lab: 34" + ) ) ), tar_target( diff --git a/wweval/R/ms_fig2.R b/wweval/R/ms_fig2.R index 631b8689..2a27e75b 100644 --- a/wweval/R/ms_fig2.R +++ b/wweval/R/ms_fig2.R @@ -128,7 +128,10 @@ make_fig2_ct <- function(ww_quantiles, site_lab_names_to_show = NULL) { if (!is.null(site_lab_names_to_show)) { ww_quantiles <- ww_quantiles |> - dplyr::filter(lab_site_name %in% c(site_lab_names_to_show)) + dplyr::filter(site_lab_name %in% c(site_lab_names_to_show)) + } else { + ww_quantiles <- ww_quantiles |> + dplyr::filter(lab_site_index <= !!max_n_site_labs_to_show) } ww <- ww_quantiles |> @@ -137,8 +140,9 @@ make_fig2_ct <- function(ww_quantiles, dplyr::filter( date <= forecast_date + lubridate::days(!!n_forecast_days), date >= forecast_date - lubridate::days(!!n_calib_days) - ) |> - dplyr::filter(lab_site_index <= !!max_n_site_labs_to_show) + ) + + stopifnot( "This function is meant for one location" = From 3185723f61ea5929c446185239b1d81d6bf97861 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 13 Nov 2024 21:37:16 +0000 Subject: [PATCH 020/110] fix typo in scores --- wweval/R/ms_fig3.R | 1 + 1 file changed, 1 insertion(+) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 25cc1653..e21443a1 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -28,6 +28,7 @@ make_fig3_single_loc_comp <- function(scores, )) |> dplyr::filter(horizon %in% !!horizons_to_show) scores_overall <- scores |> + dplyr::filter(location == !!loc_to_plot) |> data.table::as.data.table() |> scoringutils::summarise_scores(by = c( "forecast_date", "location", From 3fb4ed8327dc3b2a54949b8f3fc84d7875edf93e Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 19:33:51 +0000 Subject: [PATCH 021/110] fix bug in collection rfequency --- wweval/R/combine_and_summarize_ww_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/combine_and_summarize_ww_data.R b/wweval/R/combine_and_summarize_ww_data.R index e07325d7..db078ab2 100644 --- a/wweval/R/combine_and_summarize_ww_data.R +++ b/wweval/R/combine_and_summarize_ww_data.R @@ -174,7 +174,7 @@ load_data_and_summarize <- function(fp_hosp, fp_ww, dplyr::distinct(.data$date) |> dplyr::summarize( n_days_w_samples = dplyr::n(), - n_days_total = as.numeric(max(.data$date) - min(.data$date)), + n_days_total = as.numeric(max(.data$date) - min(.data$date)) + 1, mean_collection_freq = .data$n_days_w_samples / .data$n_days_total ) |> dplyr::summarize( From 214572d508f4e6fc0c7544dd9bc9142841a6eccb Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 19:34:50 +0000 Subject: [PATCH 022/110] remove the flag around low ww values --- wweval/R/get_table_sufficient_ww.R | 1 + 1 file changed, 1 insertion(+) diff --git a/wweval/R/get_table_sufficient_ww.R b/wweval/R/get_table_sufficient_ww.R index 86c602e0..c6bb0f40 100644 --- a/wweval/R/get_table_sufficient_ww.R +++ b/wweval/R/get_table_sufficient_ww.R @@ -22,6 +22,7 @@ get_table_sufficient_ww <- function(combined_ww_data_flags) { ) table_of_loc_dates_w_ww <- combined_ww_data_flags |> + dplyr::filter(name != "flag_low_val") |> # try removing this temporarily dplyr::group_by(location, forecast_date) |> dplyr::summarise(ww_sufficient = !any(value)) From 481197ce3be1dcf7f42d18b51bc8b0422ece109a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 20:22:18 +0000 Subject: [PATCH 023/110] add heatmaps of performance by forecast date and location --- wweval/NAMESPACE | 2 + wweval/R/supplement_analyses_and_figs.R | 93 +++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index a5ca7d91..81487ab5 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -37,7 +37,9 @@ export(get_model_draws_w_data) export(get_model_path) export(get_n_states_improved_plot) export(get_plot_bias_over_time) +export(get_plot_comb_perf_heatmap) export(get_plot_hosp_data_comparison) +export(get_plot_hub_perf_heatmap) export(get_plot_hub_performance) export(get_plot_quantile_comparison) export(get_plot_raw_scores) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index fdf015bd..715c0f07 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -723,3 +723,96 @@ get_plot_sites_vs_performance <- function(scores, return(p_n_sites) } +#' Plot a heatmap of the avg forecast performance by locations and forecast date +#' for the Hub submissions +#' +#' @param scores A tibble of daily scores by forecast date, location, and model +#' @param fig_file_dir A string indicating the directory to save the figures in +#' +#' @return a ggplot object +#' @export +get_plot_hub_perf_heatmap <- function(scores, + fig_file_dir) { + scores_summary <- scores |> + dplyr::filter( + model %in% c("cfa-wwrenewal(retro)", "cfa-hosponlyrenewal(retro)") + ) |> + dplyr::group_by(forecast_date, location_name, model) |> + dplyr::summarise(avg_wis = mean(interval_score)) + + p <- ggplot(scores_summary) + + geom_tile(aes(x = forecast_date, y = location_name, fill = avg_wis)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + midpoint = mean(scores_summary$avg_wis), + guide = "colourbar", aesthetics = "fill" + ) + + facet_wrap(~model) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 3 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Avg WIS") + + ggtitle(glue::glue("Average WIS by forecast date and location")) + + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_heatmap_wis.png") + ) + ) + return(p) +} + +#' Plot a heatmap of the avg forecast performance by locations and forecast date +#' for the head-to-head comparison +#' +#' @param scores A tibble of daily scores by forecast date, location, and model +#' @param fig_file_dir A string indicating the directory to save the figures in +#' +#' @return a ggplot object +#' @export +get_plot_comb_perf_heatmap <- function(scores, + fig_file_dir) { + scores_summary <- scores |> + dplyr::filter( + model %in% c("ww", "hosp") + ) |> + dplyr::group_by(forecast_date, location, model) |> + dplyr::summarise(avg_crps = mean(crps)) + + p <- ggplot(scores_summary) + + geom_tile(aes(x = forecast_date, y = location, fill = avg_crps)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + midpoint = mean(scores_summary$avg_crps), + guide = "colourbar", aesthetics = "fill" + ) + + facet_wrap(~model) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 3 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Avg CRPS") + + ggtitle(glue::glue("Average CRPS by forecast date and location")) + + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_heatmap_crps.png") + ) + ) + return(p) +} From 6354bcd55822cbe25f5bb303f5a4c4e38144f00a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 21:22:40 +0000 Subject: [PATCH 024/110] add metadata and heatmaps of metadata --- _targets_eval_postprocessing.R | 25 +++++++ wweval/NAMESPACE | 2 + wweval/R/supplement_analyses_and_figs.R | 95 ++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 417f2de4..7e7373f7 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -516,6 +516,19 @@ manuscript_figures <- list( table_of_loc_dates_w_ww ) ), + tar_target( + name = summary_metadata, + command = get_summary_metadata( + granular_ww_metadata_used + ) + ), + tar_target( + name = sfig_heatmap_metadata_comp, + command = get_heatmap_metadata( + granular_ww_metadata_used, + fig_file_dir = eval_config$ms_fig_dir + ) + ), tar_target( name = list_of_summary_ww_tables, command = get_summary_ww_table( @@ -1493,6 +1506,18 @@ benchmarks <- list( # Supplement ---------------------------------------------------------- # Make some tables with summary stats to include in results supp_targets <- list( + tar_target(sfig_hub_perf_heatmap, + command = get_plot_hub_perf_heatmap( + scores = summarized_scores_oct_mar, + fig_file_dir = eval_config$ms_fig_dir + ) + ), + tar_target(sfig_comb_perf_heatmap, + command = get_plot_comb_perf_heatmap( + scores = scores_filtered, + fig_file_dir = eval_config$ms_fig_dir + ) + ), tar_target( name = sfig_bias_over_time_comparison, command = get_plot_bias_over_time(scores_filtered, diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index 81487ab5..d579beec 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -27,6 +27,7 @@ export(get_epidemic_phases_from_rt) export(get_filepath) export(get_full_scores) export(get_growth_rate_plot) +export(get_heatmap_metadata) export(get_heatmap_relative_wis) export(get_heatmap_scores) export(get_input_hosp_data) @@ -56,6 +57,7 @@ export(get_secret) export(get_state_level_quantiles) export(get_state_level_ww_quantiles) export(get_stats_improved_forecasts) +export(get_summary_metadata) export(get_summary_ww_table) export(get_table_sufficient_ww) export(get_ww_data_flags) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 715c0f07..d2a9e468 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -750,7 +750,7 @@ get_plot_hub_perf_heatmap <- function(scores, facet_wrap(~model) + get_plot_theme( x_axis_dates = TRUE, - y_axis_text_size = 3 + y_axis_text_size = 4 ) + scale_x_date( date_breaks = "1 week", @@ -797,7 +797,7 @@ get_plot_comb_perf_heatmap <- function(scores, facet_wrap(~model) + get_plot_theme( x_axis_dates = TRUE, - y_axis_text_size = 3 + y_axis_text_size = 4 ) + scale_x_date( date_breaks = "1 week", @@ -816,3 +816,94 @@ get_plot_comb_perf_heatmap <- function(scores, ) return(p) } + +#' Get a summary table of the number of forecasts excluded for each reason +#' +#' @param metadata a tibble containing metadata for each forecast date location +#' +#' @return a 1 row tibble with the number of forecasts for each category +#' @export +get_summary_metadata <- function(metadata) { + metadata_summarized <- metadata |> + dplyr::select( + forecast_date, location, ww_data_present, + ww_exclude_manual, ww_sufficient, + any_flags_hosp, any_flags_ww + ) + + metadata_remove_insuff_ww <- metadata_summarized |> + dplyr::filter(ww_data_present == 1, ww_sufficient == TRUE) + # There are 3 loc-forecast dates with inussifficient ww not included here, + # will fix this eventually but for now just put in total number. + n_insuff_ww <- 1144 - nrow(metadata_remove_insuff_ww) + + metadata_remove_conv_issues <- metadata_remove_insuff_ww |> + dplyr::filter(any_flags_hosp == FALSE, any_flags_ww == FALSE) + + n_conv_issues <- nrow(metadata_remove_insuff_ww) - nrow(metadata_remove_conv_issues) + + metadata_man_excl <- metadata_remove_conv_issues |> + dplyr::filter(ww_exclude_manual == FALSE) + + n_excl <- nrow(metadata_remove_conv_issues) - nrow(metadata_man_excl) + + summary_table <- tibble::tibble(n_insuff_ww, n_conv_issues, n_excl, + n_forecasts = nrow(metadata_man_excl) + ) + + return(summary_table) +} + +#' Get a heatmap of the metadata of reasons for excluding forecasts from analysis +#' +#' @param metadata a tibble of location -forecast date metadata +#' +#' @return a ggplot object with a heatmap colored by reason for excluding +#' @export + +get_heatmap_metadata <- function(metadata, + fig_file_dir) { + metadata_summarized <- metadata |> + dplyr::select( + forecast_date, location, ww_data_present, + ww_exclude_manual, ww_sufficient, + any_flags_hosp, any_flags_ww + ) |> + dplyr::ungroup() |> + dplyr::mutate( + metadata_cat = + case_when( + ww_data_present != 1 ~ "absent or insufficient wastewater", + ww_sufficient != TRUE ~ "absent or insufficient wastewater", + any_flags_ww == TRUE ~ "model had convergence issues", + any_flags_hosp == TRUE ~ "model had convergence issues", + ww_exclude_manual == TRUE ~ "manual exclusion of ww model", + TRUE ~ "both models produced forecasts" + ) + ) + + p <- ggplot(metadata_summarized) + + geom_tile(aes(x = forecast_date, y = location, fill = metadata_cat)) + + scale_fill_discrete() + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Metadata Information") + + ggtitle(glue::glue("Summary of retrospective comparison analysis")) + + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_heatmap_metadata.png") + ) + ) + + return(p) +} From 397457338bbcf6c89e8b80b2b91aef31833d0aa0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 21:31:35 +0000 Subject: [PATCH 025/110] change fig size, add docs --- wweval/R/supplement_analyses_and_figs.R | 2 ++ wweval/man/get_heatmap_metadata.Rd | 17 +++++++++++++++++ wweval/man/get_plot_comb_perf_heatmap.Rd | 21 +++++++++++++++++++++ wweval/man/get_plot_hub_perf_heatmap.Rd | 21 +++++++++++++++++++++ wweval/man/get_summary_metadata.Rd | 17 +++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 wweval/man/get_heatmap_metadata.Rd create mode 100644 wweval/man/get_plot_comb_perf_heatmap.Rd create mode 100644 wweval/man/get_plot_hub_perf_heatmap.Rd create mode 100644 wweval/man/get_summary_metadata.Rd diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index d2a9e468..c20fec6e 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -762,6 +762,7 @@ get_plot_hub_perf_heatmap <- function(scores, ggtitle(glue::glue("Average WIS by forecast date and location")) ggsave(p, + width = 10, height = 6, filename = file.path( fig_file_dir, glue::glue("sfig_heatmap_wis.png") @@ -809,6 +810,7 @@ get_plot_comb_perf_heatmap <- function(scores, ggtitle(glue::glue("Average CRPS by forecast date and location")) ggsave(p, + width = 10, height = 6, filename = file.path( fig_file_dir, glue::glue("sfig_heatmap_crps.png") diff --git a/wweval/man/get_heatmap_metadata.Rd b/wweval/man/get_heatmap_metadata.Rd new file mode 100644 index 00000000..e065f43c --- /dev/null +++ b/wweval/man/get_heatmap_metadata.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_heatmap_metadata} +\alias{get_heatmap_metadata} +\title{Get a heatmap of the metadata of reasons for excluding forecasts from analysis} +\usage{ +get_heatmap_metadata(metadata) +} +\arguments{ +\item{metadata}{a tibble of location -forecast date metadata} +} +\value{ +a ggplot object with a heatmap colored by reason for excluding +} +\description{ +Get a heatmap of the metadata of reasons for excluding forecasts from analysis +} diff --git a/wweval/man/get_plot_comb_perf_heatmap.Rd b/wweval/man/get_plot_comb_perf_heatmap.Rd new file mode 100644 index 00000000..ed6da6ff --- /dev/null +++ b/wweval/man/get_plot_comb_perf_heatmap.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_plot_comb_perf_heatmap} +\alias{get_plot_comb_perf_heatmap} +\title{Plot a heatmap of the avg forecast performance by locations and forecast date +for the head-to-head comparison} +\usage{ +get_plot_comb_perf_heatmap(scores, fig_file_dir) +} +\arguments{ +\item{scores}{A tibble of daily scores by forecast date, location, and model} + +\item{fig_file_dir}{A string indicating the directory to save the figures in} +} +\value{ +a ggplot object +} +\description{ +Plot a heatmap of the avg forecast performance by locations and forecast date +for the head-to-head comparison +} diff --git a/wweval/man/get_plot_hub_perf_heatmap.Rd b/wweval/man/get_plot_hub_perf_heatmap.Rd new file mode 100644 index 00000000..b2e58301 --- /dev/null +++ b/wweval/man/get_plot_hub_perf_heatmap.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_plot_hub_perf_heatmap} +\alias{get_plot_hub_perf_heatmap} +\title{Plot a heatmap of the avg forecast performance by locations and forecast date +for the Hub submissions} +\usage{ +get_plot_hub_perf_heatmap(scores, fig_file_dir) +} +\arguments{ +\item{scores}{A tibble of daily scores by forecast date, location, and model} + +\item{fig_file_dir}{A string indicating the directory to save the figures in} +} +\value{ +a ggplot object +} +\description{ +Plot a heatmap of the avg forecast performance by locations and forecast date +for the Hub submissions +} diff --git a/wweval/man/get_summary_metadata.Rd b/wweval/man/get_summary_metadata.Rd new file mode 100644 index 00000000..66b9482b --- /dev/null +++ b/wweval/man/get_summary_metadata.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_summary_metadata} +\alias{get_summary_metadata} +\title{Get a summary table of the number of forecasts excluded for each reason} +\usage{ +get_summary_metadata(metadata) +} +\arguments{ +\item{metadata}{a tibble containing metadata for each forecast date location} +} +\value{ +a 1 row tibble with the number of forecasts for each category +} +\description{ +Get a summary table of the number of forecasts excluded for each reason +} From ec10a14b2a61f94a3d37c2a28ea422b83954f1a5 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 21:49:44 +0000 Subject: [PATCH 026/110] add docs --- wweval/man/get_heatmap_metadata.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/man/get_heatmap_metadata.Rd b/wweval/man/get_heatmap_metadata.Rd index e065f43c..dbf0efe8 100644 --- a/wweval/man/get_heatmap_metadata.Rd +++ b/wweval/man/get_heatmap_metadata.Rd @@ -4,7 +4,7 @@ \alias{get_heatmap_metadata} \title{Get a heatmap of the metadata of reasons for excluding forecasts from analysis} \usage{ -get_heatmap_metadata(metadata) +get_heatmap_metadata(metadata, fig_file_dir) } \arguments{ \item{metadata}{a tibble of location -forecast date metadata} From cd8f8e84d5723b04ac01dd16d9ec0621b6b354e5 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 21:54:53 +0000 Subject: [PATCH 027/110] update to rerun for 3 forecast date locs that fail wwinference checks --- wweval/R/eval_fit.R | 46 ++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/wweval/R/eval_fit.R b/wweval/R/eval_fit.R index a98b4dbb..100d0c30 100644 --- a/wweval/R/eval_fit.R +++ b/wweval/R/eval_fit.R @@ -82,25 +82,33 @@ eval_fit_ww <- function(config_index, ## Use wwinference to fit the model------------------------------------------ if (!is.null(input_ww_data)) { - ww_fit_obj <- wwinference::wwinference( - ww_data = input_ww_data, - count_data = input_hosp_data, - forecast_date = forecast_date, - calibration_time = eval_config$calibration_time, - forecast_horizon = eval_config$forecast_time, - model_spec = wwinference::get_model_spec( - generation_interval = eval_config$generation_interval, - inf_to_count_delay = wwinference::default_covid_inf_to_hosp, # eval_config$inf_to_hosp, - infection_feedback_pmf = eval_config$infection_feedback_pmf, - params = params - ), - fit_opts = list( - seed = eval_config$seed, - iter_sampling = eval_config$iter_sampling, - adapt_delta = eval_config$adapt_delta, - chains = eval_config$n_chains, - max_treedepth = eval_config$max_treedepth - ) + ww_fit_obj <- tryCatch( + { + wwinference::wwinference( + ww_data = input_ww_data, + count_data = input_hosp_data, + forecast_date = forecast_date, + calibration_time = eval_config$calibration_time, + forecast_horizon = eval_config$forecast_time, + model_spec = wwinference::get_model_spec( + generation_interval = eval_config$generation_interval, + inf_to_count_delay = wwinference::default_covid_inf_to_hosp, # eval_config$inf_to_hosp, + infection_feedback_pmf = eval_config$infection_feedback_pmf, + params = params + ), + fit_opts = list( + seed = eval_config$seed, + iter_sampling = eval_config$iter_sampling, + adapt_delta = eval_config$adapt_delta, + chains = eval_config$n_chains, + max_treedepth = eval_config$max_treedepth + ) + ) + }, + error = function(e) { + # Handle the error + message("Caught an error in wwinference: ", e$message) + } ) } else { # Format as expected from cmdstan object From ad82468d091ddac8c399bbf56a6e465642459ee3 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 15 Nov 2024 22:00:19 +0000 Subject: [PATCH 028/110] fix docs --- wweval/R/supplement_analyses_and_figs.R | 1 + wweval/man/get_heatmap_metadata.Rd | 2 ++ 2 files changed, 3 insertions(+) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index c20fec6e..76814be7 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -859,6 +859,7 @@ get_summary_metadata <- function(metadata) { #' Get a heatmap of the metadata of reasons for excluding forecasts from analysis #' #' @param metadata a tibble of location -forecast date metadata +#' @param fig_file_dir string indicating where to save figs #' #' @return a ggplot object with a heatmap colored by reason for excluding #' @export diff --git a/wweval/man/get_heatmap_metadata.Rd b/wweval/man/get_heatmap_metadata.Rd index dbf0efe8..b197d70d 100644 --- a/wweval/man/get_heatmap_metadata.Rd +++ b/wweval/man/get_heatmap_metadata.Rd @@ -8,6 +8,8 @@ get_heatmap_metadata(metadata, fig_file_dir) } \arguments{ \item{metadata}{a tibble of location -forecast date metadata} + +\item{fig_file_dir}{string indicating where to save figs} } \value{ a ggplot object with a heatmap colored by reason for excluding From d3308ef26183445156ac7eb5c70a49ac7ced372f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 16 Nov 2024 13:00:04 +0000 Subject: [PATCH 029/110] add workaround for wwinference failure --- wweval/R/eval_fit.R | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wweval/R/eval_fit.R b/wweval/R/eval_fit.R index 100d0c30..cc681c6f 100644 --- a/wweval/R/eval_fit.R +++ b/wweval/R/eval_fit.R @@ -118,6 +118,15 @@ eval_fit_ww <- function(config_index, ) } + # If wwinference job fails its due to data not overlapping, replace + # with missing data error for postprocessing to proceed without failure + if (is.null(ww_fit_obj)) { + ww_fit_obj <- list( + fit = + list(result = list(error = "missing ww data")) + ) + } + save_object("ww_fit_obj", output_file_suffix) From f04caddc8baf40bffff347a1b2857514a1f98f38 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 16 Nov 2024 18:36:26 +0000 Subject: [PATCH 030/110] add geom text to heatmap with performance of each forecast --- wweval/R/supplement_analyses_and_figs.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 76814be7..c031ddc4 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -747,6 +747,10 @@ get_plot_hub_perf_heatmap <- function(scores, midpoint = mean(scores_summary$avg_wis), guide = "colourbar", aesthetics = "fill" ) + + geom_text(aes( + x = forecast_date, y = location_name, + label = round(avg_wis, 2) + ), size = 1.5) + facet_wrap(~model) + get_plot_theme( x_axis_dates = TRUE, @@ -795,6 +799,10 @@ get_plot_comb_perf_heatmap <- function(scores, midpoint = mean(scores_summary$avg_crps), guide = "colourbar", aesthetics = "fill" ) + + geom_text(aes( + x = forecast_date, y = location, + label = round(avg_crps, 2) + ), size = 1.5) + facet_wrap(~model) + get_plot_theme( x_axis_dates = TRUE, From c991f0eebc6fa042a585b9d45b0ab1d954f0306a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 16 Nov 2024 20:32:02 +0000 Subject: [PATCH 031/110] add a bunch of summary tables/figures --- wweval/NAMESPACE | 2 ++ wweval/R/ms_fig3.R | 31 ++++++++++++++++ wweval/R/ms_fig4.R | 36 +++++++++++++++++++ wweval/R/ms_fig5.R | 49 ++++++++++++++++++++++++++ wweval/man/get_summary_table_fig3.Rd | 20 +++++++++++ wweval/man/make_fig4_results_table.Rd | 19 ++++++++++ wweval/man/make_fig5_table_and_plot.Rd | 19 ++++++++++ 7 files changed, 176 insertions(+) create mode 100644 wweval/man/get_summary_table_fig3.Rd create mode 100644 wweval/man/make_fig4_results_table.Rd create mode 100644 wweval/man/make_fig5_table_and_plot.Rd diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index d579beec..5267b867 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -79,12 +79,14 @@ export(make_fig4_rel_crps_by_location) export(make_fig4_rel_crps_by_phase) export(make_fig4_rel_crps_over_time) export(make_fig4_rel_crps_overall) +export(make_fig4_results_table) export(make_fig5) export(make_fig5_average_wis) export(make_fig5_density_rank) export(make_fig5_heatmap_relative_wis) export(make_fig5_hub_performance) export(make_fig5_qq_plot) +export(make_fig5_table_and_plot) export(make_qq_plot_overall) export(make_sfig_crps_by_phase) export(nhsn_soda_query) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index e21443a1..0d0905a4 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -1,3 +1,34 @@ +#' Get a summary of a single states crps +#' +#' @param scores tibble of crps scores by location, forecast date, model, +#' horizon day +#' @param locs_to_plot the locations we want summaries for +#' +#' @return a table with mean crps for each model and the relative crps +get_summary_table_fig3 <- function(scores, + locs_to_plot) { + scores_locs <- scores |> + dplyr::filter( + location %in% locs_to_plot + ) |> + dplyr::group_by(model, location) |> + dplyr::summarize( + mean_crps = mean(crps) + ) |> + tidyr::pivot_wider( + id_cols = c("location"), + names_from = "model", + names_prefix = "mean_crps_", + values_from = mean_crps + ) |> + dplyr::mutate( + rel_crps = mean_crps_ww / mean_crps_hosp + ) + + return(scores_locs) +} + + #' Make head to head CRPS distribution comparison plot for a single location #' #' @param scores A tibble of scores by location, forecast date, date and model, diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index f0f67a1e..eff12c68 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -1,3 +1,39 @@ +#' Make a summary of the with and without wastewater comparison scores +#' +#' @param scores a tibble of scores for each model, horizon day, forecast date +#' and location for the subset of forecasts used in the head-to-head comparison +#' +#' @return a list of two tables with summary scores, one overall and one by +#' forecast vs nowcast +#' @export +make_fig4_results_table <- function(scores) { + # Overall avg crps, bias, absolute error etc + scores_overall <- scores |> + dplyr::group_by(model) |> + dplyr::summarise( + avg_crps = mean(crps), + avg_bias = mean(bias), + avg_ae = mean(ae_median) + ) + + # By period (nowcast vs forecast) + scores_by_period <- scores |> + dplyr::group_by(model, period) |> + dplyr::summarise( + avg_crps = mean(crps), + avg_bias = mean(bias), + avg_ae = mean(ae_median) + ) + + scores_tables <- list( + scores_overall = scores_overall, + scores_by_period = scores_by_period + ) + + return(scores_tables) +} + + #' Make a CRPS density plot for a subset of locations #' #' @param scores A tibble of scores by location, forecast date, date and model, diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 5c25008f..5c94952f 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -1,3 +1,52 @@ +#' Make summary table of WIS scores in Hub models overall +#' +#' @param scores quantile based scores from the hub +#' @param fig_file_dir +#' +#' @return A table with the average scores of each model over the time period +#' @export +make_fig5_table_and_plot <- function(scores, + time_period, + fig_file_dir) { + # Overall avg wis, bias, absolute error etc + hub_scores_overall <- scores |> + dplyr::group_by(model) |> + dplyr::summarise( + avg_wis = mean(interval_score), + avg_bias = mean(bias), + avg_ae = mean(ae_median) + ) |> + dplyr::mutate(model = factor(model, + levels = as.character(model)[order(avg_wis)] + )) + + colors <- plot_components() + p <- ggplot(hub_scores_overall) + + geom_bar(aes(x = model, y = avg_wis, fill = model), + stat = "identity", position = "dodge" + ) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_title_size = 8 + ) + + theme(legend.position = "none") + + scale_fill_manual(values = colors$model_colors) + + xlab("") + + ylab("Average WIS") + + ggtitle(glue::glue("Average WIS across forecast dates and locations from {time_period} 2024")) # nolint + + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_bar_chart_{time_period}.png") + ) + ) + + + return(hub_scores_overall) +} + + #' Get plot of WIS over time #' #' @param all_scores Scores from entire time period of interest, including diff --git a/wweval/man/get_summary_table_fig3.Rd b/wweval/man/get_summary_table_fig3.Rd new file mode 100644 index 00000000..c704a885 --- /dev/null +++ b/wweval/man/get_summary_table_fig3.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig3.R +\name{get_summary_table_fig3} +\alias{get_summary_table_fig3} +\title{Get a summary of a single states crps} +\usage{ +get_summary_table_fig3(scores, locs_to_plot) +} +\arguments{ +\item{scores}{tibble of crps scores by location, forecast date, model, +horizon day} + +\item{locs_to_plot}{the locations we want summaries for} +} +\value{ +a table with mean crps for each model and the relative crps +} +\description{ +Get a summary of a single states crps +} diff --git a/wweval/man/make_fig4_results_table.Rd b/wweval/man/make_fig4_results_table.Rd new file mode 100644 index 00000000..06369636 --- /dev/null +++ b/wweval/man/make_fig4_results_table.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig4.R +\name{make_fig4_results_table} +\alias{make_fig4_results_table} +\title{Make a summary of the with and without wastewater comparison scores} +\usage{ +make_fig4_results_table(scores) +} +\arguments{ +\item{scores}{a tibble of scores for each model, horizon day, forecast date +and location for the subset of forecasts used in the head-to-head comparison} +} +\value{ +a list of two tables with summary scores, one overall and one by +forecast vs nowcast +} +\description{ +Make a summary of the with and without wastewater comparison scores +} diff --git a/wweval/man/make_fig5_table_and_plot.Rd b/wweval/man/make_fig5_table_and_plot.Rd new file mode 100644 index 00000000..86df2aac --- /dev/null +++ b/wweval/man/make_fig5_table_and_plot.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig5.R +\name{make_fig5_table_and_plot} +\alias{make_fig5_table_and_plot} +\title{Make summary table of WIS scores in Hub models overall} +\usage{ +make_fig5_table_and_plot(scores, time_period, fig_file_dir) +} +\arguments{ +\item{scores}{quantile based scores from the hub} + +\item{fig_file_dir}{} +} +\value{ +A table with the average scores of each model over the time period +} +\description{ +Make summary table of WIS scores in Hub models overall +} From c136699d8beb95c8ecc21683c8bece9d9d741cea Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 16 Nov 2024 20:54:37 +0000 Subject: [PATCH 032/110] write function to get ind forecast score --- wweval/R/ms_fig3.R | 24 ++++++++++++++++++++++++ wweval/man/get_ind_forecast_score.Rd | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 wweval/man/get_ind_forecast_score.Rd diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 0d0905a4..8ef427c3 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -28,6 +28,30 @@ get_summary_table_fig3 <- function(scores, return(scores_locs) } +#' Get an individual forecast score summary for a particular +#' forecast date and location +#' +#' @param scores A tibble of all forecast date- location- model +#' forecast perfomance scores +#' @param loc the location of interest +#' @param this_forecast_date the forecast date of interest +#' +#' @return A tibble of mean scores by models +get_ind_forecast_score <- function(scores, + loc, + this_forecast_date) { + ind_score <- scores |> + dplyr::filter( + location == loc, + forecast_date == this_forecast_date + ) |> + dplyr::group_by(model) |> + dplyr::summarize( + mean_crps = mean(crps) + ) + return(ind_score) +} + #' Make head to head CRPS distribution comparison plot for a single location #' diff --git a/wweval/man/get_ind_forecast_score.Rd b/wweval/man/get_ind_forecast_score.Rd new file mode 100644 index 00000000..a3c11927 --- /dev/null +++ b/wweval/man/get_ind_forecast_score.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig3.R +\name{get_ind_forecast_score} +\alias{get_ind_forecast_score} +\title{Get an individual forecast score summary for a particular +forecast date and location} +\usage{ +get_ind_forecast_score(scores, loc, this_forecast_date) +} +\arguments{ +\item{scores}{A tibble of all forecast date- location- model +forecast perfomance scores} + +\item{loc}{the location of interest} + +\item{this_forecast_date}{the forecast date of interest} +} +\value{ +A tibble of mean scores by models +} +\description{ +Get an individual forecast score summary for a particular +forecast date and location +} From 0576be4f2bd1633dd56c26b22b70d8aa0f60bd67 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 16 Nov 2024 21:57:55 +0000 Subject: [PATCH 033/110] add function to get rel crps of ind location --- wweval/R/ms_fig4.R | 20 ++++++++++++++++++++ wweval/man/get_loc_rel_crps.Rd | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 wweval/man/get_loc_rel_crps.Rd diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index eff12c68..77ef183d 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -231,6 +231,26 @@ make_fig4_admissions_overall <- function(eval_hosp_data, return(p) } +#' Get the mean relative crps for a location +#' +#' @param scores tibble of scores by day forecast day model +#' @param locs loc to get mean relative score for +#' +#' @return table of mean relative score for each location +get_loc_rel_crps <- function(scores, locs) { + relative_crps <- scores |> + dplyr::filter(location %in% locs) |> + compute_relative_crps(id_cols = c( + "location", "forecast_date", "date" + )) |> + dplyr::group_by(location) |> + dplyr::summarise(mean = mean(rel_crps)) + + return(relative_crps) +} + + + #' Make figure that stratifies scores by location across forecast dates #' #' @param scores A tibble of scores by location, forecast date, date and model, diff --git a/wweval/man/get_loc_rel_crps.Rd b/wweval/man/get_loc_rel_crps.Rd new file mode 100644 index 00000000..4fa19427 --- /dev/null +++ b/wweval/man/get_loc_rel_crps.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig4.R +\name{get_loc_rel_crps} +\alias{get_loc_rel_crps} +\title{Get the mean relative crps for a location} +\usage{ +get_loc_rel_crps(scores, locs) +} +\arguments{ +\item{scores}{tibble of scores by day forecast day model} + +\item{locs}{loc to get mean relative score for} +} +\value{ +table of mean relative score for each location +} +\description{ +Get the mean relative crps for a location +} From 8927d334472e74e5f216e3c0c5a748b6cf982edd Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sat, 16 Nov 2024 23:44:54 +0000 Subject: [PATCH 034/110] add rel_crps heatmap to supplement --- wweval/NAMESPACE | 1 + wweval/R/supplement_analyses_and_figs.R | 58 +++++++++++++++++++++++-- wweval/man/get_plot_rel_crps_heatmap.Rd | 21 +++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 wweval/man/get_plot_rel_crps_heatmap.Rd diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index 5267b867..48f8df57 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -44,6 +44,7 @@ export(get_plot_hub_perf_heatmap) export(get_plot_hub_performance) export(get_plot_quantile_comparison) export(get_plot_raw_scores) +export(get_plot_rel_crps_heatmap) export(get_plot_score_by_horizon_t) export(get_plot_scores_w_data) export(get_plot_summarized_scores) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index c031ddc4..7c7bddf1 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -786,9 +786,6 @@ get_plot_hub_perf_heatmap <- function(scores, get_plot_comb_perf_heatmap <- function(scores, fig_file_dir) { scores_summary <- scores |> - dplyr::filter( - model %in% c("ww", "hosp") - ) |> dplyr::group_by(forecast_date, location, model) |> dplyr::summarise(avg_crps = mean(crps)) @@ -827,6 +824,61 @@ get_plot_comb_perf_heatmap <- function(scores, return(p) } +#' Plot a heatmap of the relative crps by locations and forecast date +#' for the head-to-head comparison +#' +#' @param scores A tibble of daily scores by forecast date, location, and model +#' @param fig_file_dir A string indicating the directory to save the figures in +#' +#' @return a ggplot object +#' @export +get_plot_rel_crps_heatmap <- function(scores, + fig_file_dir) { + scores_summary <- scores |> + compute_relative_crps(id_cols = c( + "location", + "forecast_date", "date" + )) |> + dplyr::group_by(location, forecast_date) |> + dplyr::summarize( + mean_rel_crps = mean(rel_crps) + ) + + + p <- ggplot(scores_summary) + + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + midpoint = mean(scores_summary$mean_rel_crps), + guide = "colourbar", aesthetics = "fill" + ) + + geom_text(aes( + x = forecast_date, y = location, + label = round(mean_rel_crps, 2) + ), size = 1.5) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Relative CRPS") + + ggtitle(glue::glue("Mean relative CRPS by forecast date and location")) + + ggsave(p, + width = 7, height = 6, + filename = file.path( + fig_file_dir, + glue::glue("sfig_heatmap_rel_crps.png") + ) + ) + return(p) +} + #' Get a summary table of the number of forecasts excluded for each reason #' #' @param metadata a tibble containing metadata for each forecast date location diff --git a/wweval/man/get_plot_rel_crps_heatmap.Rd b/wweval/man/get_plot_rel_crps_heatmap.Rd new file mode 100644 index 00000000..a3b03b13 --- /dev/null +++ b/wweval/man/get_plot_rel_crps_heatmap.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_plot_rel_crps_heatmap} +\alias{get_plot_rel_crps_heatmap} +\title{Plot a heatmap of the relative crps by locations and forecast date +for the head-to-head comparison} +\usage{ +get_plot_rel_crps_heatmap(scores, fig_file_dir) +} +\arguments{ +\item{scores}{A tibble of daily scores by forecast date, location, and model} + +\item{fig_file_dir}{A string indicating the directory to save the figures in} +} +\value{ +a ggplot object +} +\description{ +Plot a heatmap of the relative crps by locations and forecast date +for the head-to-head comparison +} From 804eb385c4c08621d462f47aa136bbc4b7ae7c79 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 12:59:31 +0000 Subject: [PATCH 035/110] make rel_crps heatmap log scale and mid point = 1 --- wweval/R/supplement_analyses_and_figs.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 7c7bddf1..3bbcf83c 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -849,7 +849,8 @@ get_plot_rel_crps_heatmap <- function(scores, geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + scale_fill_gradient2( high = "red", mid = "white", low = "blue", - midpoint = mean(scores_summary$mean_rel_crps), + transform = "log2", + midpoint = 1, guide = "colourbar", aesthetics = "fill" ) + geom_text(aes( From 0a28c09a20c855bcbb0511bb715a38a9d3c697bd Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 13:00:50 +0000 Subject: [PATCH 036/110] don't exclude the manually excluded ones in retro head to head comparison --- _targets_eval_postprocessing.R | 66 +++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 7e7373f7..f092f25b 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -406,14 +406,6 @@ head_to_head_targets <- list( dplyr::left_join(table_of_loc_dates_w_ww, by = c("location", "forecast_date") ) |> - dplyr::anti_join( - ww_forecast_date_locs_to_excl |> - dplyr::mutate(forecast_date = lubridate::ymd(forecast_date)), - by = c( - "location", - "forecast_date" - ) - ) |> dplyr::filter(ww_sufficient) |> dplyr::left_join( convergence_df, @@ -637,6 +629,29 @@ manuscript_figures <- list( ), ## Fig 3------------------------------------------------- + tar_target( + name = summary_table_crps, + command = get_summary_table_fig3( + scores_filtered, + locs_to_plot + ) + ), + tar_target( + name = ex_CA_forecast_score, + command = get_ind_forecast_score( + scores_filtered, + "CA", + "2024-02-05" + ) + ), + tar_target( + name = ex_WA_forecast_score, + command = get_ind_forecast_score( + scores_filtered, + "WA", + "2023-11-06" + ) + ), tar_target( ### First location -------- name = fig3_crps_single_loc1, @@ -915,6 +930,12 @@ manuscript_figures <- list( ## Fig 4------------------------------------------------ + tar_target( + name = fig4_results_tables, + command = make_fig4_results_table( + scores_filtered + ) + ), tar_target( name = fig4_rel_crps_over_time, command = make_fig4_rel_crps_over_time( @@ -922,6 +943,13 @@ manuscript_figures <- list( horizons_to_show = "overall" ) ), + tar_target( + name = loc_summary, + command = get_loc_rel_crps( + scores_filtered, + locs = c("DC", "OH") + ) + ), tar_target( name = fig4_natl_admissions, command = make_fig4_admissions_overall( @@ -1356,6 +1384,22 @@ hub_targets <- list( ## Hub comparison plots ------------------------------------------------------ ## Fig 5------------------------------------------------------------------- hub_comparison_plots <- list( + tar_target( + name = fig5_summary_table, + command = make_fig5_table_and_plot( + combine_scores_oct_mar, + time_period = "Oct-Mar", + fig_file_dir = eval_config$ms_fig_dir + ) + ), + tar_target( + name = fig5_summary_table_Feb_Mar, + command = make_fig5_table_and_plot( + combine_scores_feb_mar, + time_period = "Feb-Mar", + fig_file_dir = eval_config$ms_fig_dir + ) + ), tar_target( name = summarized_scores_oct_mar, command = combine_scores_oct_mar |> @@ -1518,6 +1562,12 @@ supp_targets <- list( fig_file_dir = eval_config$ms_fig_dir ) ), + tar_target(sfig_rel_crps_heatmap, + command = get_plot_rel_crps_heatmap( + scores = scores_filtered, + fig_file_dir = eval_config$ms_fig_dir + ) + ), tar_target( name = sfig_bias_over_time_comparison, command = get_plot_bias_over_time(scores_filtered, From 1ec6022cc5b4531d603047d58661bffd4ff7d3fc Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 13:21:42 +0000 Subject: [PATCH 037/110] make metadata heatmap for retro comparison --- _targets_eval_postprocessing.R | 1 + wweval/R/supplement_analyses_and_figs.R | 49 +++++++++++++++++-------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index f092f25b..8f161647 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -518,6 +518,7 @@ manuscript_figures <- list( name = sfig_heatmap_metadata_comp, command = get_heatmap_metadata( granular_ww_metadata_used, + type_of_analysis = "retro_comparison", fig_file_dir = eval_config$ms_fig_dir ) ), diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 3bbcf83c..14c97eaa 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -896,9 +896,8 @@ get_summary_metadata <- function(metadata) { metadata_remove_insuff_ww <- metadata_summarized |> dplyr::filter(ww_data_present == 1, ww_sufficient == TRUE) - # There are 3 loc-forecast dates with inussifficient ww not included here, - # will fix this eventually but for now just put in total number. - n_insuff_ww <- 1144 - nrow(metadata_remove_insuff_ww) + + n_insuff_ww <- nrow(metadata_summarized) - nrow(metadata_remove_insuff_ww) metadata_remove_conv_issues <- metadata_remove_insuff_ww |> dplyr::filter(any_flags_hosp == FALSE, any_flags_ww == FALSE) @@ -920,12 +919,14 @@ get_summary_metadata <- function(metadata) { #' Get a heatmap of the metadata of reasons for excluding forecasts from analysis #' #' @param metadata a tibble of location -forecast date metadata +#' @param type_of_analysis either "retro_comparison" or "hub_comparison" #' @param fig_file_dir string indicating where to save figs #' #' @return a ggplot object with a heatmap colored by reason for excluding #' @export get_heatmap_metadata <- function(metadata, + type_of_analysis, fig_file_dir) { metadata_summarized <- metadata |> dplyr::select( @@ -933,20 +934,36 @@ get_heatmap_metadata <- function(metadata, ww_exclude_manual, ww_sufficient, any_flags_hosp, any_flags_ww ) |> - dplyr::ungroup() |> - dplyr::mutate( - metadata_cat = - case_when( - ww_data_present != 1 ~ "absent or insufficient wastewater", - ww_sufficient != TRUE ~ "absent or insufficient wastewater", - any_flags_ww == TRUE ~ "model had convergence issues", - any_flags_hosp == TRUE ~ "model had convergence issues", - ww_exclude_manual == TRUE ~ "manual exclusion of ww model", - TRUE ~ "both models produced forecasts" - ) - ) + dplyr::ungroup() + + if (type_of_analysis == "retro_comparison") { + metadata_final <- metadata_summarized |> + dplyr::mutate( + metadata_cat = + case_when( + ww_data_present != 1 ~ "absent or insufficient wastewater", + ww_sufficient != TRUE ~ "absent or insufficient wastewater", + any_flags_ww == TRUE ~ "model had convergence issues", + any_flags_hosp == TRUE ~ "model had convergence issues", + TRUE ~ "both models produced forecasts" + ) + ) + } else { + metadata_final <- metadata_summarized |> + dplyr::mutate( + metadata_cat = + case_when( + ww_data_present != 1 ~ "absent or insufficient wastewater", + ww_sufficient != TRUE ~ "absent or insufficient wastewater", + any_flags_ww == TRUE ~ "model had convergence issues", + any_flags_hosp == TRUE ~ "model had convergence issues", + ww_exclude_manual == TRUE ~ "manual exclusion of ww model", + TRUE ~ "both models produced forecasts" + ) + ) + } - p <- ggplot(metadata_summarized) + + p <- ggplot(metadata_final) + geom_tile(aes(x = forecast_date, y = location, fill = metadata_cat)) + scale_fill_discrete() + get_plot_theme( From c09407a53ae3252ef17c86c0d79272d733643296 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 13:50:08 +0000 Subject: [PATCH 038/110] add hub model inclusion figure --- _targets_eval_postprocessing.R | 7 +++ wweval/NAMESPACE | 1 + wweval/R/supplement_analyses_and_figs.R | 72 ++++++++++++++++++++++++- wweval/man/get_heatmap_metadata.Rd | 4 +- wweval/man/get_heatmap_metadata_hub.Rd | 19 +++++++ 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 wweval/man/get_heatmap_metadata_hub.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 8f161647..e18fe0ec 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -522,6 +522,13 @@ manuscript_figures <- list( fig_file_dir = eval_config$ms_fig_dir ) ), + tar_target( + name = sfig_heatmap_metadata_hub, + command = get_heatmap_metadata_hub( + granular_ww_metadata_used, + fig_file_dir = eval_config$ms_fig_dir + ) + ), tar_target( name = list_of_summary_ww_tables, command = get_summary_ww_table( diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index 48f8df57..0343aad3 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -28,6 +28,7 @@ export(get_filepath) export(get_full_scores) export(get_growth_rate_plot) export(get_heatmap_metadata) +export(get_heatmap_metadata_hub) export(get_heatmap_relative_wis) export(get_heatmap_scores) export(get_input_hosp_data) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 14c97eaa..b1a66beb 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -924,7 +924,6 @@ get_summary_metadata <- function(metadata) { #' #' @return a ggplot object with a heatmap colored by reason for excluding #' @export - get_heatmap_metadata <- function(metadata, type_of_analysis, fig_file_dir) { @@ -988,3 +987,74 @@ get_heatmap_metadata <- function(metadata, return(p) } + +#' Get a heatmap of the metadata of Hub models submitted +#' +#' @param metadata a tibble of location -forecast date metadata +#' @param fig_file_dir string indicating where to save figs +#' +#' @return a ggplot object with a heatmap colored by reason for excluding +#' @export +get_heatmap_metadata_hub <- function(metadata, + fig_file_dir) { + metadata_summarized <- metadata |> + dplyr::select( + forecast_date, location, ww_data_present, + ww_exclude_manual, ww_sufficient, + any_flags_hosp, any_flags_ww + ) |> + dplyr::ungroup() |> + dplyr::mutate( + model_submitted = + dplyr::case_when( + ww_data_present != 1 ~ "hosp", + ww_sufficient != TRUE ~ "hosp", + any_flags_ww == TRUE ~ "hosp", + ww_exclude_manual == TRUE ~ "hosp", + TRUE ~ "ww" + ) + ) |> + dplyr::mutate( + model_name = "cfa-wwrenewal(retro)" + ) + + metadata_hosp_only <- metadata_summarized |> + dplyr::mutate( + model_submitted = "hosp", + model_name = "cfa-hosponlyrenewal(retro)" + ) + metadata_real_time <- metadata_summarized |> + dplyr::filter(forecast_date >= "2024-02-05") |> + dplyr::mutate(model_name = "cfa-wwrenewal(real_time)") + + all_metadata <- dplyr::bind_rows( + metadata_summarized, metadata_hosp_only, + metadata_real_time + ) + colors <- plot_components() + p <- ggplot(all_metadata) + + geom_tile(aes(x = forecast_date, y = location, fill = model_submitted)) + + scale_fill_discrete() + + facet_wrap(~model_name) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + theme(legend.position = "bottom") + + xlab("") + + ylab("Location") + + labs(fill = "Model submitted") + + ggtitle(glue::glue("Summary of models used in Hub analysis")) + + ggsave(p, + height = 7, width = 12, + filename = file.path( + fig_file_dir, + glue::glue("sfig_heatmap_hub_metadata.png") + ) + ) +} diff --git a/wweval/man/get_heatmap_metadata.Rd b/wweval/man/get_heatmap_metadata.Rd index b197d70d..b51cdf4a 100644 --- a/wweval/man/get_heatmap_metadata.Rd +++ b/wweval/man/get_heatmap_metadata.Rd @@ -4,11 +4,13 @@ \alias{get_heatmap_metadata} \title{Get a heatmap of the metadata of reasons for excluding forecasts from analysis} \usage{ -get_heatmap_metadata(metadata, fig_file_dir) +get_heatmap_metadata(metadata, type_of_analysis, fig_file_dir) } \arguments{ \item{metadata}{a tibble of location -forecast date metadata} +\item{type_of_analysis}{either "retro_comparison" or "hub_comparison"} + \item{fig_file_dir}{string indicating where to save figs} } \value{ diff --git a/wweval/man/get_heatmap_metadata_hub.Rd b/wweval/man/get_heatmap_metadata_hub.Rd new file mode 100644 index 00000000..2d39c4dd --- /dev/null +++ b/wweval/man/get_heatmap_metadata_hub.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_heatmap_metadata_hub} +\alias{get_heatmap_metadata_hub} +\title{Get a heatmap of the metadata of Hub models submitted} +\usage{ +get_heatmap_metadata_hub(metadata, fig_file_dir) +} +\arguments{ +\item{metadata}{a tibble of location -forecast date metadata} + +\item{fig_file_dir}{string indicating where to save figs} +} +\value{ +a ggplot object with a heatmap colored by reason for excluding +} +\description{ +Get a heatmap of the metadata of Hub models submitted +} From e7f2e5986225ea0b942d613d6c41f7fe7100c8c4 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 16:14:13 +0000 Subject: [PATCH 039/110] fix docs --- wweval/R/ms_fig5.R | 2 +- wweval/man/make_fig5_table_and_plot.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 5c94952f..2b651250 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -1,7 +1,7 @@ #' Make summary table of WIS scores in Hub models overall #' #' @param scores quantile based scores from the hub -#' @param fig_file_dir +#' @param fig_file_dir directory to save figure #' #' @return A table with the average scores of each model over the time period #' @export diff --git a/wweval/man/make_fig5_table_and_plot.Rd b/wweval/man/make_fig5_table_and_plot.Rd index 86df2aac..e4a04758 100644 --- a/wweval/man/make_fig5_table_and_plot.Rd +++ b/wweval/man/make_fig5_table_and_plot.Rd @@ -9,7 +9,7 @@ make_fig5_table_and_plot(scores, time_period, fig_file_dir) \arguments{ \item{scores}{quantile based scores from the hub} -\item{fig_file_dir}{} +\item{fig_file_dir}{directory to save figure} } \value{ A table with the average scores of each model over the time period From e9857d229968722ac89b3e5a7b763553a7c07e0e Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 19:21:36 +0000 Subject: [PATCH 040/110] add description of time period --- wweval/R/ms_fig5.R | 1 + wweval/man/make_fig5_table_and_plot.Rd | 2 ++ 2 files changed, 3 insertions(+) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 2b651250..a91fd1b9 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -1,6 +1,7 @@ #' Make summary table of WIS scores in Hub models overall #' #' @param scores quantile based scores from the hub +#' @param time_period string indicating which time period to make the plot for #' @param fig_file_dir directory to save figure #' #' @return A table with the average scores of each model over the time period diff --git a/wweval/man/make_fig5_table_and_plot.Rd b/wweval/man/make_fig5_table_and_plot.Rd index e4a04758..6810ed76 100644 --- a/wweval/man/make_fig5_table_and_plot.Rd +++ b/wweval/man/make_fig5_table_and_plot.Rd @@ -9,6 +9,8 @@ make_fig5_table_and_plot(scores, time_period, fig_file_dir) \arguments{ \item{scores}{quantile based scores from the hub} +\item{time_period}{string indicating which time period to make the plot for} + \item{fig_file_dir}{directory to save figure} } \value{ From e50f3eb4f6e2389d1bfc2c57f7af0efe509cf812 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Sun, 17 Nov 2024 19:21:59 +0000 Subject: [PATCH 041/110] swap model to be visualized --- _targets_eval_postprocessing.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index e18fe0ec..c43b7405 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1429,7 +1429,7 @@ hub_comparison_plots <- list( tar_target( name = models_to_plot, command = c( - "UMass-gbq", + "UMass-sarix", "CMU-TimeSeries", "COVIDhub-4_week_ensemble", "cfa-wwrenewal(real-time)", From 1f7c6234bb455788dcfd39f6398147e0ee3cbc49 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 20 Nov 2024 17:10:11 +0000 Subject: [PATCH 042/110] update description --- wweval/DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/DESCRIPTION b/wweval/DESCRIPTION index a3d4a9da..bbc6a998 100644 --- a/wweval/DESCRIPTION +++ b/wweval/DESCRIPTION @@ -90,6 +90,6 @@ Config/Needs/check: rcmdcheck, testthat RoxygenNote: 7.3.2 Remotes: stan-dev/cmdstanr, - wwinference=CDCgov/ww-inference-model@227-inf-feedback-mod, + wwinference=CDCgov/ww-inference-model@v0.1.1, github::epiforecasts/scoringutils@v1.2.2 LazyData: true From 1ff9638007d5f62c551e866e2169044384532946 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:12:34 -0500 Subject: [PATCH 043/110] Issue 209: Compute the relative scores in real-time (#210) --- _targets_eval_postprocessing.R | 31 +++++ src/create_table_of_run_ids.R | 18 +++ src/setup_eval.R | 2 +- src/write_eval_config.R | 19 ++- wweval/NAMESPACE | 2 + wweval/R/score_real_time_outputs.R | 160 ++++++++++++++++++++++ wweval/R/supplement_analyses_and_figs.R | 91 ++++++++++++ wweval/man/get_plot_rel_crps_real_time.Rd | 20 +++ wweval/man/get_rel_crps_real_time.Rd | 18 +++ wweval/man/score_real_time_outputs.Rd | 37 +++++ 10 files changed, 392 insertions(+), 6 deletions(-) create mode 100644 src/create_table_of_run_ids.R create mode 100644 wweval/R/score_real_time_outputs.R create mode 100644 wweval/man/get_plot_rel_crps_real_time.Rd create mode 100644 wweval/man/get_rel_crps_real_time.Rd create mode 100644 wweval/man/score_real_time_outputs.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index c43b7405..54474770 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1639,6 +1639,37 @@ supp_targets <- list( scores = scores_filtered, threshold = 0.1 ) + ), + tar_target( + name = real_time_scores_both_models, + command = score_real_time_outputs( + real_time_output_dir = eval_config$real_time_output_dir, + table_of_run_ids = as.data.frame(eval_config$table_of_run_ids), + locations = unique(eval_config$location_ww), + dates = as.character(seq( + from = lubridate::ymd("2024-02-05"), + to = lubridate::ymd("2024-03-11"), + by = "week" + )), + eval_data = eval_hosp_data + ) + ), + tar_target( + name = rel_scores, + command = get_rel_crps_real_time(real_time_scores_both_models) + ), + tar_target( + name = plot_real_time_rel_crps, + command = get_plot_rel_crps_real_time( + rel_scores, + fig_file_dir = eval_config$ms_fig_dir + ) + ), + tar_target( + name = overall_rel_crps, + command = rel_scores |> + dplyr::ungroup() |> + dplyr::summarise(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) ) ) diff --git a/src/create_table_of_run_ids.R b/src/create_table_of_run_ids.R new file mode 100644 index 00000000..5bc6d197 --- /dev/null +++ b/src/create_table_of_run_ids.R @@ -0,0 +1,18 @@ +# Create a table of model run ids that correspond to the prod run for each +# real-time forecast date + +ids <- c("b84a4", "5ebc5", "bb0b4", "a6e67", "f86b2", "8150f") +forecast_date <- seq( + from = lubridate::ymd("2024-02-05"), + to = lubridate::ymd("2024-03-11"), + by = "week" +) +dates_run <- c( + "2024-02-05", "2024-02-12", + "2024-02-18", "2024-02-25", + "2024-03-02", "2024-03-09" +) + +table_of_run_ids <- tibble::tibble(ids, forecast_date, dates_run) + +saveRDS(table_of_run_ids, "output/real_time_outputs/table_of_run_ids.rds") diff --git a/src/setup_eval.R b/src/setup_eval.R index d92e3d5b..3cb71743 100644 --- a/src/setup_eval.R +++ b/src/setup_eval.R @@ -34,5 +34,5 @@ write_eval_config( overwrite_benchmark = TRUE, # Set as TRUE if want to save outputs of # benchmarking in directory - wwinference_version = "227-inf-feedback-posterior-mod-eta" + wwinference_version = "v0.1.1" ) diff --git a/src/write_eval_config.R b/src/write_eval_config.R index 44ad947c..135bd801 100644 --- a/src/write_eval_config.R +++ b/src/write_eval_config.R @@ -80,15 +80,15 @@ write_eval_config <- function(locations, forecast_dates, # stan_models_dir <- system.file("stan", package = "cfaforecastrenewalww") #nolint stan_models_dir <- file.path("cfaforecastrenewalww", "inst", "stan") init_dir <- file.path("input", "init_lists") - output_dir <- file.path("output", "eval") - figure_dir <- file.path("output", "eval", "plots") + output_dir <- file.path("output", "eval_latest") + figure_dir <- file.path("output", "eval_latest", "plots") ms_fig_dir <- file.path( - "output", "eval", + "output", "eval_latest", "plots", "manuscript" ) - hub_subdir <- file.path("output", "eval", "hub") + hub_subdir <- file.path("output", "eval_latest", "hub") retro_rt_path <- file.path("input", "retro_Rt", "Rt_draws.parquet") - score_subdir <- file.path("output", "eval", "hub") + score_subdir <- file.path("output", "eval_latest", "hub") # Proportion of forecast dates that a model must have submitted for to be # included in the Hub analysis prop_dates_for_incl_hub <- 18 / 22 @@ -132,6 +132,13 @@ write_eval_config <- function(locations, forecast_dates, as.vector() |> unique() + # Table of run ids for accessing real-time model fits + real_time_output_dir <- file.path("output", "real_time_outputs") + path_to_table_of_run_ids <- file.path("output", "real_time_outputs", "table_of_run_ids.rds") + table_of_run_ids <- readRDS(path_to_table_of_run_ids) + table_of_run_ids$forecast_date <- as.character(table_of_run_ids$forecast_date) + + # These come from the yaml files we saved in the forecast folders, # documentation which location-forecast dates we chose to use the hospital # admissions only model for in real-time @@ -183,6 +190,8 @@ write_eval_config <- function(locations, forecast_dates, forecast_time = forecast_time, ww_data_mapping = ww_data_mapping, table_of_exclusions = table_of_exclusions, + table_of_run_ids = table_of_run_ids, + real_time_output_dir = real_time_output_dir, ww_forecast_date_locs_to_excl = ww_forecast_date_locs_to_excl, # MCMC settings iter_warmup = iter_warmup, diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index 0343aad3..29d8928e 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -53,6 +53,7 @@ export(get_plot_theme) export(get_plot_wis_over_time) export(get_plot_ww_data_comparison) export(get_qq_plot) +export(get_rel_crps_real_time) export(get_scenario_site_ids) export(get_scores_from_quantiles) export(get_secret) @@ -102,6 +103,7 @@ export(pull_nhsn) export(query_and_select_models) export(save_table) export(score_hub_submissions) +export(score_real_time_outputs) export(setup_secrets) export(soql_is_in) export(trajectories_to_quantiles) diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R new file mode 100644 index 00000000..719f1bc6 --- /dev/null +++ b/wweval/R/score_real_time_outputs.R @@ -0,0 +1,160 @@ +#' Load in and score the real-time outputs +#' +#' +#' @param real_time_output_dir A string indicating the upper level directory +#' where the real-time outputs live locally +#' @param table_of_run_ids A tibble containing the forecast date, run id, +#' and date run for each of the production runs +#' @param locations A vector of character strings indicating the locations to +#' pull, this should be all jurisdictions +#' @param dates A vector of forecast dates to pull +#' @param eval_data a tibble of hospital admissions evaluation data to be used +#' for scoring. +#' +#' @return A large tibble containing crps scores for every location and +#' forecast date, conditioned on the presence of wastewater and model +#' convergence +#' @export +score_real_time_outputs <- function(real_time_output_dir, + table_of_run_ids, + locations, + dates, + eval_data) { + model_types <- c("ww", "hosp") + all_scores <- c() + for (i in seq_along(dates)) { + date_to_pull <- dates[i] + metadata <- table_of_run_ids |> dplyr::filter( + forecast_date == date_to_pull + ) + run_id <- metadata$ids + date_run <- metadata$dates_run + for (j in seq_along(locations)) { + for (m in seq_along(model_types)) { + model_long <- ifelse(model_types[m] == "ww", + "site-level infection dynamics", + "hospital admissions only" + ) + if (date_to_pull %in% c("2024-02-05", "2024-02-12")) { + # Assume the old file structure + fp <- file.path( + real_time_output_dir, + glue::glue("output_{date_to_pull}"), + "raw", + locations[j], + model_long, + "draws", + date_to_pull, + glue::glue("run-on-{date_run}-{run_id}-draws.parquet") + ) + if (file.exists(fp)) { + # The diagnostics are not flags here, just values. + any_flags <- FALSE + + this_draws <- arrow::read_parquet(fp) |> + dplyr::filter( + name == "pred_hosp", + period != "calibration" + ) |> + dplyr::select( + forecast_date, + date, + location, + value, + draw + ) |> + dplyr::mutate( + model = model_types[m], + failed_convergence = any_flags + ) + } else { + this_draws <- c() + } + } else { + # Assume the main newer file structure + dir <- file.path( + real_time_output_dir, + date_to_pull, + glue::glue("run-on-{date_run}-{run_id}"), + "raw", + locations[j], + model_long + ) + + if (file.exists(file.path(dir, "draws.parquet"))) { + this_flags <- readr::read_csv(file.path(dir, "diagnostics.csv")) + any_flags <- any(this_flags$value[20:23] == TRUE) + + this_draws <- arrow::read_parquet(file.path(dir, "draws.parquet")) |> + dplyr::filter( + name == "pred_hosp", + period != "calibration" + ) |> + dplyr::select( + forecast_date, + date, + location, + value, + draw + ) |> + dplyr::mutate( + model = model_types[m], + failed_convergence = any_flags + ) + } else { + this_draws <- c() + } + } # end ifelse for file structures + + # Score the draws + if (!is.null(this_draws)) { + draws_w_eval <- this_draws |> + dplyr::left_join( + eval_data |> + dplyr::select(-pop) |> + dplyr::rename(true_value = daily_hosp_admits), + by = c("location", "date") + ) + + # Pass to scoring utils + + forecasted_draws <- draws_w_eval |> + dplyr::rename( + sample = draw, + prediction = value, + ) |> + dplyr::select( + location, + forecast_date, + date, + true_value, + prediction, + sample, + model, + failed_convergence + ) + scores <- forecasted_draws |> + data.table::as.data.table() |> + scoringutils::transform_forecasts( + fun = scoringutils::log_shift, + offset = 1 + ) |> + scoringutils::check_forecasts() |> + scoringutils::score() |> + tibble::tibble() + } else { + scores <- c() + } + + + all_scores <- dplyr::bind_rows( + all_scores, + scores + ) + } # end loop around model types + } # end loop around locs + } # end loop around forecast dates + + + return(all_scores) +} diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index b1a66beb..07307264 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -1058,3 +1058,94 @@ get_heatmap_metadata_hub <- function(metadata, ) ) } + +#' Get the relative crps for the real time scores +#' +#' @param all_scores a tibble of the scores for both models in real-time +#' +#' @return A tibble of the relative crps at each forecast date, location, and +#' horizon day +#' @export +get_rel_crps_real_time <- function(all_scores) { + full_metadata <- all_scores |> + dplyr::filter(scale == "log") |> + dplyr::group_by(forecast_date, model, location, failed_convergence) |> + dplyr::summarize(mean_crps = mean(crps)) |> + dplyr::filter(failed_convergence == FALSE) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps + ) + # Find the date locations to exclude + + date_locs_to_exclude <- full_metadata |> + dplyr::filter(is.na(ww)) |> + dplyr::distinct(location, forecast_date) + + scores_filtered <- all_scores |> + dplyr::anti_join(date_locs_to_exclude, + by = c("location", "forecast_date") + ) + + rel_scores <- scores_filtered |> + dplyr::filter(scale == "log") |> + dplyr::select(location, forecast_date, date, model, crps) |> + tidyr::pivot_wider( + names_from = model, + values_from = crps + ) |> + dplyr::mutate( + rel_crps = ww / hosp + ) + + return(rel_scores) +} + +#' Get a plot of the relative crps from the real-time models +#' +#' @param rel_scores tibble containing the relative crps for each forecast +#' date and location and horizon day +#' @param fig_file_dir string indicating the directory to save the figure +#' +#' @return ggplot object of a heatmap of the realtive crps +get_plot_rel_crps_real_time <- function(rel_scores, + fig_file_dir) { + avg_rel_scores <- rel_scores |> + dplyr::group_by(forecast_date, location) |> + dplyr::summarise(mean_rel_crps = mean(rel_crps)) + + p <- ggplot(avg_rel_scores) + + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + transform = "log2", + midpoint = 1, + guide = "colourbar", aesthetics = "fill" + ) + + geom_text(aes( + x = forecast_date, y = location, + label = round(mean_rel_crps, 2) + ), size = 1.5) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Relative CRPS") + + ggtitle(glue::glue("Real-time mean relative CRPS by forecast date and location")) + + ggsave(p, + width = 7, height = 6, + filename = file.path( + fig_file_dir, + glue::glue("sfig_real_time_heatmap_rel_crps.png") + ) + ) + + return(p) +} diff --git a/wweval/man/get_plot_rel_crps_real_time.Rd b/wweval/man/get_plot_rel_crps_real_time.Rd new file mode 100644 index 00000000..5ace6b2e --- /dev/null +++ b/wweval/man/get_plot_rel_crps_real_time.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_plot_rel_crps_real_time} +\alias{get_plot_rel_crps_real_time} +\title{Get a plot of the relative crps from the real-time models} +\usage{ +get_plot_rel_crps_real_time(rel_scores, fig_file_dir) +} +\arguments{ +\item{rel_scores}{tibble containing the relative crps for each forecast +date and location and horizon day} + +\item{fig_file_dir}{string indicating the directory to save the figure} +} +\value{ +ggplot object of a heatmap of the realtive crps +} +\description{ +Get a plot of the relative crps from the real-time models +} diff --git a/wweval/man/get_rel_crps_real_time.Rd b/wweval/man/get_rel_crps_real_time.Rd new file mode 100644 index 00000000..8e31d183 --- /dev/null +++ b/wweval/man/get_rel_crps_real_time.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_rel_crps_real_time} +\alias{get_rel_crps_real_time} +\title{Get the relative crps for the real time scores} +\usage{ +get_rel_crps_real_time(all_scores) +} +\arguments{ +\item{all_scores}{a tibble of the scores for both models in real-time} +} +\value{ +A tibble of the relative crps at each forecast date, location, and +horizon day +} +\description{ +Get the relative crps for the real time scores +} diff --git a/wweval/man/score_real_time_outputs.Rd b/wweval/man/score_real_time_outputs.Rd new file mode 100644 index 00000000..48ce7945 --- /dev/null +++ b/wweval/man/score_real_time_outputs.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/score_real_time_outputs.R +\name{score_real_time_outputs} +\alias{score_real_time_outputs} +\title{Load in and score the real-time outputs} +\usage{ +score_real_time_outputs( + real_time_output_dir, + table_of_run_ids, + locations, + dates, + eval_data +) +} +\arguments{ +\item{real_time_output_dir}{A string indicating the upper level directory +where the real-time outputs live locally} + +\item{table_of_run_ids}{A tibble containing the forecast date, run id, +and date run for each of the production runs} + +\item{locations}{A vector of character strings indicating the locations to +pull, this should be all jurisdictions} + +\item{dates}{A vector of forecast dates to pull} + +\item{eval_data}{a tibble of hospital admissions evaluation data to be used +for scoring.} +} +\value{ +A large tibble containing crps scores for every location and +forecast date, conditioned on the presence of wastewater and model +convergence +} +\description{ +Load in and score the real-time outputs +} From 87c0a269a8ba6e3e2e6ebb73c5693ee6c4949d81 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 26 Nov 2024 22:14:57 +0000 Subject: [PATCH 044/110] add functionality to either score draws with crps or quantiled forecasts with wis for realtime both models --- _targets_eval_postprocessing.R | 84 ++++++++++++++++---------- wweval/R/score_real_time_outputs.R | 85 ++++++++++++++++++--------- wweval/man/score_real_time_outputs.Rd | 5 ++ 3 files changed, 113 insertions(+), 61 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 54474770..e8174ee9 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1198,6 +1198,56 @@ scenario_targets <- list( ) ) +# Real-time relative targets-------------------------------------- +real_time_rel_targets <- list( + tar_target( + name = real_time_crps_both_models, + command = score_real_time_outputs( + score_type = "crps", + real_time_output_dir = eval_config$real_time_output_dir, + table_of_run_ids = as.data.frame(eval_config$table_of_run_ids), + locations = unique(eval_config$location_ww), + dates = as.character(seq( + from = lubridate::ymd("2024-02-05"), + to = lubridate::ymd("2024-03-11"), + by = "week" + )), + eval_data = eval_hosp_data + ) + ), + tar_target( + name = real_time_wis_both_models, + command = score_real_time_outputs( + score_type = "wis", + real_time_output_dir = eval_config$real_time_output_dir, + table_of_run_ids = as.data.frame(eval_config$table_of_run_ids), + locations = unique(eval_config$location_ww), + dates = as.character(seq( + from = lubridate::ymd("2024-02-05"), + to = lubridate::ymd("2024-03-11"), + by = "week" + )), + eval_data = eval_hosp_data + ) + ), + tar_target( + name = rel_scores, + command = get_rel_crps_real_time(real_time_crps_both_models) + ), + tar_target( + name = plot_real_time_rel_crps, + command = get_plot_rel_crps_real_time( + rel_scores, + fig_file_dir = eval_config$ms_fig_dir + ) + ), + tar_target( + name = overall_rel_crps, + command = rel_scores |> + dplyr::ungroup() |> + dplyr::summarise(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + ) +) # Hub targets------------------------------------------------------- hub_targets <- list( @@ -1639,37 +1689,6 @@ supp_targets <- list( scores = scores_filtered, threshold = 0.1 ) - ), - tar_target( - name = real_time_scores_both_models, - command = score_real_time_outputs( - real_time_output_dir = eval_config$real_time_output_dir, - table_of_run_ids = as.data.frame(eval_config$table_of_run_ids), - locations = unique(eval_config$location_ww), - dates = as.character(seq( - from = lubridate::ymd("2024-02-05"), - to = lubridate::ymd("2024-03-11"), - by = "week" - )), - eval_data = eval_hosp_data - ) - ), - tar_target( - name = rel_scores, - command = get_rel_crps_real_time(real_time_scores_both_models) - ), - tar_target( - name = plot_real_time_rel_crps, - command = get_plot_rel_crps_real_time( - rel_scores, - fig_file_dir = eval_config$ms_fig_dir - ) - ), - tar_target( - name = overall_rel_crps, - command = rel_scores |> - dplyr::ungroup() |> - dplyr::summarise(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) ) ) @@ -1685,5 +1704,6 @@ list( hub_targets, hub_comparison_plots, supp_targets, - benchmarks + benchmarks, + real_time_rel_targets ) diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index 719f1bc6..f299397f 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -1,6 +1,8 @@ #' Load in and score the real-time outputs #' -#' +#' @param score_type A string indicating which score to generate, either +#' "crps" or "wis". Note, if using crps, will score draws from nowcast and +#' forecast. If using wis, will score only the forecasts. #' @param real_time_output_dir A string indicating the upper level directory #' where the real-time outputs live locally #' @param table_of_run_ids A tibble containing the forecast date, run id, @@ -15,13 +17,17 @@ #' forecast date, conditioned on the presence of wastewater and model #' convergence #' @export -score_real_time_outputs <- function(real_time_output_dir, +score_real_time_outputs <- function(score_type, + real_time_output_dir, table_of_run_ids, locations, dates, eval_data) { model_types <- c("ww", "hosp") all_scores <- c() + + data_type <- ifelse(score_type == "crps", "draws", "quantiles") + col_name <- ifelse(score_type == "crps", "draw", "quantile") for (i in seq_along(dates)) { date_to_pull <- dates[i] metadata <- table_of_run_ids |> dplyr::filter( @@ -43,15 +49,15 @@ score_real_time_outputs <- function(real_time_output_dir, "raw", locations[j], model_long, - "draws", + data_type, date_to_pull, - glue::glue("run-on-{date_run}-{run_id}-draws.parquet") + glue::glue("run-on-{date_run}-{run_id}-{data_type}.parquet") ) if (file.exists(fp)) { # The diagnostics are not flags here, just values. any_flags <- FALSE - this_draws <- arrow::read_parquet(fp) |> + these_preds <- arrow::read_parquet(fp) |> dplyr::filter( name == "pred_hosp", period != "calibration" @@ -61,14 +67,14 @@ score_real_time_outputs <- function(real_time_output_dir, date, location, value, - draw + !!sym(col_name) ) |> dplyr::mutate( model = model_types[m], failed_convergence = any_flags ) } else { - this_draws <- c() + these_preds <- c() } } else { # Assume the main newer file structure @@ -81,11 +87,13 @@ score_real_time_outputs <- function(real_time_output_dir, model_long ) - if (file.exists(file.path(dir, "draws.parquet"))) { + if (file.exists(file.path(dir, glue::glue("{data_type}.parquet")))) { this_flags <- readr::read_csv(file.path(dir, "diagnostics.csv")) any_flags <- any(this_flags$value[20:23] == TRUE) - this_draws <- arrow::read_parquet(file.path(dir, "draws.parquet")) |> + these_preds <- arrow::read_parquet( + file.path(dir, glue::glue("{data_type}.parquet")) + ) |> dplyr::filter( name == "pred_hosp", period != "calibration" @@ -102,13 +110,13 @@ score_real_time_outputs <- function(real_time_output_dir, failed_convergence = any_flags ) } else { - this_draws <- c() + these_preds <- c() } } # end ifelse for file structures # Score the draws - if (!is.null(this_draws)) { - draws_w_eval <- this_draws |> + if (!is.null(these_preds)) { + preds_w_eval <- these_preds |> dplyr::left_join( eval_data |> dplyr::select(-pop) |> @@ -117,23 +125,42 @@ score_real_time_outputs <- function(real_time_output_dir, ) # Pass to scoring utils - - forecasted_draws <- draws_w_eval |> - dplyr::rename( - sample = draw, - prediction = value, - ) |> - dplyr::select( - location, - forecast_date, - date, - true_value, - prediction, - sample, - model, - failed_convergence - ) - scores <- forecasted_draws |> + if (score_type == "crps") { + forecasted_preds <- preds_w_eval |> + dplyr::rename( + sample = draw, + prediction = value, + ) |> + dplyr::select( + location, + forecast_date, + date, + true_value, + prediction, + sample, + model, + failed_convergence + ) + } else if (score_type == "wis") { + forecasted_preds <- preds_w_eval |> + dplyr::rename( + prediction = value, + ) |> + dplyr::select( + location, + forecast_date, + date, + true_value, + prediction, + quantile, + model, + failed_convergence + ) |> + dplyr::filter( + date > forecast_date + ) + } + scores <- forecasted_preds |> data.table::as.data.table() |> scoringutils::transform_forecasts( fun = scoringutils::log_shift, diff --git a/wweval/man/score_real_time_outputs.Rd b/wweval/man/score_real_time_outputs.Rd index 48ce7945..aea04811 100644 --- a/wweval/man/score_real_time_outputs.Rd +++ b/wweval/man/score_real_time_outputs.Rd @@ -5,6 +5,7 @@ \title{Load in and score the real-time outputs} \usage{ score_real_time_outputs( + score_type, real_time_output_dir, table_of_run_ids, locations, @@ -13,6 +14,10 @@ score_real_time_outputs( ) } \arguments{ +\item{score_type}{A string indicating which score to generate, either +"crps" or "wis". Note, if using crps, will score draws from nowcast and +forecast. If using wis, will score only the forecasts.} + \item{real_time_output_dir}{A string indicating the upper level directory where the real-time outputs live locally} From b597b34156ccc4f8d30a9b376082078b0826e7eb Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 26 Nov 2024 23:42:09 +0000 Subject: [PATCH 045/110] add a function to format the real time hosp only WIS as the ones from github in real time are formatted --- wweval/NAMESPACE | 1 + wweval/R/score_real_time_outputs.R | 52 +++++++++++++++++++++- wweval/man/format_scores_for_comparison.Rd | 30 +++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 wweval/man/format_scores_for_comparison.Rd diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index 29d8928e..b8069447 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -17,6 +17,7 @@ export(eval_post_process_hosp) export(eval_post_process_ww) export(exclude_hosp_outliers) export(format_for_hub) +export(format_scores_for_comparison) export(get_add_ww_metadata) export(get_avg_scores_model_horizon) export(get_box_plot) diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index f299397f..b1810f83 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -103,7 +103,7 @@ score_real_time_outputs <- function(score_type, date, location, value, - draw + !!sym(col_name) ) |> dplyr::mutate( model = model_types[m], @@ -185,3 +185,53 @@ score_real_time_outputs <- function(score_type, return(all_scores) } + +#' Format the hosp only real time scores for comparison to the other real +#' time models +#' +#' @param real_time_scores the set of real time scores gathered from local +#' pull +#' @param other_real_time_scores the set we want them to be formatted like +#' @param truth_data_path a link to the truth data to create loc name +#' +#' @return a tibble formatted as the other real time scores for the real +#' time hosp only model +#' @export +format_scores_for_comparison <- function(real_time_scores, + other_real_time_scores, + truth_data_path = "https://media.githubusercontent.com/media/reichlab/covid19-forecast-hub/master/data-truth/truth-Incident%20Hospitalizations.csv") { # nolint + + loc_to_loc_name_table <- readr::read_csv(truth_data_path) |> + dplyr::distinct(location, location_name) + + + formatted_scores <- real_time_scores |> + dplyr::filter( + model == "hosp", + scale == "log" + ) |> + dplyr::mutate( + location = loc_abbr_to_flusight_code(location), + model = "cfa-hosponlyrenewal(real-time)", + type = "quantile", + days_ahead = as.numeric(date - forecast_date), + target = glue::glue("{days_ahead} day ahead inc hosp"), + horizon_days = as.integer( + lubridate::ymd(date) - lubridate::ymd(forecast_date) + ), + horizon_weeks = ceiling(horizon_days / 7), + horizon = glue::glue("{horizon_weeks} week ahead") + ) |> + dplyr::rename( + target_end_date = date + ) |> + dplyr::left_join( + loc_to_loc_name_table, + by = "location" + ) |> + dplyr::select( + colnames(other_real_time_scores) + ) + + return(formatted_scores) +} diff --git a/wweval/man/format_scores_for_comparison.Rd b/wweval/man/format_scores_for_comparison.Rd new file mode 100644 index 00000000..fa19f0cb --- /dev/null +++ b/wweval/man/format_scores_for_comparison.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/score_real_time_outputs.R +\name{format_scores_for_comparison} +\alias{format_scores_for_comparison} +\title{Format the hosp only real time scores for comparison to the other real +time models} +\usage{ +format_scores_for_comparison( + real_time_scores, + other_real_time_scores, + truth_data_path = + "https://media.githubusercontent.com/media/reichlab/covid19-forecast-hub/master/data-truth/truth-Incident\%20Hospitalizations.csv" +) +} +\arguments{ +\item{real_time_scores}{the set of real time scores gathered from local +pull} + +\item{other_real_time_scores}{the set we want them to be formatted like} + +\item{truth_data_path}{a link to the truth data to create loc name} +} +\value{ +a tibble formatted as the other real time scores for the real +time hosp only model +} +\description{ +Format the hosp only real time scores for comparison to the other real +time models +} From b0ffef8cad40cc0916c400d82bc02c8766da3680 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 26 Nov 2024 23:42:49 +0000 Subject: [PATCH 046/110] add a color for the real time hosp only model --- wweval/R/plotting_style.R | 1 + 1 file changed, 1 insertion(+) diff --git a/wweval/R/plotting_style.R b/wweval/R/plotting_style.R index 3a38e4f2..5cb302c9 100644 --- a/wweval/R/plotting_style.R +++ b/wweval/R/plotting_style.R @@ -102,6 +102,7 @@ plot_components <- function() { "hosp" = pal_model[2], "cfa-wwrenewal(retro)" = pal_model[1], "cfa-wwrenewal(real-time)" = pal_model[5], + "cfa-hosponlyrenewal(real-time)" = "peachpuff", "cfa-hosponlyrenewal(retro)" = pal_model[2], "COVIDhub-4_week_ensemble" = pastel_model[3], "COVIDhub-trained_ensemble" = pal_horizons[1], From de173c9044793e2cfaba6f1ccf28465111299fea Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 26 Nov 2024 23:43:28 +0000 Subject: [PATCH 047/110] add the real time hosp only wis to pipeline --- _targets_eval_postprocessing.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index e8174ee9..cd41f8d2 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1422,10 +1422,18 @@ hub_targets <- list( ) ) ), + tar_target( + name = cfa_hosp_real_time_scores, + command = format_scores_for_comparison( + real_time_scores = real_time_wis_both_models, + other_real_time_scores = cfa_real_time_scores + ) + ), tar_target( name = combine_scores_feb_mar, command = dplyr::bind_rows( cfa_real_time_scores, + cfa_hosp_real_time_scores, combine_scores_oct_mar |> dplyr::filter( forecast_date >= lubridate::ymd("2024-02-05") ) From b314a12cae60de4f583ec13a2fc39b7319a84a42 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 02:20:43 +0000 Subject: [PATCH 048/110] make the rel real-time heatmap WIS for consistency --- _targets_eval_postprocessing.R | 27 ++++++---- wweval/NAMESPACE | 2 +- wweval/R/supplement_analyses_and_figs.R | 53 ++++++++++++------- wweval/man/get_heatmap_rel_wis.Rd | 25 +++++++++ wweval/man/get_plot_rel_crps_real_time.Rd | 20 ------- ..._real_time.Rd => get_rel_wis_real_time.Rd} | 6 +-- 6 files changed, 80 insertions(+), 53 deletions(-) create mode 100644 wweval/man/get_heatmap_rel_wis.Rd delete mode 100644 wweval/man/get_plot_rel_crps_real_time.Rd rename wweval/man/{get_rel_crps_real_time.Rd => get_rel_wis_real_time.Rd} (81%) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index cd41f8d2..46cb7fa1 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1231,21 +1231,14 @@ real_time_rel_targets <- list( ) ), tar_target( - name = rel_scores, - command = get_rel_crps_real_time(real_time_crps_both_models) + name = rel_real_time_wis, + command = get_rel_wis_real_time(real_time_wis_both_models) ), tar_target( - name = plot_real_time_rel_crps, - command = get_plot_rel_crps_real_time( - rel_scores, - fig_file_dir = eval_config$ms_fig_dir - ) - ), - tar_target( - name = overall_rel_crps, + name = overall_real_time_rel_wis, command = rel_scores |> dplyr::ungroup() |> - dplyr::summarise(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + dplyr::summarise(mean_rel_wis = mean(rel_wis, na.rm = TRUE)) ) ) @@ -1491,10 +1484,22 @@ hub_comparison_plots <- list( "CMU-TimeSeries", "COVIDhub-4_week_ensemble", "cfa-wwrenewal(real-time)", + "cfa-hosponlyrenewal(real-time)", "cfa-wwrenewal(retro)", "cfa-hosponlyrenewal(retro)" ) ), + ## Real-time Hub comparison top row------------------------------------------ + tar_target( + name = fig5_plot_real_time_rel_wis, + command = get_heatmap_rel_wis( + rel_real_time_wis, + time_period = "Feb-Mar", + analysis_type = "Real-time", + fig_file_dir = eval_config$ms_fig_dir + ) + ), + ## Retro Hub comparison top row------------------------------------------- tar_target( name = fig5_plot_wis_over_time, command = make_fig5_average_wis( diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index b8069447..595f5ade 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -54,7 +54,7 @@ export(get_plot_theme) export(get_plot_wis_over_time) export(get_plot_ww_data_comparison) export(get_qq_plot) -export(get_rel_crps_real_time) +export(get_rel_wis_real_time) export(get_scenario_site_ids) export(get_scores_from_quantiles) export(get_secret) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 07307264..f2df5a3e 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -1066,15 +1066,21 @@ get_heatmap_metadata_hub <- function(metadata, #' @return A tibble of the relative crps at each forecast date, location, and #' horizon day #' @export -get_rel_crps_real_time <- function(all_scores) { +get_rel_wis_real_time <- function(all_scores) { full_metadata <- all_scores |> dplyr::filter(scale == "log") |> - dplyr::group_by(forecast_date, model, location, failed_convergence) |> - dplyr::summarize(mean_crps = mean(crps)) |> + as.data.table() |> + scoringutils::summarise_scores( + by = c("forecast_date", "model", "location", "failed_convergence") + ) |> + dplyr::select( + forecast_date, model, location, failed_convergence, + interval_score + ) |> dplyr::filter(failed_convergence == FALSE) |> tidyr::pivot_wider( names_from = model, - values_from = mean_crps + values_from = interval_score ) # Find the date locations to exclude @@ -1089,33 +1095,44 @@ get_rel_crps_real_time <- function(all_scores) { rel_scores <- scores_filtered |> dplyr::filter(scale == "log") |> - dplyr::select(location, forecast_date, date, model, crps) |> + as.data.table() |> + scoringutils::summarise_scores( + by = c("forecast_date", "model", "date", "location") + ) |> + tibble::tibble() |> + dplyr::select(location, forecast_date, date, model, interval_score) |> tidyr::pivot_wider( names_from = model, - values_from = crps + values_from = interval_score ) |> dplyr::mutate( - rel_crps = ww / hosp + rel_wis = ww / hosp ) return(rel_scores) } -#' Get a plot of the relative crps from the real-time models +#' Get a plot of the relative wis from the real-time models #' -#' @param rel_scores tibble containing the relative crps for each forecast +#' @param rel_scores tibble containing the relative wis for each forecast #' date and location and horizon day +#' @param time_period string indicating dates of analysis, either "Feb-Mar", +#' or "Oct-Mar" +#' @param analysis_type string indicating whether analysis is Real-time +# or Retrospective #' @param fig_file_dir string indicating the directory to save the figure #' -#' @return ggplot object of a heatmap of the realtive crps -get_plot_rel_crps_real_time <- function(rel_scores, - fig_file_dir) { +#' @return ggplot object of a heatmap of the realtive wis +get_heatmap_rel_wis <- function(rel_scores, + time_period, + analysis_type, + fig_file_dir) { avg_rel_scores <- rel_scores |> dplyr::group_by(forecast_date, location) |> - dplyr::summarise(mean_rel_crps = mean(rel_crps)) + dplyr::summarise(mean_rel_wis = mean(rel_wis)) p <- ggplot(avg_rel_scores) + - geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + scale_fill_gradient2( high = "red", mid = "white", low = "blue", transform = "log2", @@ -1124,7 +1141,7 @@ get_plot_rel_crps_real_time <- function(rel_scores, ) + geom_text(aes( x = forecast_date, y = location, - label = round(mean_rel_crps, 2) + label = round(mean_rel_wis, 2) ), size = 1.5) + get_plot_theme( x_axis_dates = TRUE, @@ -1136,14 +1153,14 @@ get_plot_rel_crps_real_time <- function(rel_scores, ) + xlab("") + ylab("Location") + - labs(fill = "Relative CRPS") + - ggtitle(glue::glue("Real-time mean relative CRPS by forecast date and location")) + labs(fill = "Relative WIS") + + ggtitle(glue::glue("{analysis_type} mean relative WIS from {time_period}")) ggsave(p, width = 7, height = 6, filename = file.path( fig_file_dir, - glue::glue("sfig_real_time_heatmap_rel_crps.png") + glue::glue("sfig_heatmap_rel_wis_{time_period}_{analysis_type}.png") ) ) diff --git a/wweval/man/get_heatmap_rel_wis.Rd b/wweval/man/get_heatmap_rel_wis.Rd new file mode 100644 index 00000000..c695aa58 --- /dev/null +++ b/wweval/man/get_heatmap_rel_wis.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_heatmap_rel_wis} +\alias{get_heatmap_rel_wis} +\title{Get a plot of the relative wis from the real-time models} +\usage{ +get_heatmap_rel_wis(rel_scores, time_period, analysis_type, fig_file_dir) +} +\arguments{ +\item{rel_scores}{tibble containing the relative wis for each forecast +date and location and horizon day} + +\item{time_period}{string indicating dates of analysis, either "Feb-Mar", +or "Oct-Mar"} + +\item{analysis_type}{string indicating whether analysis is Real-time} + +\item{fig_file_dir}{string indicating the directory to save the figure} +} +\value{ +ggplot object of a heatmap of the realtive wis +} +\description{ +Get a plot of the relative wis from the real-time models +} diff --git a/wweval/man/get_plot_rel_crps_real_time.Rd b/wweval/man/get_plot_rel_crps_real_time.Rd deleted file mode 100644 index 5ace6b2e..00000000 --- a/wweval/man/get_plot_rel_crps_real_time.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/supplement_analyses_and_figs.R -\name{get_plot_rel_crps_real_time} -\alias{get_plot_rel_crps_real_time} -\title{Get a plot of the relative crps from the real-time models} -\usage{ -get_plot_rel_crps_real_time(rel_scores, fig_file_dir) -} -\arguments{ -\item{rel_scores}{tibble containing the relative crps for each forecast -date and location and horizon day} - -\item{fig_file_dir}{string indicating the directory to save the figure} -} -\value{ -ggplot object of a heatmap of the realtive crps -} -\description{ -Get a plot of the relative crps from the real-time models -} diff --git a/wweval/man/get_rel_crps_real_time.Rd b/wweval/man/get_rel_wis_real_time.Rd similarity index 81% rename from wweval/man/get_rel_crps_real_time.Rd rename to wweval/man/get_rel_wis_real_time.Rd index 8e31d183..281d50fe 100644 --- a/wweval/man/get_rel_crps_real_time.Rd +++ b/wweval/man/get_rel_wis_real_time.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/supplement_analyses_and_figs.R -\name{get_rel_crps_real_time} -\alias{get_rel_crps_real_time} +\name{get_rel_wis_real_time} +\alias{get_rel_wis_real_time} \title{Get the relative crps for the real time scores} \usage{ -get_rel_crps_real_time(all_scores) +get_rel_wis_real_time(all_scores) } \arguments{ \item{all_scores}{a tibble of the scores for both models in real-time} From 981946612f204087541c7e9867df28cf905995b6 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 02:38:52 +0000 Subject: [PATCH 049/110] move rel real time heatmap to fig 5 --- _targets_eval_postprocessing.R | 4 +- wweval/R/ms_fig5.R | 57 +++++++++++++++++++ wweval/R/supplement_analyses_and_figs.R | 55 ------------------ ...el_wis.Rd => make_fig5_heatmap_rel_wis.Rd} | 8 +-- 4 files changed, 63 insertions(+), 61 deletions(-) rename wweval/man/{get_heatmap_rel_wis.Rd => make_fig5_heatmap_rel_wis.Rd} (75%) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 46cb7fa1..eb0c7a98 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1236,7 +1236,7 @@ real_time_rel_targets <- list( ), tar_target( name = overall_real_time_rel_wis, - command = rel_scores |> + command = rel_real_time_wis |> dplyr::ungroup() |> dplyr::summarise(mean_rel_wis = mean(rel_wis, na.rm = TRUE)) ) @@ -1492,7 +1492,7 @@ hub_comparison_plots <- list( ## Real-time Hub comparison top row------------------------------------------ tar_target( name = fig5_plot_real_time_rel_wis, - command = get_heatmap_rel_wis( + command = make_fig5_heatmap_rel_wis( rel_real_time_wis, time_period = "Feb-Mar", analysis_type = "Real-time", diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index a91fd1b9..bee91380 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -452,6 +452,63 @@ make_fig5_density_rank <- function(scores, return(p) } + +#' Get a plot of the relative wis from the real-time models +#' +#' @param rel_scores tibble containing the relative wis for each forecast +#' date and location and horizon day +#' @param time_period string indicating dates of analysis, either "Feb-Mar", +#' or "Oct-Mar" +#' @param analysis_type string indicating whether analysis is Real-time +# or Retrospective +#' @param fig_file_dir string indicating the directory to save the figure +#' +#' @return ggplot object of a heatmap of the realtive wis +make_fig5_heatmap_rel_wis <- function(rel_scores, + time_period, + analysis_type, + fig_file_dir) { + avg_rel_scores <- rel_scores |> + dplyr::group_by(forecast_date, location) |> + dplyr::summarise(mean_rel_wis = mean(rel_wis)) + + p <- ggplot(avg_rel_scores) + + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + transform = "log2", + midpoint = 1, + guide = "colourbar", aesthetics = "fill" + ) + + geom_text(aes( + x = forecast_date, y = location, + label = round(mean_rel_wis, 2) + ), size = 1.5) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Relative WIS") + + ggtitle(glue::glue("{analysis_type} mean relative WIS from {time_period}")) + + ggsave(p, + width = 7, height = 6, + filename = file.path( + fig_file_dir, + glue::glue("sfig_heatmap_rel_wis_{time_period}_{analysis_type}.png") + ) + ) + + return(p) +} + + #' Make Fig 5 #' #' @param fig5_plot_wis_over_time average wis over time across locations for diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index f2df5a3e..a971bf5d 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -1111,58 +1111,3 @@ get_rel_wis_real_time <- function(all_scores) { return(rel_scores) } - -#' Get a plot of the relative wis from the real-time models -#' -#' @param rel_scores tibble containing the relative wis for each forecast -#' date and location and horizon day -#' @param time_period string indicating dates of analysis, either "Feb-Mar", -#' or "Oct-Mar" -#' @param analysis_type string indicating whether analysis is Real-time -# or Retrospective -#' @param fig_file_dir string indicating the directory to save the figure -#' -#' @return ggplot object of a heatmap of the realtive wis -get_heatmap_rel_wis <- function(rel_scores, - time_period, - analysis_type, - fig_file_dir) { - avg_rel_scores <- rel_scores |> - dplyr::group_by(forecast_date, location) |> - dplyr::summarise(mean_rel_wis = mean(rel_wis)) - - p <- ggplot(avg_rel_scores) + - geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + - scale_fill_gradient2( - high = "red", mid = "white", low = "blue", - transform = "log2", - midpoint = 1, - guide = "colourbar", aesthetics = "fill" - ) + - geom_text(aes( - x = forecast_date, y = location, - label = round(mean_rel_wis, 2) - ), size = 1.5) + - get_plot_theme( - x_axis_dates = TRUE, - y_axis_text_size = 4 - ) + - scale_x_date( - date_breaks = "1 week", - labels = scales::date_format("%Y-%m-%d") - ) + - xlab("") + - ylab("Location") + - labs(fill = "Relative WIS") + - ggtitle(glue::glue("{analysis_type} mean relative WIS from {time_period}")) - - ggsave(p, - width = 7, height = 6, - filename = file.path( - fig_file_dir, - glue::glue("sfig_heatmap_rel_wis_{time_period}_{analysis_type}.png") - ) - ) - - return(p) -} diff --git a/wweval/man/get_heatmap_rel_wis.Rd b/wweval/man/make_fig5_heatmap_rel_wis.Rd similarity index 75% rename from wweval/man/get_heatmap_rel_wis.Rd rename to wweval/man/make_fig5_heatmap_rel_wis.Rd index c695aa58..5ef1addb 100644 --- a/wweval/man/get_heatmap_rel_wis.Rd +++ b/wweval/man/make_fig5_heatmap_rel_wis.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/supplement_analyses_and_figs.R -\name{get_heatmap_rel_wis} -\alias{get_heatmap_rel_wis} +% Please edit documentation in R/ms_fig5.R +\name{make_fig5_heatmap_rel_wis} +\alias{make_fig5_heatmap_rel_wis} \title{Get a plot of the relative wis from the real-time models} \usage{ -get_heatmap_rel_wis(rel_scores, time_period, analysis_type, fig_file_dir) +make_fig5_heatmap_rel_wis(rel_scores, time_period, analysis_type, fig_file_dir) } \arguments{ \item{rel_scores}{tibble containing the relative wis for each forecast From 00fa69767af8595fb3976cd4b7cb918d8112f83a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 03:07:07 +0000 Subject: [PATCH 050/110] add requirements for top row of hub comparison figure --- _targets_eval_postprocessing.R | 29 ++++++++++++++ wweval/R/ms_fig5.R | 59 ++++++++++++++++++++++++++++- wweval/R/plotting_style.R | 2 +- wweval/man/make_fig5_average_wis.Rd | 5 ++- 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index eb0c7a98..9e8574b7 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1490,6 +1490,7 @@ hub_comparison_plots <- list( ) ), ## Real-time Hub comparison top row------------------------------------------ + # This will be the real-time relative WIS across the models submitted tar_target( name = fig5_plot_real_time_rel_wis, command = make_fig5_heatmap_rel_wis( @@ -1499,6 +1500,34 @@ hub_comparison_plots <- list( fig_file_dir = eval_config$ms_fig_dir ) ), + # This will be the real-time density of relative CRPS compared + # to covidhub baseline (will need to get the summary stats for this too) + tar_target( + name = fig5_density_real_time, + command = make_fig5_density( + all_scores = summarized_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-wwrenewal(retro)", + "cfa-hosponlyrenewal(retro)" + )), + models_to_show = models_to_plot, + analysis_type = "Real-time", + ) + ), + # This will be the average WIS across forecast dates for the real-time + # scores + tar_target( + name = fig5_plot_real_time_wis_t, + command = make_fig5_average_wis( + all_scores = summarized_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-wwrenewal(retro)", + "cfa-hosponlyrenewal(retro)" + )), + models_to_show = models_to_plot + ) + ), + ## Retro Hub comparison top row------------------------------------------- tar_target( name = fig5_plot_wis_over_time, diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index bee91380..82ea3346 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -55,7 +55,8 @@ make_fig5_table_and_plot <- function(scores, #' summarized across quantiles only with [scoringutils::summarise_scores()] #' @param cfa_real_time_scores Real-time scores from Feb - Mar for the cfa ww #' model submitted to the hub, scored with [scoringutils::score()] and -#' summarized across quantiles only with [scoringutils::summarise_scores()] +#' summarized across quantiles only with [scoringutils::summarise_scores()], +#' default is `c()` #' @param models_to_show A vector of charcter strings indicating which models #' from the COVID-19 forecast hub to include in the plot. #' @param horizon_time_in_weeks horizon time in weeks to summarize over, default @@ -68,7 +69,7 @@ make_fig5_table_and_plot <- function(scores, #' @export #' make_fig5_average_wis <- function(all_scores, - cfa_real_time_scores, + cfa_real_time_scores = c(), models_to_show, horizon_time_in_weeks = NULL) { subset_model_scores <- all_scores |> @@ -266,6 +267,60 @@ make_fig5_hub_performance <- function(all_scores, return(p) } +make_fig5_density <- function(all_scores, + analysis_type, + models_to_show, + baseline_model = "COVIDhub-4_week_ensemble") { + subset_scores <- all_scores |> + dplyr::filter(model %in% !!models_to_show) + + baseline_scores <- subset_scores |> + dplyr::filter(model == {{ baseline_model }}) |> + dplyr::select( + location, forecast_date, target_end_date, + horizon, interval_score + ) |> + dplyr::rename(baseline_score = interval_score) |> + dplyr::distinct() + + scores_final <- subset_scores |> + dplyr::left_join(baseline_scores, by = c( + "forecast_date", "horizon", + "location", "target_end_date" + )) |> + dplyr::mutate(relative_wis = interval_score / baseline_score) |> + dplyr::filter(model != {{ baseline_model }}) + + + colors <- plot_components() + + p <- ggplot(scores_final) + + tidybayes::stat_halfeye( + aes( + x = model, y = relative_wis + 1e-8, + fill = model + ), + point_interval = "mean_qi", + alpha = 0.5, + position = position_dodge(width = 0.75) + ) + + coord_trans(ylim = c(0, 2)) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_title_size = 8 + ) + + scale_fill_manual(values = colors$model_colors) + + scale_color_manual(values = colors$model_colors) + + xlab("") + + theme(legend.position = "bottom") + + ylab(glue::glue("{analysis_type} relative WIS \n compared to {baseline_model}")) + + + + return(p) +} + + #' Make a heatmap of relative WIS across locations #' #' @param scores df of granular (daily) score across models, locations, forecast diff --git a/wweval/R/plotting_style.R b/wweval/R/plotting_style.R index 5cb302c9..33ca2049 100644 --- a/wweval/R/plotting_style.R +++ b/wweval/R/plotting_style.R @@ -102,7 +102,7 @@ plot_components <- function() { "hosp" = pal_model[2], "cfa-wwrenewal(retro)" = pal_model[1], "cfa-wwrenewal(real-time)" = pal_model[5], - "cfa-hosponlyrenewal(real-time)" = "peachpuff", + "cfa-hosponlyrenewal(real-time)" = "orange4", "cfa-hosponlyrenewal(retro)" = pal_model[2], "COVIDhub-4_week_ensemble" = pastel_model[3], "COVIDhub-trained_ensemble" = pal_horizons[1], diff --git a/wweval/man/make_fig5_average_wis.Rd b/wweval/man/make_fig5_average_wis.Rd index 770976dc..36ecd0ab 100644 --- a/wweval/man/make_fig5_average_wis.Rd +++ b/wweval/man/make_fig5_average_wis.Rd @@ -6,7 +6,7 @@ \usage{ make_fig5_average_wis( all_scores, - cfa_real_time_scores, + cfa_real_time_scores = c(), models_to_show, horizon_time_in_weeks = NULL ) @@ -18,7 +18,8 @@ summarized across quantiles only with \code{\link[scoringutils:summarise_scores] \item{cfa_real_time_scores}{Real-time scores from Feb - Mar for the cfa ww model submitted to the hub, scored with \code{\link[scoringutils:score]{scoringutils::score()}} and -summarized across quantiles only with \code{\link[scoringutils:summarise_scores]{scoringutils::summarise_scores()}}} +summarized across quantiles only with \code{\link[scoringutils:summarise_scores]{scoringutils::summarise_scores()}}, +default is \code{c()}} \item{models_to_show}{A vector of charcter strings indicating which models from the COVID-19 forecast hub to include in the plot.} From 2c13cd5da5cfde3574719e4c60bf03bebb5df6c2 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 15:08:24 +0000 Subject: [PATCH 051/110] get relative wis retro for both models, change colors --- _targets_eval_postprocessing.R | 37 ++++++++++++++--- wweval/NAMESPACE | 1 + wweval/R/ms_fig5.R | 25 ++++++++++-- wweval/R/plotting_style.R | 2 +- wweval/R/supplement_analyses_and_figs.R | 53 ++++++++++++++++++++++++- wweval/man/get_rel_wis_all_time.Rd | 19 +++++++++ wweval/man/get_rel_wis_real_time.Rd | 6 +-- wweval/man/make_fig5_average_wis.Rd | 1 + 8 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 wweval/man/get_rel_wis_all_time.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 9e8574b7..3e64a2ba 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1344,6 +1344,12 @@ hub_targets <- list( scores_list_hub_submission_oct_mar$log_scale_scores ) ), + tar_target( + name = rel_all_time_wis, + command = get_rel_wis_all_time( + all_scores = scores_list_retro_hub_submissions$log_scale_scores + ) + ), # Rename the model as retrospective tar_target( name = combine_scores_oct_mar_full, @@ -1495,7 +1501,7 @@ hub_comparison_plots <- list( name = fig5_plot_real_time_rel_wis, command = make_fig5_heatmap_rel_wis( rel_real_time_wis, - time_period = "Feb-Mar", + time_period = "Feb-Mar 2024", analysis_type = "Real-time", fig_file_dir = eval_config$ms_fig_dir ) @@ -1524,17 +1530,35 @@ hub_comparison_plots <- list( "cfa-wwrenewal(retro)", "cfa-hosponlyrenewal(retro)" )), - models_to_show = models_to_plot + models_to_show = models_to_plot, + time_period = "Feb-Mar 2024" ) ), ## Retro Hub comparison top row------------------------------------------- tar_target( - name = fig5_plot_wis_over_time, + name = fig5_plot_all_time_rel_wis, + command = make_fig5_heatmap_rel_wis( + rel_all_time_wis, + time_period = "Oct 2023-Mar 2024", + analysis_type = "Retrospective", + fig_file_dir = eval_config$ms_fig_dir + ) + ), + tar_target( + name = fig5_density_all_time, + command = make_fig5_density( + all_scores = summarized_scores_oct_mar, + models_to_show = models_to_plot, + analysis_type = "Retrospective", + ) + ), + tar_target( + name = fig5_plot_all_time_wis_t, command = make_fig5_average_wis( all_scores = summarized_scores_oct_mar, - cfa_real_time_scores = summarized_scores_cfa_real_time, - models_to_show = models_to_plot + models_to_show = models_to_plot, + time_period = "Oct 2023-Mar 2024" ) ), tar_target( @@ -1547,6 +1571,7 @@ hub_comparison_plots <- list( real_time_period = "Feb 2024-Mar 2024", ) ), + # Lower rows Hub comparison fig------------------------------------ tar_target( name = fig5_heatmap_rel_wis_all_time, command = make_fig5_heatmap_relative_wis( @@ -1601,7 +1626,7 @@ hub_comparison_plots <- list( tar_target( name = fig5, command = make_fig5( - fig5_plot_wis_over_time = fig5_plot_wis_over_time, + fig5_plot_wis_over_time = fig5_plot_all_time_wis_t, fig5_overall_performance = fig5_overall_performance, fig5_heatmap_rel_wis_all_time = fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar = fig5_heatmap_rel_wis_feb_mar, diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index 595f5ade..f30ea108 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -54,6 +54,7 @@ export(get_plot_theme) export(get_plot_wis_over_time) export(get_plot_ww_data_comparison) export(get_qq_plot) +export(get_rel_wis_all_time) export(get_rel_wis_real_time) export(get_scenario_site_ids) export(get_scores_from_quantiles) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 82ea3346..f898895d 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -71,6 +71,7 @@ make_fig5_table_and_plot <- function(scores, make_fig5_average_wis <- function(all_scores, cfa_real_time_scores = c(), models_to_show, + time_period, horizon_time_in_weeks = NULL) { subset_model_scores <- all_scores |> dplyr::filter(model %in% !!models_to_show) @@ -98,7 +99,7 @@ make_fig5_average_wis <- function(all_scores, "forecast_date", "model" )) - title <- glue::glue("Average weighted interval scores by model") + title <- glue::glue("Average WIS by model {time_period}") } colors <- plot_components() @@ -114,6 +115,7 @@ make_fig5_average_wis <- function(all_scores, x = forecast_date, y = interval_score, color = model )) + + guides(color = guide_legend(nrow = 2)) + xlab("") + ylab("Average WIS across locations") + get_plot_theme( @@ -129,7 +131,9 @@ make_fig5_average_wis <- function(all_scores, theme( legend.position = "top", legend.justification = "left", - legend.direction = "horizontal" + legend.direction = "horizontal", + legend.title = element_blank(), + legend.text = element_text(size = 7) ) return(p) @@ -252,11 +256,19 @@ make_fig5_hub_performance <- function(all_scores, alpha = 0.5, position = position_dodge(width = 0.75) ) + + guides(fill = guide_legend(nrow = 2)) + coord_trans(ylim = c(0, 2)) + get_plot_theme( x_axis_dates = TRUE, y_axis_title_size = 8 ) + + theme( + legend.justification = "left", + legend.direction = "horizontal", + legend.position = "top", + legend.title = element_blank(), + legend.text = element_text(size = 7) + ) + scale_fill_manual(values = colors$model_colors) + scale_color_manual(values = colors$model_colors) + xlab("") + @@ -309,10 +321,17 @@ make_fig5_density <- function(all_scores, x_axis_dates = TRUE, y_axis_title_size = 8 ) + + guides(fill = guide_legend(nrow = 2)) + scale_fill_manual(values = colors$model_colors) + scale_color_manual(values = colors$model_colors) + xlab("") + - theme(legend.position = "bottom") + + theme( + legend.justification = "left", + legend.direction = "horizontal", + legend.position = "none", + legend.title = element_blank(), + legend.text = element_text(size = 7) + ) + ylab(glue::glue("{analysis_type} relative WIS \n compared to {baseline_model}")) diff --git a/wweval/R/plotting_style.R b/wweval/R/plotting_style.R index 33ca2049..31261d7e 100644 --- a/wweval/R/plotting_style.R +++ b/wweval/R/plotting_style.R @@ -102,7 +102,7 @@ plot_components <- function() { "hosp" = pal_model[2], "cfa-wwrenewal(retro)" = pal_model[1], "cfa-wwrenewal(real-time)" = pal_model[5], - "cfa-hosponlyrenewal(real-time)" = "orange4", + "cfa-hosponlyrenewal(real-time)" = "orange3", "cfa-hosponlyrenewal(retro)" = pal_model[2], "COVIDhub-4_week_ensemble" = pastel_model[3], "COVIDhub-trained_ensemble" = pal_horizons[1], diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index a971bf5d..d05d376c 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -1059,11 +1059,11 @@ get_heatmap_metadata_hub <- function(metadata, ) } -#' Get the relative crps for the real time scores +#' Get the relative wis for the real time scores #' #' @param all_scores a tibble of the scores for both models in real-time #' -#' @return A tibble of the relative crps at each forecast date, location, and +#' @return A tibble of the relative wis at each forecast date, location, and #' horizon day #' @export get_rel_wis_real_time <- function(all_scores) { @@ -1111,3 +1111,52 @@ get_rel_wis_real_time <- function(all_scores) { return(rel_scores) } + +#' Get the relative wis from the hub formatted +#' +#' @param all_scores a tibble of the scores for both models, formatted +#' like the hub +#' +#' @return A tibble of the relative wis at each forecast date, location, and +#' horizon day +#' @export +get_rel_wis_all_time <- function(all_scores) { + scores <- all_scores |> + data.table::as.data.table() |> + scoringutils::summarize_scores( + by = + c( + "target_end_date", + "model", + "location", + "forecast_date" + ) + ) |> + dplyr::rename( + date = target_end_date + ) |> + dplyr::left_join(wweval::flusight_location_table, + by = c("location" = "location_code") + ) |> + dplyr::select( + short_name, forecast_date, date, + model, interval_score + ) |> + dplyr::rename(location = short_name) |> + dplyr::mutate( + model = dplyr::case_when( + model == "cfa-wwrenewal" ~ "ww", + model == "cfa-hosponlyrenewal" ~ "hosp" + ) + ) |> + tidyr::pivot_wider( + names_from = model, + values_from = interval_score + ) |> + dplyr::mutate( + rel_wis = ww / hosp + ) |> + dplyr::select(location, forecast_date, ww, hosp, rel_wis) + + return(scores) +} diff --git a/wweval/man/get_rel_wis_all_time.Rd b/wweval/man/get_rel_wis_all_time.Rd new file mode 100644 index 00000000..09f9007d --- /dev/null +++ b/wweval/man/get_rel_wis_all_time.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_rel_wis_all_time} +\alias{get_rel_wis_all_time} +\title{Get the relative wis from the hub formatted} +\usage{ +get_rel_wis_all_time(all_scores) +} +\arguments{ +\item{all_scores}{a tibble of the scores for both models, formatted +like the hub} +} +\value{ +A tibble of the relative wis at each forecast date, location, and +horizon day +} +\description{ +Get the relative wis from the hub formatted +} diff --git a/wweval/man/get_rel_wis_real_time.Rd b/wweval/man/get_rel_wis_real_time.Rd index 281d50fe..d8b12c5e 100644 --- a/wweval/man/get_rel_wis_real_time.Rd +++ b/wweval/man/get_rel_wis_real_time.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/supplement_analyses_and_figs.R \name{get_rel_wis_real_time} \alias{get_rel_wis_real_time} -\title{Get the relative crps for the real time scores} +\title{Get the relative wis for the real time scores} \usage{ get_rel_wis_real_time(all_scores) } @@ -10,9 +10,9 @@ get_rel_wis_real_time(all_scores) \item{all_scores}{a tibble of the scores for both models in real-time} } \value{ -A tibble of the relative crps at each forecast date, location, and +A tibble of the relative wis at each forecast date, location, and horizon day } \description{ -Get the relative crps for the real time scores +Get the relative wis for the real time scores } diff --git a/wweval/man/make_fig5_average_wis.Rd b/wweval/man/make_fig5_average_wis.Rd index 36ecd0ab..9263b452 100644 --- a/wweval/man/make_fig5_average_wis.Rd +++ b/wweval/man/make_fig5_average_wis.Rd @@ -8,6 +8,7 @@ make_fig5_average_wis( all_scores, cfa_real_time_scores = c(), models_to_show, + time_period, horizon_time_in_weeks = NULL ) } From 649c83446dd635e951a054242e75768c59689f91 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 15:55:50 +0000 Subject: [PATCH 052/110] create new fig5 --- _targets_eval_postprocessing.R | 22 +++++++------------ wweval/R/ms_fig5.R | 40 ++++++++++++++++++++++------------ wweval/man/make_fig5.Rd | 28 +++++++++++++++++++----- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 3e64a2ba..75c5de3b 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1368,16 +1368,6 @@ hub_targets <- list( targets::tar_group(), iteration = "group" ), - tar_target( - name = plot_wis_w_forecasts, - command = get_plot_wis_t( - hosp_quantiles_filtered_grouped, - combine_scores_oct_mar_raw, - eval_output_subdir = eval_config$output_dir - ), - pattern = map(hosp_quantiles_filtered_grouped), - iteration = "list" - ), # Filter out the states that not every model has estimates for, # start by doing this manually, can write functions if needed as @@ -1523,7 +1513,7 @@ hub_comparison_plots <- list( # This will be the average WIS across forecast dates for the real-time # scores tar_target( - name = fig5_plot_real_time_wis_t, + name = fig5_plot_wis_t_real_time, command = make_fig5_average_wis( all_scores = summarized_scores_feb_mar |> dplyr::filter(!model %in% c( @@ -1554,7 +1544,7 @@ hub_comparison_plots <- list( ) ), tar_target( - name = fig5_plot_all_time_wis_t, + name = fig5_plot_wis_t_all_time, command = make_fig5_average_wis( all_scores = summarized_scores_oct_mar, models_to_show = models_to_plot, @@ -1626,8 +1616,12 @@ hub_comparison_plots <- list( tar_target( name = fig5, command = make_fig5( - fig5_plot_wis_over_time = fig5_plot_all_time_wis_t, - fig5_overall_performance = fig5_overall_performance, + fig5_plot_wis_t_real_time = fig5_plot_wis_t_real_time, + fig5_density_real_time = fig5_density_real_time, + fig5_plot_real_time_rel_wis = fig5_plot_real_time_rel_wis, + fig5_plot_wis_t_all_time = fig5_plot_wis_t_all_time, + fig5_density_all_time = fig5_density_all_time, + fig5_plot_all_time_rel_wis = fig5_plot_all_time_rel_wis, fig5_heatmap_rel_wis_all_time = fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar = fig5_heatmap_rel_wis_feb_mar, fig5_qq_plot_all_time = fig5_qq_plot_all_time, diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index f898895d..da4149d3 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -585,10 +585,18 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, #' Make Fig 5 #' -#' @param fig5_plot_wis_over_time average wis over time across locations for -#' each model -#' @param fig5_overall_performance density plot of overall performance across -#' location, forecast date, day, and model, stratified by time period +#' @param fig5_plot_wis_t_real_time average wis over time across locations for +#' each model in real-time (feb-mar) +#' @param fig5_density_real_time density plot of relative performance +#' across location, forecast_date, day, and model +#' @param fig5_plot_real_time_rel_wis heatmap of the relative wis between +#' the two models +#' @param fig5_plot_wis_t_all_time average wis over time across locations for +#' each model in real-time (feb-mar) +#' @param fig5_density_all_time density plot of relative performance +#' across location, forecast_date, day, and model +#' @param fig5_plot_all_time_rel_wis heatmap of the relative wis between +#' the two models #' @param fig5_heatmap_rel_wis_all_time heatmap comparing WIS across #' forecast dates for each location for all time #' @param fig5_heatmap_rel_wis_feb_mar heatmap comparing WIS across @@ -605,8 +613,12 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, #' @return a ggplot object containing all the figures combined #' @export #' -make_fig5 <- function(fig5_plot_wis_over_time, - fig5_overall_performance, +make_fig5 <- function(fig5_plot_wis_t_real_time, + fig5_density_real_time, + fig5_plot_real_time_rel_wis, + fig5_plot_wis_t_all_time, + fig5_density_all_time, + fig5_plot_all_time_rel_wis, fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar, fig5_qq_plot_all_time, @@ -615,15 +627,15 @@ make_fig5 <- function(fig5_plot_wis_over_time, fig5_std_rank_all_time, fig_file_dir) { layout <- " -ABB -CDE -FGH +ABC +DEF +GHI +JKL " - fig5 <- fig5_overall_performance + fig5_plot_wis_over_time + - fig5_heatmap_rel_wis_feb_mar + fig5_qq_plot_feb_mar + - fig5_std_rank_feb_mar + - fig5_heatmap_rel_wis_all_time + fig5_qq_plot_all_time + - fig5_std_rank_all_time + + fig5 <- fig5_plot_real_time_rel_wis + fig5_density_real_time + fig5_plot_wis_t_real_time + + fig5_heatmap_rel_wis_feb_mar + fig5_qq_plot_feb_mar + fig5_std_rank_feb_mar + + fig5_plot_all_time_rel_wis + fig5_density_all_time + fig5_plot_wis_t_all_time + + fig5_heatmap_rel_wis_all_time + fig5_qq_plot_all_time + fig5_std_rank_all_time + patchwork::plot_layout( design = layout, axes = "collect", diff --git a/wweval/man/make_fig5.Rd b/wweval/man/make_fig5.Rd index ea927fd2..32d1bcc1 100644 --- a/wweval/man/make_fig5.Rd +++ b/wweval/man/make_fig5.Rd @@ -5,8 +5,12 @@ \title{Make Fig 5} \usage{ make_fig5( - fig5_plot_wis_over_time, - fig5_overall_performance, + fig5_plot_wis_t_real_time, + fig5_density_real_time, + fig5_plot_real_time_rel_wis, + fig5_plot_wis_t_all_time, + fig5_density_all_time, + fig5_plot_all_time_rel_wis, fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar, fig5_qq_plot_all_time, @@ -17,11 +21,23 @@ make_fig5( ) } \arguments{ -\item{fig5_plot_wis_over_time}{average wis over time across locations for -each model} +\item{fig5_plot_wis_t_real_time}{average wis over time across locations for +each model in real-time (feb-mar)} -\item{fig5_overall_performance}{density plot of overall performance across -location, forecast date, day, and model, stratified by time period} +\item{fig5_density_real_time}{density plot of relative performance +across location, forecast_date, day, and model} + +\item{fig5_plot_real_time_rel_wis}{heatmap of the relative wis between +the two models} + +\item{fig5_plot_wis_t_all_time}{average wis over time across locations for +each model in real-time (feb-mar)} + +\item{fig5_density_all_time}{density plot of relative performance +across location, forecast_date, day, and model} + +\item{fig5_plot_all_time_rel_wis}{heatmap of the relative wis between +the two models} \item{fig5_heatmap_rel_wis_all_time}{heatmap comparing WIS across forecast dates for each location for all time} From 3eb1eaaef7b408e05f5f31f736378fd1f1128c15 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 15:56:51 +0000 Subject: [PATCH 053/110] exclude NAs --- wweval/R/ms_fig5.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index da4149d3..006bdf43 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -544,7 +544,8 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, fig_file_dir) { avg_rel_scores <- rel_scores |> dplyr::group_by(forecast_date, location) |> - dplyr::summarise(mean_rel_wis = mean(rel_wis)) + dplyr::summarise(mean_rel_wis = mean(rel_wis)) |> + dplyr::filter(!is.na(mea_rel_wis)) p <- ggplot(avg_rel_scores) + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + From d791d6df35a80c66f4eaa2c3ce1c699440580996 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 17:10:58 +0000 Subject: [PATCH 054/110] draft fig 5 --- _targets_eval_postprocessing.R | 16 ++++++--- wweval/R/ms_fig5.R | 55 +++++++++++++++++------------ wweval/man/make_fig5_average_wis.Rd | 2 ++ 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 75c5de3b..fab02b7e 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1574,7 +1574,11 @@ hub_comparison_plots <- list( tar_target( name = fig5_heatmap_rel_wis_feb_mar, command = make_fig5_heatmap_relative_wis( - scores = summarized_scores_feb_mar, + scores = summarized_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-wwrenewal(retro)", + "cfa-hosponlyrenewal(retro)" + )), models_to_show = models_to_plot, time_period = "Feb 2024-Mar 2024", baseline_model = "COVIDhub-4_week_ensemble" @@ -1591,9 +1595,13 @@ hub_comparison_plots <- list( tar_target( name = fig5_qq_plot_feb_mar, command = make_fig5_qq_plot( - scores = combine_scores_feb_mar, + scores = combine_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-wwrenewal(retro)", + "cfa-hosponlyrenewal(retro)" + )), models_to_show = models_to_plot, - time_period = "Feb 2024-Mar 2024" + time_period = "Feb-Mar 2024" ) ), tar_target( @@ -1601,7 +1609,7 @@ hub_comparison_plots <- list( command = make_fig5_density_rank( scores = summarized_scores_feb_mar, models_to_show = models_to_plot, - time_period = "Feb 2024-Mar 2024" + time_period = "Feb-Mar 2024" ) ), tar_target( diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 006bdf43..1e35efb1 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -59,6 +59,7 @@ make_fig5_table_and_plot <- function(scores, #' default is `c()` #' @param models_to_show A vector of charcter strings indicating which models #' from the COVID-19 forecast hub to include in the plot. +#' @param time_period String indicating the time period this plot pertains to #' @param horizon_time_in_weeks horizon time in weeks to summarize over, default #' is `NULL` which means that the scores are summarized over the nowcast period #' and the 4 week forecast period @@ -115,7 +116,7 @@ make_fig5_average_wis <- function(all_scores, x = forecast_date, y = interval_score, color = model )) + - guides(color = guide_legend(nrow = 2)) + + # guides(color = guide_legend(nrow = 5)) + xlab("") + ylab("Average WIS across locations") + get_plot_theme( @@ -129,7 +130,7 @@ make_fig5_average_wis <- function(all_scores, ggtitle(title) + scale_color_manual(values = colors$model_colors) + theme( - legend.position = "top", + legend.position = "left", legend.justification = "left", legend.direction = "horizontal", legend.title = element_blank(), @@ -314,16 +315,21 @@ make_fig5_density <- function(all_scores, ), point_interval = "mean_qi", alpha = 0.5, - position = position_dodge(width = 0.75) + position = position_dodge(width = 0.75), ) + coord_trans(ylim = c(0, 2)) + get_plot_theme( x_axis_dates = TRUE, y_axis_title_size = 8 ) + - guides(fill = guide_legend(nrow = 2)) + - scale_fill_manual(values = colors$model_colors) + - scale_color_manual(values = colors$model_colors) + + scale_fill_manual( + values = colors$model_colors, + guide = "none" + ) + + scale_color_manual( + values = colors$model_colors, + guide = "none" + ) + xlab("") + theme( legend.justification = "left", @@ -437,7 +443,8 @@ make_fig5_qq_plot <- function(scores, scoringutils::plot_quantile_coverage() + ggtitle(glue::glue("QQ plot for {time_period}")) + get_plot_theme() + - scale_color_manual(values = colors$model_colors) + theme(legend.position = "none") + + scale_color_manual(values = colors$model_colors, guide = "none") return(p) @@ -517,11 +524,14 @@ make_fig5_density_rank <- function(scores, position = ggridges::position_points_jitter(width = 0.05, height = 0), point_shape = "|", point_size = 3, point_alpha = 1, alpha = 0.7, ) + - scale_fill_viridis_d(name = "Quartiles") + + scale_fill_viridis_d(guide = "none") + get_plot_theme() + - scale_x_continuous(name = "Standardized rank", limits = c(0, 1)) + + scale_x_continuous( + name = "Standardized rank", limits = c(0, 1), + guide = "none" + ) + ylab("") + - ggtitle(glue::glue("Standardized rank {time_period}")) + ggtitle(glue::glue("Standardized rank \n {time_period}")) return(p) } @@ -545,7 +555,7 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, avg_rel_scores <- rel_scores |> dplyr::group_by(forecast_date, location) |> dplyr::summarise(mean_rel_wis = mean(rel_wis)) |> - dplyr::filter(!is.na(mea_rel_wis)) + dplyr::filter(!is.na(mean_rel_wis)) p <- ggplot(avg_rel_scores) + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + @@ -568,9 +578,9 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, labels = scales::date_format("%Y-%m-%d") ) + xlab("") + - ylab("Location") + + ylab("") + labs(fill = "Relative WIS") + - ggtitle(glue::glue("{analysis_type} mean relative WIS from {time_period}")) + ggtitle(glue::glue("{analysis_type} mean relative \n WIS between renewal models \n from {time_period}")) # nolint ggsave(p, width = 7, height = 6, @@ -628,10 +638,10 @@ make_fig5 <- function(fig5_plot_wis_t_real_time, fig5_std_rank_all_time, fig_file_dir) { layout <- " -ABC -DEF -GHI -JKL +AABCCC +DDEEFF +GGHIII +JJKKLL " fig5 <- fig5_plot_real_time_rel_wis + fig5_density_real_time + fig5_plot_wis_t_real_time + fig5_heatmap_rel_wis_feb_mar + fig5_qq_plot_feb_mar + fig5_std_rank_feb_mar + @@ -642,20 +652,21 @@ JKL axes = "collect", guides = "collect" ) & theme( - legend.position = "top", - legend.justification = "left" - ) #+ plot_annotation(tag_levels = "A") #nolint, not working + legend.position = "none" + ) + # legend.justification = "left" #nolint + # ) #+ plot_annotation(tag_levels = "A") #nolint, not working fs::dir_create(fig_file_dir) ggsave(fig5, filename = file.path(fig_file_dir, "fig5.png"), - width = 12, height = 12 + width = 12, height = 20 ) ggsave(fig5, filename = file.path(fig_file_dir, "fig5.svg"), - width = 12, height = 12 + width = 12, height = 20 ) return(fig5) diff --git a/wweval/man/make_fig5_average_wis.Rd b/wweval/man/make_fig5_average_wis.Rd index 9263b452..7e650efa 100644 --- a/wweval/man/make_fig5_average_wis.Rd +++ b/wweval/man/make_fig5_average_wis.Rd @@ -25,6 +25,8 @@ default is \code{c()}} \item{models_to_show}{A vector of charcter strings indicating which models from the COVID-19 forecast hub to include in the plot.} +\item{time_period}{String indicating the time period this plot pertains to} + \item{horizon_time_in_weeks}{horizon time in weeks to summarize over, default is \code{NULL} which means that the scores are summarized over the nowcast period and the 4 week forecast period} From d3d273e9c2176d23e2e1e549e4f0f439bfb6614a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 27 Nov 2024 20:06:11 +0000 Subject: [PATCH 055/110] forgot to remove retro from std ranking fig --- _targets_eval_postprocessing.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index fab02b7e..3f73a080 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1607,7 +1607,11 @@ hub_comparison_plots <- list( tar_target( name = fig5_std_rank_feb_mar, command = make_fig5_density_rank( - scores = summarized_scores_feb_mar, + scores = summarized_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-wwrenewal(retro)", + "cfa-hosponlyrenewal(retro)" + )), models_to_show = models_to_plot, time_period = "Feb-Mar 2024" ) From 1d29a8a05ceca4b28eb3fe8b052090ee60b58e61 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 14:03:00 +0000 Subject: [PATCH 056/110] separately compute mean rel crps and add to density plots --- _targets_eval_postprocessing.R | 14 ++- wweval/R/ms_fig4.R | 113 ++++++++++--------- wweval/man/make_fig4_rel_crps_by_location.Rd | 9 +- wweval/man/make_fig4_rel_crps_over_time.Rd | 9 +- 4 files changed, 68 insertions(+), 77 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 3f73a080..cf5db007 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -947,15 +947,14 @@ manuscript_figures <- list( tar_target( name = fig4_rel_crps_over_time, command = make_fig4_rel_crps_over_time( - scores_filtered, - horizons_to_show = "overall" + scores_filtered ) ), tar_target( name = loc_summary, command = get_loc_rel_crps( scores_filtered, - locs = c("DC", "OH") + locs = c("DC", "OH", "NH", "CO") ) ), tar_target( @@ -988,8 +987,7 @@ manuscript_figures <- list( tar_target( name = fig4_rel_crps_by_location, command = make_fig4_rel_crps_by_location( - scores_filtered, - horizons_to_show = "overall" + scores_filtered ) ), tar_target( @@ -1350,6 +1348,12 @@ hub_targets <- list( all_scores = scores_list_retro_hub_submissions$log_scale_scores ) ), + tar_target( + name = overall_all_time_rel_wis, + command = rel_all_time_wis |> + dplyr::ungroup() |> + dplyr::summarise(mean_rel_wis = mean(rel_wis, na.rm = TRUE)) + ), # Rename the model as retrospective tar_target( name = combine_scores_oct_mar_full, diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 77ef183d..65372724 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -16,6 +16,15 @@ make_fig4_results_table <- function(scores) { avg_ae = mean(ae_median) ) + # Above was averaged across models, get avg of rel_crps + overall_all_time_rel_crps <- scores |> + compute_relative_crps(id_cols = c( + "location", + "forecast_date", "date", "horizon" + )) |> + dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + + # By period (nowcast vs forecast) scores_by_period <- scores |> dplyr::group_by(model, period) |> @@ -27,7 +36,8 @@ make_fig4_results_table <- function(scores) { scores_tables <- list( scores_overall = scores_overall, - scores_by_period = scores_by_period + scores_by_period = scores_by_period, + overall_all_time_rel_crps = overall_all_time_rel_crps ) return(scores_tables) @@ -39,60 +49,46 @@ make_fig4_results_table <- function(scores) { #' @param scores A tibble of scores by location, forecast date, date and model, #' containing the outputs of `scoringutils::score()` on samples plus metadata #' transformed into a tibble. -#' @param horizons_to_show A vector of strings indicating the names of the -#' `horizon` that we want to show on the plot, must be a subset of -#' `nowcast`, `1 wk`, `2 wks`,`3 wks`, `4 wks` and `overall` -#' #' @return a ggplot object that is a vertical facet of violin plots colored #' by model type and broken down my horizon #' @export -make_fig4_rel_crps_over_time <- function(scores, - horizons_to_show = c( - "nowcast", - "1 wk", "4 wks", - "overall" - )) { - scores_by_horizon <- scores +make_fig4_rel_crps_over_time <- function(scores) { scores_overall <- scores |> dplyr::mutate( horizon = "overall" ) - scores_comb <- dplyr::bind_rows(scores_by_horizon, scores_overall) |> - dplyr::filter( - horizon %in% !!horizons_to_show - ) - - relative_crps <- scores_comb |> + relative_crps <- scores_overall |> compute_relative_crps(id_cols = c( "location", "forecast_date", "date", "horizon" - )) |> - dplyr::filter(!is.na(horizon)) |> - order_horizons() + )) + + + mean_rel_crps <- relative_crps |> + dplyr::group_by(forecast_date, horizon) |> + dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) colors <- plot_components() date_lims <- c(range(scores$forecast_date)) - p <- ggplot( - relative_crps, - aes( - x = as.factor(forecast_date), y = rel_crps, color = horizon, - fill = horizon - ), - show.legend = FALSE - ) + - tidybayes::stat_halfeye( + p <- ggplot(relative_crps) + + tidybayes::stat_slab( aes( x = as.factor(forecast_date), y = rel_crps, fill = horizon ), - point_interval = "mean_qi", alpha = 0.5, position = position_dodge(width = 0.75), show.legend = FALSE ) + + geom_point( + data = mean_rel_crps, + aes(x = as.factor(forecast_date), y = mean_rel_crps), + size = 1.5, + color = "black" + ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + xlab("") + ylab("Relative CRPS") + @@ -256,32 +252,18 @@ get_loc_rel_crps <- function(scores, locs) { #' @param scores A tibble of scores by location, forecast date, date and model, #' containing the outputs of `scoringutils::score()` on samples plus metadata #' transformed into a tibble. -#' @param horizons_to_show A vector of strings indicating the names of the -#' `horizon` that we want to show on the plot, must be a subset of -#' `nowcast`, `1 wk`, `2 wks`,`3 wks`, `4 wks` and `overall` #' #' @return A ggplot object containing plots of the distribution of relative #' CRPS scores by location, across forecast dates, colored by location #' @export -make_fig4_rel_crps_by_location <- function(scores, - horizons_to_show = c( - "nowcast", - "1 wk", "4 wks", - "overall" - )) { - scores_by_horizon <- scores +make_fig4_rel_crps_by_location <- function(scores) { scores_overall <- scores |> dplyr::mutate( horizon = "overall" ) - scores_comb <- dplyr::bind_rows(scores_by_horizon, scores_overall) |> - dplyr::filter( - horizon %in% !!horizons_to_show - ) - - relative_crps <- scores_comb |> + relative_crps <- scores_overall |> compute_relative_crps(id_cols = c( "location", "forecast_date", "date", @@ -290,23 +272,27 @@ make_fig4_rel_crps_by_location <- function(scores, dplyr::filter(!is.na(horizon)) |> order_horizons() + mean_rel_crps <- relative_crps |> + group_by(horizon, location) |> + summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + colors <- plot_components() - p <- ggplot(relative_crps, aes( - x = location, y = rel_crps, color = horizon, - fill = horizon, - show.legend = FALSE - )) + - tidybayes::stat_halfeye( + p <- ggplot(relative_crps) + + tidybayes::stat_slab( aes( x = location, y = rel_crps, fill = horizon ), - point_interval = "mean_qi", alpha = 0.5, position = position_dodge(width = 0.75), show.legend = FALSE ) + + geom_point( + data = mean_rel_crps, + aes(x = location, y = mean_rel_crps), + size = 1 + ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + theme_bw() + get_plot_theme( @@ -362,18 +348,33 @@ make_fig4_rel_crps_overall <- function(scores, colors <- plot_components() + mean_rel_crps <- relative_crps |> + dplyr::group_by(horizon) |> + dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + quartiled_rel_crps <- relative_crps |> + dplyr::group_by(horizon) |> + dplyr::summarize( + lb_25th = quantile(rel_crps, probs = 0.25), + ub_75 = quantile(rel_crps, probs = 0.75) + ) |> + tidyr::pivot_longer(!horizon) + p <- ggplot(relative_crps) + - tidybayes::stat_halfeye( + tidybayes::stat_slab( aes( x = horizon, y = rel_crps, fill = horizon ), - point_interval = "mean_qi", alpha = 0.5, position = position_dodge(width = 0.75), show.legend = FALSE ) + + geom_point( + data = mean_rel_crps, + aes(x = horizon, y = mean_rel_crps), + size = 4 + ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + xlab("Horizon") + ylab("Relative CRPS") + diff --git a/wweval/man/make_fig4_rel_crps_by_location.Rd b/wweval/man/make_fig4_rel_crps_by_location.Rd index 8835305e..70cf8d2d 100644 --- a/wweval/man/make_fig4_rel_crps_by_location.Rd +++ b/wweval/man/make_fig4_rel_crps_by_location.Rd @@ -4,19 +4,12 @@ \alias{make_fig4_rel_crps_by_location} \title{Make figure that stratifies scores by location across forecast dates} \usage{ -make_fig4_rel_crps_by_location( - scores, - horizons_to_show = c("nowcast", "1 wk", "4 wks", "overall") -) +make_fig4_rel_crps_by_location(scores) } \arguments{ \item{scores}{A tibble of scores by location, forecast date, date and model, containing the outputs of \code{scoringutils::score()} on samples plus metadata transformed into a tibble.} - -\item{horizons_to_show}{A vector of strings indicating the names of the -\code{horizon} that we want to show on the plot, must be a subset of -\code{nowcast}, \verb{1 wk}, \verb{2 wks},\verb{3 wks}, \verb{4 wks} and \code{overall}} } \value{ A ggplot object containing plots of the distribution of relative diff --git a/wweval/man/make_fig4_rel_crps_over_time.Rd b/wweval/man/make_fig4_rel_crps_over_time.Rd index c0072dc5..35e4dc14 100644 --- a/wweval/man/make_fig4_rel_crps_over_time.Rd +++ b/wweval/man/make_fig4_rel_crps_over_time.Rd @@ -4,19 +4,12 @@ \alias{make_fig4_rel_crps_over_time} \title{Make a CRPS density plot for a subset of locations} \usage{ -make_fig4_rel_crps_over_time( - scores, - horizons_to_show = c("nowcast", "1 wk", "4 wks", "overall") -) +make_fig4_rel_crps_over_time(scores) } \arguments{ \item{scores}{A tibble of scores by location, forecast date, date and model, containing the outputs of \code{scoringutils::score()} on samples plus metadata transformed into a tibble.} - -\item{horizons_to_show}{A vector of strings indicating the names of the -\code{horizon} that we want to show on the plot, must be a subset of -\code{nowcast}, \verb{1 wk}, \verb{2 wks},\verb{3 wks}, \verb{4 wks} and \code{overall}} } \value{ a ggplot object that is a vertical facet of violin plots colored From ff5bdc197b65ec5325157be724d645c601f11d45 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 15:23:12 +0000 Subject: [PATCH 057/110] fix fig 5 to properly compute mena rel crps --- wweval/R/ms_fig5.R | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 1e35efb1..8394e025 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -304,11 +304,14 @@ make_fig5_density <- function(all_scores, dplyr::mutate(relative_wis = interval_score / baseline_score) |> dplyr::filter(model != {{ baseline_model }}) + mean_rel_wis <- scores_final |> + dplyr::group_by(model) |> + dplyr::summarize(mean_rel_wis = mean(relative_wis, na.rm = TRUE)) colors <- plot_components() p <- ggplot(scores_final) + - tidybayes::stat_halfeye( + tidybayes::stat_slab( aes( x = model, y = relative_wis + 1e-8, fill = model @@ -317,6 +320,11 @@ make_fig5_density <- function(all_scores, alpha = 0.5, position = position_dodge(width = 0.75), ) + + geom_point( + data = mean_rel_wis, + aes(x = model, y = mean_rel_wis), + size = 3 + ) + coord_trans(ylim = c(0, 2)) + get_plot_theme( x_axis_dates = TRUE, From a53c5c437ee4319ceb3efe42e9a482e4ce7bf78f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 16:06:06 +0000 Subject: [PATCH 058/110] add the two different ways of computing the mean rel crps --- wweval/R/ms_fig3.R | 75 +++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 8ef427c3..8e9d6e16 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -22,9 +22,31 @@ get_summary_table_fig3 <- function(scores, values_from = mean_crps ) |> dplyr::mutate( - rel_crps = mean_crps_ww / mean_crps_hosp + rel_crps_means = mean_crps_ww / mean_crps_hosp ) + raw_rel_scores <- scores |> + dplyr::filter( + location %in% locs_to_plot + ) |> + tidyr::pivot_wider( + id_cols = c("location", "date", "forecast_date"), + names_from = "model", + names_prefix = "crps_", + values_from = crps + ) |> + dplyr::mutate(rel_crps = crps_ww / crps_hosp) |> + dplyr::group_by(location) |> + dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + + scores_summary <- raw_rel_scores |> dplyr::left_join(scores_locs, + by = "location" + ) + + + + + return(scores_locs) } @@ -76,19 +98,9 @@ make_fig3_single_loc_comp <- function(scores, )) { scores_by_horizon <- scores |> dplyr::filter(location == !!loc_to_plot) |> - data.table::as.data.table() |> - scoringutils::summarise_scores(by = c( - "forecast_date", "location", - "model", "horizon" - )) |> dplyr::filter(horizon %in% !!horizons_to_show) scores_overall <- scores |> dplyr::filter(location == !!loc_to_plot) |> - data.table::as.data.table() |> - scoringutils::summarise_scores(by = c( - "forecast_date", "location", - "model" - )) |> dplyr::mutate(horizon = "overall") scores_comb <- dplyr::bind_rows(scores_by_horizon, scores_overall) |> @@ -97,28 +109,49 @@ make_fig3_single_loc_comp <- function(scores, ) |> order_horizons() + relative_crps <- scores_comb |> + compute_relative_crps(id_cols = c( + "location", "forecast_date", + "horizon", "date" + )) |> + dplyr::filter(!is.na(horizon)) |> + order_horizons() + + mean_rel_crps <- relative_crps |> + dplyr::group_by(horizon) |> + dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + colors <- plot_components() - p <- ggplot(scores_comb) + - tidybayes::stat_halfeye( + p <- ggplot(relative_crps) + + tidybayes::stat_slab( aes( - x = horizon, y = crps, - fill = model + x = horizon, y = rel_crps, + fill = horizon ), point_interval = "mean_qi", alpha = 0.5, - position = position_dodge(width = 0.75) + position = position_dodge(width = 0.75), + show.legend = FALSE + ) + + geom_point( + data = mean_rel_crps, + aes(x = horizon, mean_rel_crps), + size = 3 ) + xlab("") + - ylab("CRPS") + + ylab("Relative CRPS") + ggtitle(glue::glue( "{loc_to_plot}" )) + theme_bw() + - scale_color_manual(values = colors$model_colors) + - scale_fill_manual(values = colors$model_colors) + - get_plot_theme(y_axis_title_size = 8) + - scale_y_continuous(trans = "log10", limits = c(0.03, 1.5)) + + scale_color_manual(values = colors$horizon_colors) + + scale_fill_manual(values = colors$horizon_colors) + + get_plot_theme( + y_axis_title_size = 8, + x_axis_text_size = 6 + ) + + scale_y_continuous(trans = "log10") + # , limits = c(0.25, 4.0)) + labs(color = "Model", fill = "Model") return(p) From cc74ecb2128382be81f5cb4e969255dc9f714889 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 16:16:37 +0000 Subject: [PATCH 059/110] fix bug --- wweval/R/ms_fig3.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 8e9d6e16..8a649d3a 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -47,7 +47,7 @@ get_summary_table_fig3 <- function(scores, - return(scores_locs) + return(scores_summary) } #' Get an individual forecast score summary for a particular From 51974a26d67f6eef998f4e59f9f7d97346a4e327 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 17:06:01 +0000 Subject: [PATCH 060/110] add a plot of the distribution of relative crps scores --- _targets_eval_postprocessing.R | 7 +++ wweval/R/supplement_analyses_and_figs.R | 67 ++++++++++++++++++++++++- wweval/man/get_plot_rel_crps_distrib.Rd | 19 +++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 wweval/man/get_plot_rel_crps_distrib.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index cf5db007..503324a8 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1766,6 +1766,13 @@ supp_targets <- list( scores = scores_filtered, threshold = 0.1 ) + ), + tar_target( + name = plot_rel_crps_distrib, + command = get_plot_rel_crps_distrib( + scores = scores_filtered, + fig_file_dir = eval_config$ms_fig_dir + ) ) ) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index d05d376c..9786b603 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -665,9 +665,34 @@ get_stats_improved_forecasts <- function(scores, "location", "forecast_date" )) |> dplyr::mutate( - pct_change_crps = (ww - hosp) / hosp + pct_change_crps = (ww - hosp) / hosp, + rel_crps = ww / hosp ) + relative_crps_raw <- scores |> + compute_relative_crps(id_cols = c( + "location", "forecast_date", "date" + )) |> + dplyr::mutate( + pct_change_crps = (ww - hosp) / hosp, + rel_crps = ww / hosp + ) + + ggplot(relative_crps_by_forecast) + + geom_histogram(aes(x = pct_change_crps)) + + ggplot(relative_crps_raw) + + geom_histogram(aes(x = pct_change_crps)) + ggplot(relative_crps_raw) + + geom_histogram(aes(x = rel_crps)) + + scale_x_continuous(trans = "log10") + + + + + forecasts_way_worse <- relative_crps_by_forecast |> + dplyr::filter(pct_change_crps > 3) + n_forecasts_3x_worse <- forecasts_way_worse |> nrow() n_forecasts_better <- relative_crps_by_forecast |> dplyr::filter(pct_change_crps < threshold) |> nrow() @@ -683,12 +708,50 @@ get_stats_improved_forecasts <- function(scores, n_states_better, n_states_worse, n_forecasts_better, - n_forecasts_worse + n_forecasts_worse, + n_forecasts_3x_worse ) return(stats) } +#' Get a density plot of the relative CRPS distribution +#' +#' @param scores tibble of scores by horizon day, forecast date, and location +#' @param fig_file_dir directory to save figure in +#' +#' @return ggplot object of distribution of relative CRPS scores +get_plot_rel_crps_distrib <- function(scores, + fig_file_dir) { + relative_crps_by_forecast <- scores |> + dplyr::group_by(location, model, forecast_date) |> + dplyr::summarize(crps = mean(crps)) |> + compute_relative_crps(id_cols = c( + "location", "forecast_date" + )) |> + dplyr::mutate( + pct_change_crps = (ww - hosp) / hosp, + rel_crps = ww / hosp + ) + p <- ggplot(relative_crps_by_forecast) + + geom_density(aes(x = rel_crps), + fill = "darkblue" + ) + + geom_vline(aes(xintercept = 1), linetype = "dashed") + + get_plot_theme() + + ylab("Density") + + xlab("Relative CRPS by forecast date and location") + + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_distrib_rel_crps.png") + ) + ) + return(p) +} + + get_plot_sites_vs_performance <- function(scores, ww_metadata, fig_file_dir) { diff --git a/wweval/man/get_plot_rel_crps_distrib.Rd b/wweval/man/get_plot_rel_crps_distrib.Rd new file mode 100644 index 00000000..f9987d1c --- /dev/null +++ b/wweval/man/get_plot_rel_crps_distrib.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/supplement_analyses_and_figs.R +\name{get_plot_rel_crps_distrib} +\alias{get_plot_rel_crps_distrib} +\title{Get a density plot of the relative CRPS distribution} +\usage{ +get_plot_rel_crps_distrib(scores, fig_file_dir) +} +\arguments{ +\item{scores}{tibble of scores by horizon day, forecast date, and location} + +\item{fig_file_dir}{directory to save figure in} +} +\value{ +ggplot object of distribution of relative CRPS scores +} +\description{ +Get a density plot of the relative CRPS distribution +} From 974a1c68b2518037763ea30ad80b6525553b8afc Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 17:12:57 +0000 Subject: [PATCH 061/110] add log scale x axis of density plot --- wweval/R/supplement_analyses_and_figs.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 9786b603..bbb4e557 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -741,6 +741,7 @@ get_plot_rel_crps_distrib <- function(scores, get_plot_theme() + ylab("Density") + xlab("Relative CRPS by forecast date and location") + p_log <- p + scale_x_continuous(trans = "log10") ggsave(p, filename = file.path( @@ -748,6 +749,13 @@ get_plot_rel_crps_distrib <- function(scores, glue::glue("sfig_distrib_rel_crps.png") ) ) + + ggsave(p_log, + filename = file.path( + fig_file_dir, + glue::glue("sfig_distrib_rel_crps_log.png") + ) + ) return(p) } From c7f59cd38273e2efc2d531d9d5ee1735be82c517 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 17:39:01 +0000 Subject: [PATCH 062/110] add forecasts better to output summary stats --- wweval/R/supplement_analyses_and_figs.R | 32 ++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index bbb4e557..cb88b1df 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -693,12 +693,35 @@ get_stats_improved_forecasts <- function(scores, forecasts_way_worse <- relative_crps_by_forecast |> dplyr::filter(pct_change_crps > 3) n_forecasts_3x_worse <- forecasts_way_worse |> nrow() + + forecasts_way_better <- relative_crps_by_forecast |> + dplyr::filter(pct_change_crps < -3) + n_forecasts_3x_better <- forecasts_way_better |> nrow() + n_forecasts_better <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps < threshold) |> + dplyr::filter(pct_change_crps < 0) |> nrow() n_forecasts_worse <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps > threshold) |> + dplyr::filter(pct_change_crps > 0) |> + nrow() + + n_forecasts_better_thres <- relative_crps_by_forecast |> + dplyr::filter( + pct_change_crps < 0, + abs(pct_change_crps) > threshold + ) |> + nrow() + + n_forecasts_worse <- relative_crps_by_forecast |> + dplyr::filter(pct_change_crps > 0) |> + nrow() + + n_forecasts_worse_thres <- relative_crps_by_forecast |> + dplyr::filter( + pct_change_crps > 0, + abs(pct_change_crps) > threshold + ) |> nrow() @@ -709,7 +732,10 @@ get_stats_improved_forecasts <- function(scores, n_states_worse, n_forecasts_better, n_forecasts_worse, - n_forecasts_3x_worse + n_forecasts_better_thres, + n_forecasts_worse_thres, + n_forecasts_3x_worse, + n_forecasts_3x_better ) return(stats) From 8458be5589ec470b99505e7116887511e6e06b84 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 21:32:17 +0000 Subject: [PATCH 063/110] add functionality to exclude the manual exclusions from metadata summary since we are not incl in retro, but are including in hub --- wweval/R/combine_and_summarize_ww_data.R | 32 +++++++++++++++--------- wweval/R/supplement_analyses_and_figs.R | 13 +++------- wweval/man/get_add_ww_metadata.Rd | 7 +++++- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/wweval/R/combine_and_summarize_ww_data.R b/wweval/R/combine_and_summarize_ww_data.R index db078ab2..84c989fe 100644 --- a/wweval/R/combine_and_summarize_ww_data.R +++ b/wweval/R/combine_and_summarize_ww_data.R @@ -245,6 +245,9 @@ load_data_and_summarize <- function(fp_hosp, fp_ww, #' date location combination #' @param table_of_loc_dates_w_ww table containing wastewater metadata #' for every location-forecast date with wastewater +#' @param include_manual_exclusions boolean indicating whether or not the +#' ww metadata should include manual exclusiosn, default is FALSE bc isn't +#' used in main retro head to head analysis. #' #' @return a tibble with a number of additional columns indicating whether #' or not there were any flags for manual exclusions, convergence issues, @@ -253,20 +256,10 @@ load_data_and_summarize <- function(fp_hosp, fp_ww, get_add_ww_metadata <- function(granular_ww_metadata, ww_forecast_date_locs_to_excl, convergence_df, - table_of_loc_dates_w_ww) { + table_of_loc_dates_w_ww, + include_manual_exclusions = FALSE) { granular_ww_metadata_used <- granular_ww_metadata |> dplyr::mutate(forecast_date = lubridate::ymd(.data$forecast_date)) |> - dplyr::left_join( - ww_forecast_date_locs_to_excl |> - mutate( - ww_exclude_manual = TRUE, - forecast_date = lubridate::ymd(.data$forecast_date) - ), - by = c("location", "forecast_date") - ) |> - dplyr::mutate( - ww_exclude_manual = tidyr::replace_na(.data$ww_exclude_manual, FALSE) - ) |> dplyr::left_join(convergence_df, by = c("location", "forecast_date") ) |> @@ -274,6 +267,21 @@ get_add_ww_metadata <- function(granular_ww_metadata, by = c("location", "forecast_date") ) + if (isTRUE(include_manual_exclusions)) { + granular_ww_metadata_used <- granular_ww_metadata_used |> + dplyr::left_join( + ww_forecast_date_locs_to_excl |> + mutate( + ww_exclude_manual = TRUE, + forecast_date = lubridate::ymd(.data$forecast_date) + ), + by = c("location", "forecast_date") + ) |> + dplyr::mutate( + ww_exclude_manual = tidyr::replace_na(.data$ww_exclude_manual, FALSE) + ) + } + return(granular_ww_metadata_used) } diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index cb88b1df..e974746f 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -987,7 +987,7 @@ get_summary_metadata <- function(metadata) { metadata_summarized <- metadata |> dplyr::select( forecast_date, location, ww_data_present, - ww_exclude_manual, ww_sufficient, + ww_sufficient, any_flags_hosp, any_flags_ww ) @@ -1001,13 +1001,8 @@ get_summary_metadata <- function(metadata) { n_conv_issues <- nrow(metadata_remove_insuff_ww) - nrow(metadata_remove_conv_issues) - metadata_man_excl <- metadata_remove_conv_issues |> - dplyr::filter(ww_exclude_manual == FALSE) - - n_excl <- nrow(metadata_remove_conv_issues) - nrow(metadata_man_excl) - - summary_table <- tibble::tibble(n_insuff_ww, n_conv_issues, n_excl, - n_forecasts = nrow(metadata_man_excl) + summary_table <- tibble::tibble(n_insuff_ww, n_conv_issues, + n_forecasts = nrow(metadata_remove_conv_issues) ) return(summary_table) @@ -1027,7 +1022,7 @@ get_heatmap_metadata <- function(metadata, metadata_summarized <- metadata |> dplyr::select( forecast_date, location, ww_data_present, - ww_exclude_manual, ww_sufficient, + ww_sufficient, any_flags_hosp, any_flags_ww ) |> dplyr::ungroup() diff --git a/wweval/man/get_add_ww_metadata.Rd b/wweval/man/get_add_ww_metadata.Rd index 8a765f05..13584875 100644 --- a/wweval/man/get_add_ww_metadata.Rd +++ b/wweval/man/get_add_ww_metadata.Rd @@ -8,7 +8,8 @@ get_add_ww_metadata( granular_ww_metadata, ww_forecast_date_locs_to_excl, convergence_df, - table_of_loc_dates_w_ww + table_of_loc_dates_w_ww, + include_manual_exclusions = FALSE ) } \arguments{ @@ -25,6 +26,10 @@ date location combination} \item{table_of_loc_dates_w_ww}{table containing wastewater metadata for every location-forecast date with wastewater} + +\item{include_manual_exclusions}{boolean indicating whether or not the +ww metadata should include manual exclusiosn, default is FALSE bc isn't +used in main retro head to head analysis.} } \value{ a tibble with a number of additional columns indicating whether From 037b72ecce6cb7695ac4ecaa7257f27881ba2e7d Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 21:33:01 +0000 Subject: [PATCH 064/110] update targets pipeline with new metadata and convergence exclusions --- _targets_eval_postprocessing.R | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 503324a8..3d1b7880 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -371,6 +371,10 @@ head_to_head_targets <- list( "forecast_date" ) ) |> + dplyr::filter( + any_flags_ww == FALSE, + any_flags_hosp == FALSE + ) |> dplyr::anti_join( ww_forecast_date_locs_to_excl |> dplyr::mutate(forecast_date = lubridate::ymd(forecast_date)), @@ -414,6 +418,10 @@ head_to_head_targets <- list( "forecast_date" ) ) |> + dplyr::filter( + any_flags_ww == FALSE, + any_flags_hosp == FALSE + ) |> dplyr::left_join( last_hosp_data_date_map, by = c("location", "forecast_date") @@ -455,6 +463,10 @@ head_to_head_targets <- list( "forecast_date" ) ) |> + dplyr::filter( + any_flags_ww == FALSE, + any_flags_hosp == FALSE + ) |> dplyr::left_join( last_hosp_data_date_map, by = c("location", "forecast_date") @@ -505,7 +517,18 @@ manuscript_figures <- list( granular_ww_metadata, ww_forecast_date_locs_to_excl, convergence_df, - table_of_loc_dates_w_ww + table_of_loc_dates_w_ww, + include_manual_exclusions = FALSE + ) + ), + tar_target( + name = granular_ww_metadata_used_hub, + command = get_add_ww_metadata( + granular_ww_metadata, + ww_forecast_date_locs_to_excl, + convergence_df, + table_of_loc_dates_w_ww, + include_manual_exclusions = TRUE ) ), tar_target( @@ -525,7 +548,7 @@ manuscript_figures <- list( tar_target( name = sfig_heatmap_metadata_hub, command = get_heatmap_metadata_hub( - granular_ww_metadata_used, + granular_ww_metadata_used_hub, fig_file_dir = eval_config$ms_fig_dir ) ), From a4d119ba60f3b23f225ddf4322c92edfb3747835 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Fri, 29 Nov 2024 21:59:32 +0000 Subject: [PATCH 065/110] fix bug in summary tables --- wweval/R/combine_and_summarize_ww_data.R | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/wweval/R/combine_and_summarize_ww_data.R b/wweval/R/combine_and_summarize_ww_data.R index 84c989fe..9651e86d 100644 --- a/wweval/R/combine_and_summarize_ww_data.R +++ b/wweval/R/combine_and_summarize_ww_data.R @@ -356,16 +356,10 @@ get_summary_ww_table <- function(ww_metadata, hosp_quantiles_filtered) { ) |> dplyr::pull("n_ww_insuff") - n_ww_excluded <- ww_metadata |> - dplyr::summarise( - n_ww_excluded = sum(.data$ww_exclude_manual, na.rm = TRUE) - ) |> - dplyr::pull(.data$n_ww_excluded) - n_w_ww_expected <- ww_metadata |> dplyr::mutate( ww_expected = dplyr::case_when( - ww_data_present == 1 & !(.data$ww_exclude_manual) & + ww_data_present == 1 & !(.data$any_flags_hosp) & !(.data$any_flags_ww) & isTRUE(.data$ww_sufficient) ~ TRUE, TRUE ~ FALSE @@ -387,7 +381,6 @@ get_summary_ww_table <- function(ww_metadata, hosp_quantiles_filtered) { n_combos_w_hosp_conv_flags, n_combos_w_ww_conv_flags, n_insuff_ww, - n_ww_excluded, n_no_ww_expected, n_no_ww_actual, n_w_ww_expected, From 26855d540a84b1479f818027319e404b4e75cb52 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 13:39:57 +0000 Subject: [PATCH 066/110] tweaks to Fig 5 --- wweval/R/ms_fig5.R | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 8394e025..28eb26ce 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -116,7 +116,7 @@ make_fig5_average_wis <- function(all_scores, x = forecast_date, y = interval_score, color = model )) + - # guides(color = guide_legend(nrow = 5)) + + guides(color = guide_legend(nrow = 2)) + xlab("") + ylab("Average WIS across locations") + get_plot_theme( @@ -130,8 +130,7 @@ make_fig5_average_wis <- function(all_scores, ggtitle(title) + scale_color_manual(values = colors$model_colors) + theme( - legend.position = "left", - legend.justification = "left", + legend.position = "top", legend.direction = "horizontal", legend.title = element_blank(), legend.text = element_text(size = 7) @@ -346,7 +345,7 @@ make_fig5_density <- function(all_scores, legend.title = element_blank(), legend.text = element_text(size = 7) ) + - ylab(glue::glue("{analysis_type} relative WIS \n compared to {baseline_model}")) + ylab(glue::glue("Relative WIS compared to \n {baseline_model}")) @@ -420,7 +419,7 @@ make_fig5_heatmap_relative_wis <- function(scores, xlab("") + ylab("") + labs(fill = "Relative WIS") + - ggtitle(glue::glue("Relative WIS compared to \n {baseline_model} \n from {time_period}")) + ggtitle(glue::glue("Relative WIS compared to \n {baseline_model}")) return(p) @@ -449,7 +448,7 @@ make_fig5_qq_plot <- function(scores, data.table::as.data.table() |> scoringutils::summarise_scores(by = c("model", "quantile")) |> scoringutils::plot_quantile_coverage() + - ggtitle(glue::glue("QQ plot for {time_period}")) + + ggtitle(glue::glue("QQ plot")) + get_plot_theme() + theme(legend.position = "none") + scale_color_manual(values = colors$model_colors, guide = "none") @@ -535,11 +534,10 @@ make_fig5_density_rank <- function(scores, scale_fill_viridis_d(guide = "none") + get_plot_theme() + scale_x_continuous( - name = "Standardized rank", limits = c(0, 1), - guide = "none" + name = "Standardized rank", limits = c(0, 1) ) + ylab("") + - ggtitle(glue::glue("Standardized rank \n {time_period}")) + ggtitle(glue::glue("Standardized rank")) return(p) } @@ -588,7 +586,7 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, xlab("") + ylab("") + labs(fill = "Relative WIS") + - ggtitle(glue::glue("{analysis_type} mean relative \n WIS between renewal models \n from {time_period}")) # nolint + ggtitle(glue::glue(" Relative WIS of wastewater \n informed model compared to \n hospital admissions-only model")) # nolint ggsave(p, width = 7, height = 6, @@ -677,5 +675,29 @@ JJKKLL width = 12, height = 20 ) + + fig5_at <- fig5_plot_all_time_rel_wis + fig5_density_all_time + fig5_plot_wis_t_all_time + + fig5_heatmap_rel_wis_all_time + fig5_qq_plot_all_time + fig5_std_rank_all_time + + patchwork::plot_layout( + design = layout, + axes = "collect", + guides = "collect" + ) & theme( + legend.position = "none" + ) + # legend.justification = "left" #nolint + # ) #+ plot_annotation(tag_levels = "A") #nolint, not working + + fs::dir_create(fig_file_dir) + + ggsave(fig5_at, + filename = file.path(fig_file_dir, "fig5_at.png"), + width = 12, height = 10 + ) + + ggsave(fig5_at, + filename = file.path(fig_file_dir, "fig5_at.svg"), + width = 12, height = 10 + ) return(fig5) } From 847208eaf90ee6788b8825a789a958cc17fbd066 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 14:56:30 +0000 Subject: [PATCH 067/110] tweaks to fig3 --- _targets_eval_postprocessing.R | 18 +++++++++--------- wweval/R/ms_fig3.R | 30 ++++++++++++++---------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 3d1b7880..7971ada1 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -725,7 +725,7 @@ manuscript_figures <- list( loc_to_plot = locs_to_plot[1], horizon_to_plot = "nowcast", horizon_days_ahead = -10, - days_to_shift = -10 + days_to_shift = -8 ) ), tar_target( @@ -735,7 +735,7 @@ manuscript_figures <- list( loc_to_plot = locs_to_plot[1], horizon_to_plot = "1 wk", horizon_days_ahead = 7, - days_to_shift = 0 + days_to_shift = 2 ) ), tar_target( @@ -745,7 +745,7 @@ manuscript_figures <- list( loc_to_plot = locs_to_plot[1], horizon_to_plot = "4 wks", horizon_days_ahead = 28, - days_to_shift = 21 + days_to_shift = 24 ) ), # This is supplementary but useful alongside @@ -807,7 +807,7 @@ manuscript_figures <- list( scores_filtered, loc_to_plot = locs_to_plot[2], horizon_to_plot = "nowcast", - days_to_shift = -10, + days_to_shift = -8, horizon_days_ahead = -10 ) ), @@ -817,7 +817,7 @@ manuscript_figures <- list( scores_filtered, loc_to_plot = locs_to_plot[2], horizon_to_plot = "1 wk", - days_to_shift = 0, + days_to_shift = 2, horizon_days_ahead = 7 ) ), @@ -827,7 +827,7 @@ manuscript_figures <- list( scores_filtered, loc_to_plot = locs_to_plot[2], horizon_to_plot = "4 wks", - days_to_shift = 21, + days_to_shift = 24, horizon_days_ahead = 28 ) ), @@ -888,7 +888,7 @@ manuscript_figures <- list( scores_filtered, loc_to_plot = locs_to_plot[3], horizon_to_plot = "nowcast", - days_to_shift = -10, + days_to_shift = -8, horizon_days_ahead = -10 ) ), @@ -898,7 +898,7 @@ manuscript_figures <- list( scores_filtered, loc_to_plot = locs_to_plot[3], horizon_to_plot = "1 wk", - days_to_shift = 0, + days_to_shift = 2, horizon_days_ahead = 7 ) ), @@ -908,7 +908,7 @@ manuscript_figures <- list( scores_filtered, loc_to_plot = locs_to_plot[3], horizon_to_plot = "4 wks", - days_to_shift = 21, + days_to_shift = 24, horizon_days_ahead = 28 ) ), diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 8a649d3a..4dc142d7 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -141,9 +141,6 @@ make_fig3_single_loc_comp <- function(scores, ) + xlab("") + ylab("Relative CRPS") + - ggtitle(glue::glue( - "{loc_to_plot}" - )) + theme_bw() + scale_color_manual(values = colors$horizon_colors) + scale_fill_manual(values = colors$horizon_colors) + @@ -200,17 +197,17 @@ make_fig3_forecast_comp_fig <- function(hosp_quantiles, ) colors <- plot_components() - + max_obs <- max(hosp_quants_horizons$eval_data) date_lims <- c( - min(hosp_quantiles$forecast_date) + lubridate::days(horizon_days_ahead - 7), - max(hosp_quantiles$forecast_date) + lubridate::days(horizon_days_ahead + 3) + min(hosp_quantiles$forecast_date) + lubridate::days(horizon_days_ahead - 9), + max(hosp_quantiles$forecast_date) + lubridate::days(horizon_days_ahead + 5) ) p <- ggplot(hosp) + geom_point( data = hosp_quants_horizons, aes(x = date, y = eval_data), - fill = "black", size = 0.5, shape = 21, + fill = "black", size = 0.3, shape = 21, show.legend = FALSE ) + geom_ribbon( @@ -242,9 +239,6 @@ make_fig3_forecast_comp_fig <- function(hosp_quantiles, ) + xlab("") + ylab("Daily hospital \n admissions") + - ggtitle(glue::glue( - "{horizon_to_plot}" - )) + scale_color_manual(values = colors$model_colors) + scale_fill_manual(values = colors$model_colors) + scale_x_date( @@ -254,9 +248,11 @@ make_fig3_forecast_comp_fig <- function(hosp_quantiles, ) + get_plot_theme( x_axis_dates = TRUE, - y_axis_title_size = 6 + y_axis_title_size = 6, + y_axis_text_size = 6 ) + - guides(fill = "none", color = "none") + guides(fill = "none", color = "none") + + ylim(0, 2 * max_obs) return(p) } @@ -299,10 +295,11 @@ make_fig3_crps_underlay_fig <- function(scores, colors <- plot_components() date_lims <- c( - min(scores$forecast_date) + lubridate::days(horizon_days_ahead - 7), + min(scores$forecast_date) + lubridate::days(horizon_days_ahead - 9), max(scores$forecast_date) + - lubridate::days(horizon_days_ahead + 3) + lubridate::days(horizon_days_ahead + 5) ) + max_crps <- max(scores_by_horizon$crps) p <- ggplot(scores_by_horizon) + geom_bar(aes(x = forecast_date_shifted, y = crps, fill = model), @@ -319,11 +316,12 @@ make_fig3_crps_underlay_fig <- function(scores, ) + get_plot_theme( x_axis_dates = TRUE, - y_axis_title_size = 8 + y_axis_title_size = 8, + y_axis_text_size = 6 ) + scale_y_continuous( # don't expand y scale at the lower end - expand = expansion(mult = c(0, 0.05)) + limits = c(0, max_crps + 0.05) ) From 7387f3c5c9d9757828cac7556ebdc5cfc7c60c09 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 15:24:18 +0000 Subject: [PATCH 068/110] remove limits for now on fig3 --- wweval/R/ms_fig3.R | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 4dc142d7..605772a4 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -318,10 +318,6 @@ make_fig3_crps_underlay_fig <- function(scores, x_axis_dates = TRUE, y_axis_title_size = 8, y_axis_text_size = 6 - ) + - scale_y_continuous( - # don't expand y scale at the lower end - limits = c(0, max_crps + 0.05) ) From 63e39d258436e92b392034c020f7ba293b76a73f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 19:34:28 +0000 Subject: [PATCH 069/110] changes to fig3 to reflect new way of aggregating and computing relative CRPS --- wweval/R/ms_fig3.R | 70 +++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 605772a4..67a46037 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -3,18 +3,21 @@ #' @param scores tibble of crps scores by location, forecast date, model, #' horizon day #' @param locs_to_plot the locations we want summaries for +#' @param fig_file_dir string indicating directory to save fig in #' #' @return a table with mean crps for each model and the relative crps get_summary_table_fig3 <- function(scores, - locs_to_plot) { - scores_locs <- scores |> + locs_to_plot, + fig_file_dir) { + scores_locs_long <- scores |> dplyr::filter( location %in% locs_to_plot ) |> dplyr::group_by(model, location) |> dplyr::summarize( mean_crps = mean(crps) - ) |> + ) + scores_locs <- scores_locs_long |> tidyr::pivot_wider( id_cols = c("location"), names_from = "model", @@ -25,6 +28,27 @@ get_summary_table_fig3 <- function(scores, rel_crps_means = mean_crps_ww / mean_crps_hosp ) + colors <- plot_components() + p <- ggplot(scores_locs_long) + + geom_bar(aes(x = model, y = mean_crps, fill = model), + stat = "identity", + position = "dodge" + ) + + scale_fill_manual(values = colors$model_colors) + + facet_wrap(~location) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_title_size = 8, + y_axis_text_size = 6 + ) + + xlab("") + + ylab("Mean CRPS") + + ggsave(p, + filename = file.path(fig_file_dir, "sfig_bar_chart_mean_crps_3_locs.png"), + width = 7, height = 4 + ) + raw_rel_scores <- scores |> dplyr::filter( location %in% locs_to_plot @@ -110,21 +134,28 @@ make_fig3_single_loc_comp <- function(scores, order_horizons() relative_crps <- scores_comb |> - compute_relative_crps(id_cols = c( - "location", "forecast_date", - "horizon", "date" - )) |> + dplyr::group_by(horizon, forecast_date, location, model) |> + dplyr::summarize(mean_crps = mean(crps)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps, + id_cols = c("horizon", "forecast_date", "location") + ) |> + dplyr::mutate( + rel_crps = ww / hosp + ) |> dplyr::filter(!is.na(horizon)) |> order_horizons() - mean_rel_crps <- relative_crps |> + + rel_mean_crps <- relative_crps |> dplyr::group_by(horizon) |> - dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + dplyr::summarize(rel_mean_crps = mean(ww) / mean(hosp), na.rm = TRUE) colors <- plot_components() p <- ggplot(relative_crps) + - tidybayes::stat_slab( + tidybayes::stat_dotsinterval( aes( x = horizon, y = rel_crps, fill = horizon @@ -134,11 +165,6 @@ make_fig3_single_loc_comp <- function(scores, position = position_dodge(width = 0.75), show.legend = FALSE ) + - geom_point( - data = mean_rel_crps, - aes(x = horizon, mean_rel_crps), - size = 3 - ) + xlab("") + ylab("Relative CRPS") + theme_bw() + @@ -149,7 +175,10 @@ make_fig3_single_loc_comp <- function(scores, x_axis_text_size = 6 ) + scale_y_continuous(trans = "log10") + # , limits = c(0.25, 4.0)) + - labs(color = "Model", fill = "Model") + labs(color = "Model") + + # Also make a bar chart of the two average crps scores + return(p) } @@ -280,13 +309,16 @@ make_fig3_crps_underlay_fig <- function(scores, horizon_to_plot, horizon_days_ahead, days_to_shift = 0) { - scores_by_horizon <- scores |> + scores_filtered <- scores |> dplyr::filter(location == !!loc_to_plot) |> data.table::as.data.table() |> scoringutils::summarise_scores(by = c( "forecast_date", "location", "model", "horizon" - )) |> + )) + max_crps <- max(scores_filtered$crps) + + scores_by_horizon <- scores_filtered |> dplyr::filter(horizon == !!horizon_to_plot) |> dplyr::mutate( forecast_date_shifted = lubridate::ymd(forecast_date) + @@ -299,7 +331,6 @@ make_fig3_crps_underlay_fig <- function(scores, max(scores$forecast_date) + lubridate::days(horizon_days_ahead + 5) ) - max_crps <- max(scores_by_horizon$crps) p <- ggplot(scores_by_horizon) + geom_bar(aes(x = forecast_date_shifted, y = crps, fill = model), @@ -314,6 +345,7 @@ make_fig3_crps_underlay_fig <- function(scores, labels = scales::date_format("%Y-%m-%d"), limits = date_lims ) + + coord_cartesian(ylim = c(0, max_crps + 0.05)) + get_plot_theme( x_axis_dates = TRUE, y_axis_title_size = 8, From 0c6059c9291382eec625cf4ec21284614c52d435 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 20:09:56 +0000 Subject: [PATCH 070/110] temporary changes to fig4 --- wweval/R/ms_fig4.R | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 65372724..ced3e671 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -74,10 +74,11 @@ make_fig4_rel_crps_over_time <- function(scores) { date_lims <- c(range(scores$forecast_date)) p <- ggplot(relative_crps) + - tidybayes::stat_slab( + tidybayes::stat_halfeye( aes( x = as.factor(forecast_date), y = rel_crps, - fill = horizon + fill = horizon, + point_interval = "mean_qi" ), alpha = 0.5, position = position_dodge(width = 0.75), @@ -86,13 +87,15 @@ make_fig4_rel_crps_over_time <- function(scores) { geom_point( data = mean_rel_crps, aes(x = as.factor(forecast_date), y = mean_rel_crps), - size = 1.5, - color = "black" + size = 1, + shape = 17, + color = "blue" ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + xlab("") + ylab("Relative CRPS") + - scale_y_continuous(trans = "log10", limits = c(0.5, 2)) + + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(0.5, 2)) + get_plot_theme( x_axis_dates = TRUE, y_axis_title_size = 8 @@ -279,10 +282,11 @@ make_fig4_rel_crps_by_location <- function(scores) { colors <- plot_components() p <- ggplot(relative_crps) + - tidybayes::stat_slab( + tidybayes::stat_halfeye( aes( x = location, y = rel_crps, - fill = horizon + fill = horizon, + point_interval = "mean_qi" ), alpha = 0.5, position = position_dodge(width = 0.75), @@ -291,7 +295,9 @@ make_fig4_rel_crps_by_location <- function(scores) { geom_point( data = mean_rel_crps, aes(x = location, y = mean_rel_crps), - size = 1 + size = 1, + shape = 17, + color = "blue" ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + theme_bw() + @@ -301,7 +307,8 @@ make_fig4_rel_crps_by_location <- function(scores) { ) + # bc we want them smaller and turned xlab("") + ylab("Relative CRPS") + - scale_y_continuous(trans = "log10", limits = c(0.5, 2)) + + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(0.5, 2)) + scale_fill_manual(values = colors$horizon_colors) + scale_color_manual(values = colors$horizon_colors) @@ -361,10 +368,11 @@ make_fig4_rel_crps_overall <- function(scores, p <- ggplot(relative_crps) + - tidybayes::stat_slab( + tidybayes::stat_halfeye( aes( x = horizon, y = rel_crps, - fill = horizon + fill = horizon, + point_interval = "mean_qi" ), alpha = 0.5, position = position_dodge(width = 0.75), @@ -373,12 +381,15 @@ make_fig4_rel_crps_overall <- function(scores, geom_point( data = mean_rel_crps, aes(x = horizon, y = mean_rel_crps), - size = 4 + size = 1, + shape = 17, + color = "blue" ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + xlab("Horizon") + ylab("Relative CRPS") + - scale_y_continuous(trans = "log10", limits = c(0.5, 2)) + + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(0.5, 2)) + get_plot_theme( y_axis_title_size = 8, x_axis_title_size = 8 From bcce20c34ae74c320161ed556415012737ecc668 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 20:11:45 +0000 Subject: [PATCH 071/110] breakup hub comparison fig into two figs and remove relative heatmap --- _targets_eval_postprocessing.R | 6 ++- wweval/R/ms_fig5.R | 55 ++++++++++++---------------- wweval/man/get_summary_table_fig3.Rd | 4 +- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 7971ada1..9deaf915 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -664,7 +664,8 @@ manuscript_figures <- list( name = summary_table_crps, command = get_summary_table_fig3( scores_filtered, - locs_to_plot + locs_to_plot, + fig_file_dir = eval_config$ms_fig_dir ) ), tar_target( @@ -1436,7 +1437,8 @@ hub_targets <- list( model = ifelse( model == "cfa-wwrenewal", "cfa-wwrenewal(real-time)", model ) - ) + ) |> + dplyr::filter(location != "US") ), tar_target( name = cfa_hosp_real_time_scores, diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 28eb26ce..d2275cf2 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -127,7 +127,6 @@ make_fig5_average_wis <- function(all_scores, date_breaks = "2 weeks", labels = scales::date_format("%Y-%m-%d") ) + - ggtitle(title) + scale_color_manual(values = colors$model_colors) + theme( legend.position = "top", @@ -292,25 +291,28 @@ make_fig5_density <- function(all_scores, location, forecast_date, target_end_date, horizon, interval_score ) |> - dplyr::rename(baseline_score = interval_score) |> - dplyr::distinct() + dplyr::group_by(location, forecast_date) |> + dplyr::summarize(mean_baseline_score = mean(interval_score)) scores_final <- subset_scores |> + dplyr::group_by( + forecast_date, location, model + ) |> + dplyr::summarize(mean_wis = mean(interval_score)) |> dplyr::left_join(baseline_scores, by = c( - "forecast_date", "horizon", - "location", "target_end_date" + "forecast_date", "location" )) |> - dplyr::mutate(relative_wis = interval_score / baseline_score) |> - dplyr::filter(model != {{ baseline_model }}) + dplyr::mutate(relative_wis = mean_wis / mean_baseline_score) |> + dplyr::filter( + model != {{ baseline_model }}, + !is.na(relative_wis) + ) - mean_rel_wis <- scores_final |> - dplyr::group_by(model) |> - dplyr::summarize(mean_rel_wis = mean(relative_wis, na.rm = TRUE)) colors <- plot_components() p <- ggplot(scores_final) + - tidybayes::stat_slab( + tidybayes::stat_histinterval( aes( x = model, y = relative_wis + 1e-8, fill = model @@ -319,12 +321,7 @@ make_fig5_density <- function(all_scores, alpha = 0.5, position = position_dodge(width = 0.75), ) + - geom_point( - data = mean_rel_wis, - aes(x = model, y = mean_rel_wis), - size = 3 - ) + - coord_trans(ylim = c(0, 2)) + + scale_y_continuous(trans = "log10") + get_plot_theme( x_axis_dates = TRUE, y_axis_title_size = 8 @@ -448,7 +445,6 @@ make_fig5_qq_plot <- function(scores, data.table::as.data.table() |> scoringutils::summarise_scores(by = c("model", "quantile")) |> scoringutils::plot_quantile_coverage() + - ggtitle(glue::glue("QQ plot")) + get_plot_theme() + theme(legend.position = "none") + scale_color_manual(values = colors$model_colors, guide = "none") @@ -536,8 +532,7 @@ make_fig5_density_rank <- function(scores, scale_x_continuous( name = "Standardized rank", limits = c(0, 1) ) + - ylab("") + - ggtitle(glue::glue("Standardized rank")) + ylab("") return(p) } @@ -644,12 +639,10 @@ make_fig5 <- function(fig5_plot_wis_t_real_time, fig5_std_rank_all_time, fig_file_dir) { layout <- " -AABCCC -DDEEFF -GGHIII -JJKKLL +AABBBB +CCDDEE " - fig5 <- fig5_plot_real_time_rel_wis + fig5_density_real_time + fig5_plot_wis_t_real_time + + fig5_rt <- fig5_density_real_time + fig5_plot_wis_t_real_time + fig5_heatmap_rel_wis_feb_mar + fig5_qq_plot_feb_mar + fig5_std_rank_feb_mar + fig5_plot_all_time_rel_wis + fig5_density_all_time + fig5_plot_wis_t_all_time + fig5_heatmap_rel_wis_all_time + fig5_qq_plot_all_time + fig5_std_rank_all_time + @@ -665,18 +658,18 @@ JJKKLL fs::dir_create(fig_file_dir) - ggsave(fig5, - filename = file.path(fig_file_dir, "fig5.png"), - width = 12, height = 20 + ggsave(fig5_rt, + filename = file.path(fig_file_dir, "fig5_rt.png"), + width = 12, height = 10 ) - ggsave(fig5, + ggsave(fig5_rt, filename = file.path(fig_file_dir, "fig5.svg"), width = 12, height = 20 ) - fig5_at <- fig5_plot_all_time_rel_wis + fig5_density_all_time + fig5_plot_wis_t_all_time + + fig5_at <- fig5_density_all_time + fig5_plot_wis_t_all_time + fig5_heatmap_rel_wis_all_time + fig5_qq_plot_all_time + fig5_std_rank_all_time + patchwork::plot_layout( design = layout, @@ -699,5 +692,5 @@ JJKKLL filename = file.path(fig_file_dir, "fig5_at.svg"), width = 12, height = 10 ) - return(fig5) + return(fig5_rt) } diff --git a/wweval/man/get_summary_table_fig3.Rd b/wweval/man/get_summary_table_fig3.Rd index c704a885..b05fe5ba 100644 --- a/wweval/man/get_summary_table_fig3.Rd +++ b/wweval/man/get_summary_table_fig3.Rd @@ -4,13 +4,15 @@ \alias{get_summary_table_fig3} \title{Get a summary of a single states crps} \usage{ -get_summary_table_fig3(scores, locs_to_plot) +get_summary_table_fig3(scores, locs_to_plot, fig_file_dir) } \arguments{ \item{scores}{tibble of crps scores by location, forecast date, model, horizon day} \item{locs_to_plot}{the locations we want summaries for} + +\item{fig_file_dir}{string indicating directory to save fig in} } \value{ a table with mean crps for each model and the relative crps From 5fb39a4bf992291d22efa3bfd454e6e7d9448b4d Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 21:14:47 +0000 Subject: [PATCH 072/110] add new fig4 all time changes --- _targets_eval_postprocessing.R | 41 +++-- wweval/NAMESPACE | 1 + wweval/R/ms_fig4.R | 230 +++++++++++++++++------- wweval/R/order_elements.R | 34 ++++ wweval/R/supplement_analyses_and_figs.R | 98 ---------- wweval/man/get_plot_rel_crps_distrib.Rd | 2 +- wweval/man/get_plot_rel_crps_heatmap.Rd | 2 +- wweval/man/make_fig4.Rd | 17 +- wweval/man/make_plot_coverage_range.Rd | 12 +- wweval/man/make_qq_plot_overall.Rd | 12 +- wweval/man/order_locations.Rd | 20 +++ 11 files changed, 282 insertions(+), 187 deletions(-) create mode 100644 wweval/man/order_locations.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 9deaf915..6e5d92b8 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -981,6 +981,20 @@ manuscript_figures <- list( locs = c("DC", "OH", "NH", "CO") ) ), + ## Fig 4: retro all-time-------------------------------------------------- + tar_target(fig4_rel_crps_heatmap, + command = get_plot_rel_crps_heatmap( + scores = scores_filtered, + fig_file_dir = eval_config$ms_fig_dir + ) + ), + tar_target( + name = fig4_rel_crps_hist, + command = get_plot_rel_crps_distrib( + scores = scores_filtered, + fig_file_dir = eval_config$ms_fig_dir + ) + ), tar_target( name = fig4_natl_admissions, command = make_fig4_admissions_overall( @@ -1023,27 +1037,31 @@ manuscript_figures <- list( tar_target( name = fig4_qq_plot_overall, command = make_qq_plot_overall( - scores_quantiles_filtered + scores_quantiles_filtered, + fig_file_dir = eval_config$ms_fig_dir, + write_files = TRUE ) ), tar_target( name = fig4_plot_coverage_range, command = make_plot_coverage_range( scores_quantiles_filtered, - ranges = c(30, 60, 90) + ranges = c(30, 60, 90), + fig_file_dir = eval_config$ms_fig_dir, + write_files = TRUE ) ), ### Fig 4 combined--------------------------------------------------- tar_target( name = fig4, command = make_fig4( - fig4_rel_crps_overall = fig4_rel_crps_overall, + fig4_rel_crps_heatmap = fig4_rel_crps_heatmap, + fig4_rel_crps_hist = fig4_rel_crps_hist, fig4_avg_crps = fig4_avg_crps, fig4_natl_admissions = fig4_natl_admissions, fig4_rel_crps_over_time = fig4_rel_crps_over_time, fig4_rel_crps_by_location = fig4_rel_crps_by_location, - fig4_qq_plot_overall = fig4_qq_plot_overall, - fig4_plot_coverage_range = fig4_plot_coverage_range, + time_period = "all_time", fig_file_dir = eval_config$ms_fig_dir ) ) @@ -1722,12 +1740,6 @@ supp_targets <- list( fig_file_dir = eval_config$ms_fig_dir ) ), - tar_target(sfig_rel_crps_heatmap, - command = get_plot_rel_crps_heatmap( - scores = scores_filtered, - fig_file_dir = eval_config$ms_fig_dir - ) - ), tar_target( name = sfig_bias_over_time_comparison, command = get_plot_bias_over_time(scores_filtered, @@ -1791,13 +1803,6 @@ supp_targets <- list( scores = scores_filtered, threshold = 0.1 ) - ), - tar_target( - name = plot_rel_crps_distrib, - command = get_plot_rel_crps_distrib( - scores = scores_filtered, - fig_file_dir = eval_config$ms_fig_dir - ) ) ) diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index f30ea108..c85b7ff3 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -96,6 +96,7 @@ export(make_qq_plot_overall) export(make_sfig_crps_by_phase) export(nhsn_soda_query) export(order_horizons) +export(order_locations) export(order_periods) export(order_phases) export(plot_benchmarks) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index ced3e671..5d250038 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -59,38 +59,32 @@ make_fig4_rel_crps_over_time <- function(scores) { ) relative_crps <- scores_overall |> - compute_relative_crps(id_cols = c( - "location", - "forecast_date", "date", "horizon" - )) - - - mean_rel_crps <- relative_crps |> - dplyr::group_by(forecast_date, horizon) |> - dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + dplyr::group_by(forecast_date, location, model, horizon) |> + dplyr::summarize(mean_crps = mean(crps)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps, + id_cols = c("horizon", "forecast_date", "location") + ) |> + dplyr::mutate( + rel_crps = ww / hosp + ) colors <- plot_components() date_lims <- c(range(scores$forecast_date)) p <- ggplot(relative_crps) + - tidybayes::stat_halfeye( + tidybayes::stat_dotsinterval( aes( x = as.factor(forecast_date), y = rel_crps, - fill = horizon, - point_interval = "mean_qi" + fill = horizon ), + point_interval = "mean_qi", alpha = 0.5, position = position_dodge(width = 0.75), show.legend = FALSE ) + - geom_point( - data = mean_rel_crps, - aes(x = as.factor(forecast_date), y = mean_rel_crps), - size = 1, - shape = 17, - color = "blue" - ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + xlab("") + ylab("Relative CRPS") + @@ -248,6 +242,91 @@ get_loc_rel_crps <- function(scores, locs) { return(relative_crps) } +#' Plot a heatmap of the relative crps by locations and forecast date +#' for the head-to-head comparison +#' +#' @param scores A tibble of daily scores by forecast date, location, and model +#' @param fig_file_dir A string indicating the directory to save the figures in +#' +#' @return a ggplot object +#' @export +get_plot_rel_crps_heatmap <- function(scores, + fig_file_dir) { + scores_summary <- scores |> + compute_relative_crps(id_cols = c( + "location", + "forecast_date", "date" + )) |> + dplyr::group_by(location, forecast_date) |> + dplyr::summarize( + mean_rel_crps = mean(rel_crps) + ) + + + p <- ggplot(scores_summary) + + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + transform = "log2", + midpoint = 1, + guide = "colourbar", aesthetics = "fill" + ) + + geom_text(aes( + x = forecast_date, y = location, + label = round(mean_rel_crps, 2) + ), size = 1.5) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("Location") + + labs(fill = "Relative CRPS") + + ggtitle(glue::glue("Relative CRPS by forecast date and location")) + + return(p) +} + +#' Get a density plot of the relative CRPS distribution +#' +#' @param scores tibble of scores by horizon day, forecast date, and location +#' @param fig_file_dir directory to save figure in +#' +#' @return ggplot object of distribution of relative CRPS scores +get_plot_rel_crps_distrib <- function(scores, + fig_file_dir) { + relative_crps_by_forecast <- scores |> + dplyr::group_by(location, model, forecast_date) |> + dplyr::summarize(crps = mean(crps)) |> + compute_relative_crps(id_cols = c( + "location", "forecast_date" + )) |> + dplyr::mutate( + pct_change_crps = (ww - hosp) / hosp, + rel_crps = ww / hosp + ) + p_log <- ggplot(relative_crps_by_forecast) + + tidybayes::stat_dotsinterval( + aes( + y = rel_crps + ), + alpha = 0.5, + position = position_dodge(width = 0.75), + show.legend = FALSE, + fill = "darkblue" + ) + + get_plot_theme() + + ylab("Relative CRPS") + + xlab("Count") + + scale_x_continuous(trans = "log10") + + return(p_log) +} + #' Make figure that stratifies scores by location across forecast dates @@ -267,38 +346,31 @@ make_fig4_rel_crps_by_location <- function(scores) { relative_crps <- scores_overall |> - compute_relative_crps(id_cols = c( - "location", - "forecast_date", "date", - "horizon" - )) |> - dplyr::filter(!is.na(horizon)) |> - order_horizons() - - mean_rel_crps <- relative_crps |> - group_by(horizon, location) |> - summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) + dplyr::group_by(forecast_date, location, model, horizon) |> + dplyr::summarize(mean_crps = mean(crps)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps, + id_cols = c("horizon", "forecast_date", "location") + ) |> + dplyr::mutate( + rel_crps = ww / hosp + ) |> + order_locations() colors <- plot_components() p <- ggplot(relative_crps) + - tidybayes::stat_halfeye( + tidybayes::stat_dotsinterval( aes( x = location, y = rel_crps, - fill = horizon, - point_interval = "mean_qi" + fill = horizon ), + point_interval = "mean_qi", alpha = 0.5, position = position_dodge(width = 0.75), show.legend = FALSE ) + - geom_point( - data = mean_rel_crps, - aes(x = location, y = mean_rel_crps), - size = 1, - shape = 17, - color = "blue" - ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + theme_bw() + get_plot_theme( @@ -408,16 +480,22 @@ make_fig4_rel_crps_overall <- function(scores, #' @param scores_quantiles A tibble of scores by location, forecast date, #' date and model, containing the outputs of `scoringutils::score()` on #' quantiles plus metadata transformed into a tibble. +#' @param fig_file_fir string indicating directory to save figure, +#' default is NULL +#' @param write_files boolean indicating whether to save the file, default is +#' `FALSE` #' #' @return a ggplot object with the overall QQ plot colored by model. #' @export -make_qq_plot_overall <- function(scores_quantiles) { +make_qq_plot_overall <- function(scores_quantiles, + fig_file_dir = NULL, + write_files = FALSE) { colors <- plot_components() p <- scores_quantiles |> data.table::as.data.table() |> scoringutils::summarise_scores(by = c("model", "quantile")) |> scoringutils::plot_quantile_coverage() + - # ggtitle(glue::glue("QQ plot")) + + ggtitle(glue::glue("QQ plot all-time")) + get_plot_theme() + labs( ylab = "Percent of data below quantile", @@ -425,6 +503,15 @@ make_qq_plot_overall <- function(scores_quantiles) { ) + theme(legend.position = "none") + scale_color_manual(values = colors$model_colors) + if (isTRUE(write_files)) { + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_qq_plot_retro_all_time.png") + ) + ) + } + return(p) } @@ -437,10 +524,16 @@ make_qq_plot_overall <- function(scores_quantiles) { #' #' @param ranges A numeric vector of credible interval ranges to plot, #' spanning from 0 to 100. +#' @param fig_file_dir string indicating directory to save figure in, +#' default is `NULL` +#' @param write_files boolean indicating whether to save file, default is FALSE #' #' @return A ggplot2 object #' -make_plot_coverage_range <- function(scores_quantiles, ranges) { +make_plot_coverage_range <- function(scores_quantiles, + ranges, + fig_file_dir = NULL, + write_files = FALSE) { scores_by_horizon <- scores_quantiles |> dplyr::mutate( horizon_weeks = dplyr::case_when( @@ -490,6 +583,16 @@ make_plot_coverage_range <- function(scores_quantiles, ranges) { ) + scale_color_manual(values = colors$model_colors) + if (isTRUE(write_files)) { + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_coverage_range_retro_all_time.png") + ), + height = 10, + width = 4 + ) + } return(p) } @@ -674,7 +777,9 @@ make_fig4_avg_crps_over_time <- function(scores, #' Make Figure 4 #' -#' @param fig4_rel_crps_overall density plot comparing overall distribution +#' @param fig4_rel_crps_heatmap heatmap of relative crps by forecast date +#' and location +#' @param fig4_rel_crps_hist histogram comparing overall distribution #' of crps scores across forecast_date, date, location, and model #' @param fig4_avg_crps avg crps across locations by forecast date #' @param fig4_natl_admissions national admissions by day @@ -683,35 +788,32 @@ make_fig4_avg_crps_over_time <- function(scores, #' @param fig4_rel_crps_by_location avg crps across forecast dates by state #' @param fig4_qq_plot_overall overall qq plot #' @param fig4_plot_coverage_range interval coverage plots at 3 intervals +#' @param time_period string to save fig as, either "real_time" or "all_time" #' @param fig_file_dir Path to save figures #' #' @return ggplot object with all the elements combined #' @export -make_fig4 <- function(fig4_rel_crps_overall, +make_fig4 <- function(fig4_rel_crps_heatmap, + fig4_rel_crps_hist, fig4_avg_crps, fig4_natl_admissions, fig4_rel_crps_over_time, fig4_rel_crps_by_location, - fig4_qq_plot_overall, - fig4_plot_coverage_range, + time_period, fig_file_dir) { layout <- " -AAAA -BBBB -CCCC -DDDD -EEEE -FGGG -FGGG +AACCC +AADDD +BBEEE +BBFFF " - fig4 <- fig4_rel_crps_overall + + fig4 <- fig4_rel_crps_heatmap + + fig4_rel_crps_hist + fig4_natl_admissions + fig4_avg_crps + fig4_rel_crps_over_time + fig4_rel_crps_by_location + - fig4_plot_coverage_range + - fig4_qq_plot_overall + patchwork::plot_layout( design = layout, axes = "collect" @@ -724,13 +826,19 @@ FGGG fs::dir_create(fig_file_dir) ggsave(fig4, - filename = file.path(fig_file_dir, "fig4.png"), - width = 8, height = 11 + filename = file.path( + fig_file_dir, + glue::glue("fig4_{time_period}.png") + ), + width = 10, height = 8 ) ggsave(fig4, - filename = file.path(fig_file_dir, "fig4.svg"), - width = 8, height = 11 + filename = file.path( + fig_file_dir, + glue::glue("fig4_{time_period}.svg") + ), + width = 10, height = 8 ) return(fig4) diff --git a/wweval/R/order_elements.R b/wweval/R/order_elements.R index 4557645b..3a78b50d 100644 --- a/wweval/R/order_elements.R +++ b/wweval/R/order_elements.R @@ -153,3 +153,37 @@ order_phases <- function(df) { ) return(df_w_order) } + +#' Get the order of the locations for plotting +#' +#' @param df a dataframe containing the column name `phase` which will +#' contain character strings indicating the phase of the epidemic +#' (increasing, decreasing, peak, or nadir) of the score/quantile/sample. +#' +#' @return a dataframe containing the same columns as `df` but with the +#' addition of `fig_order` and reordered in terms of `fig_order` for plotting. +#' @export +order_locations <- function(df) { + loc_order <- df |> + dplyr::group_by(location) |> + dplyr::summarize(geom_mean_crps = exp(mean(log(rel_crps)))) |> + dplyr::arrange(geom_mean_crps, "desc") |> + dplyr::pull(location) + + if (!"location" %in% colnames(df)) { + cli::cli_abort( + message = + c( + "Column named `location` is missing from the dataframe" + ) + ) + } + + + + df_w_order <- df |> + dplyr::mutate( + location = factor(location, ordered = TRUE, levels = loc_order) + ) + return(df_w_order) +} diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index e974746f..9048dfb5 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -741,49 +741,6 @@ get_stats_improved_forecasts <- function(scores, return(stats) } -#' Get a density plot of the relative CRPS distribution -#' -#' @param scores tibble of scores by horizon day, forecast date, and location -#' @param fig_file_dir directory to save figure in -#' -#' @return ggplot object of distribution of relative CRPS scores -get_plot_rel_crps_distrib <- function(scores, - fig_file_dir) { - relative_crps_by_forecast <- scores |> - dplyr::group_by(location, model, forecast_date) |> - dplyr::summarize(crps = mean(crps)) |> - compute_relative_crps(id_cols = c( - "location", "forecast_date" - )) |> - dplyr::mutate( - pct_change_crps = (ww - hosp) / hosp, - rel_crps = ww / hosp - ) - p <- ggplot(relative_crps_by_forecast) + - geom_density(aes(x = rel_crps), - fill = "darkblue" - ) + - geom_vline(aes(xintercept = 1), linetype = "dashed") + - get_plot_theme() + - ylab("Density") + - xlab("Relative CRPS by forecast date and location") - p_log <- p + scale_x_continuous(trans = "log10") - - ggsave(p, - filename = file.path( - fig_file_dir, - glue::glue("sfig_distrib_rel_crps.png") - ) - ) - - ggsave(p_log, - filename = file.path( - fig_file_dir, - glue::glue("sfig_distrib_rel_crps_log.png") - ) - ) - return(p) -} get_plot_sites_vs_performance <- function(scores, @@ -921,61 +878,6 @@ get_plot_comb_perf_heatmap <- function(scores, return(p) } -#' Plot a heatmap of the relative crps by locations and forecast date -#' for the head-to-head comparison -#' -#' @param scores A tibble of daily scores by forecast date, location, and model -#' @param fig_file_dir A string indicating the directory to save the figures in -#' -#' @return a ggplot object -#' @export -get_plot_rel_crps_heatmap <- function(scores, - fig_file_dir) { - scores_summary <- scores |> - compute_relative_crps(id_cols = c( - "location", - "forecast_date", "date" - )) |> - dplyr::group_by(location, forecast_date) |> - dplyr::summarize( - mean_rel_crps = mean(rel_crps) - ) - - - p <- ggplot(scores_summary) + - geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + - scale_fill_gradient2( - high = "red", mid = "white", low = "blue", - transform = "log2", - midpoint = 1, - guide = "colourbar", aesthetics = "fill" - ) + - geom_text(aes( - x = forecast_date, y = location, - label = round(mean_rel_crps, 2) - ), size = 1.5) + - get_plot_theme( - x_axis_dates = TRUE, - y_axis_text_size = 4 - ) + - scale_x_date( - date_breaks = "1 week", - labels = scales::date_format("%Y-%m-%d") - ) + - xlab("") + - ylab("Location") + - labs(fill = "Relative CRPS") + - ggtitle(glue::glue("Mean relative CRPS by forecast date and location")) - - ggsave(p, - width = 7, height = 6, - filename = file.path( - fig_file_dir, - glue::glue("sfig_heatmap_rel_crps.png") - ) - ) - return(p) -} #' Get a summary table of the number of forecasts excluded for each reason #' diff --git a/wweval/man/get_plot_rel_crps_distrib.Rd b/wweval/man/get_plot_rel_crps_distrib.Rd index f9987d1c..a547df9b 100644 --- a/wweval/man/get_plot_rel_crps_distrib.Rd +++ b/wweval/man/get_plot_rel_crps_distrib.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/supplement_analyses_and_figs.R +% Please edit documentation in R/ms_fig4.R \name{get_plot_rel_crps_distrib} \alias{get_plot_rel_crps_distrib} \title{Get a density plot of the relative CRPS distribution} diff --git a/wweval/man/get_plot_rel_crps_heatmap.Rd b/wweval/man/get_plot_rel_crps_heatmap.Rd index a3b03b13..0d896f48 100644 --- a/wweval/man/get_plot_rel_crps_heatmap.Rd +++ b/wweval/man/get_plot_rel_crps_heatmap.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/supplement_analyses_and_figs.R +% Please edit documentation in R/ms_fig4.R \name{get_plot_rel_crps_heatmap} \alias{get_plot_rel_crps_heatmap} \title{Plot a heatmap of the relative crps by locations and forecast date diff --git a/wweval/man/make_fig4.Rd b/wweval/man/make_fig4.Rd index 0901c541..8dfa082c 100644 --- a/wweval/man/make_fig4.Rd +++ b/wweval/man/make_fig4.Rd @@ -5,18 +5,21 @@ \title{Make Figure 4} \usage{ make_fig4( - fig4_rel_crps_overall, + fig4_rel_crps_heatmap, + fig4_rel_crps_hist, fig4_avg_crps, fig4_natl_admissions, fig4_rel_crps_over_time, fig4_rel_crps_by_location, - fig4_qq_plot_overall, - fig4_plot_coverage_range, + time_period, fig_file_dir ) } \arguments{ -\item{fig4_rel_crps_overall}{density plot comparing overall distribution +\item{fig4_rel_crps_heatmap}{heatmap of relative crps by forecast date +and location} + +\item{fig4_rel_crps_hist}{histogram comparing overall distribution of crps scores across forecast_date, date, location, and model} \item{fig4_avg_crps}{avg crps across locations by forecast date} @@ -28,11 +31,13 @@ date} \item{fig4_rel_crps_by_location}{avg crps across forecast dates by state} +\item{time_period}{string to save fig as, either "real_time" or "all_time"} + +\item{fig_file_dir}{Path to save figures} + \item{fig4_qq_plot_overall}{overall qq plot} \item{fig4_plot_coverage_range}{interval coverage plots at 3 intervals} - -\item{fig_file_dir}{Path to save figures} } \value{ ggplot object with all the elements combined diff --git a/wweval/man/make_plot_coverage_range.Rd b/wweval/man/make_plot_coverage_range.Rd index 2060e3c0..1103917d 100644 --- a/wweval/man/make_plot_coverage_range.Rd +++ b/wweval/man/make_plot_coverage_range.Rd @@ -4,7 +4,12 @@ \alias{make_plot_coverage_range} \title{Plot coverage at specified ranges} \usage{ -make_plot_coverage_range(scores_quantiles, ranges) +make_plot_coverage_range( + scores_quantiles, + ranges, + fig_file_dir = NULL, + write_files = FALSE +) } \arguments{ \item{scores_quantiles}{A tibble of scores by location, forecast date, @@ -13,6 +18,11 @@ quantiles plus metadata transformed into a tibble.} \item{ranges}{A numeric vector of credible interval ranges to plot, spanning from 0 to 100.} + +\item{fig_file_dir}{string indicating directory to save figure in, +default is \code{NULL}} + +\item{write_files}{boolean indicating whether to save file, default is FALSE} } \value{ A ggplot2 object diff --git a/wweval/man/make_qq_plot_overall.Rd b/wweval/man/make_qq_plot_overall.Rd index e14166ec..6b4a8753 100644 --- a/wweval/man/make_qq_plot_overall.Rd +++ b/wweval/man/make_qq_plot_overall.Rd @@ -4,12 +4,22 @@ \alias{make_qq_plot_overall} \title{Make a qq plot} \usage{ -make_qq_plot_overall(scores_quantiles) +make_qq_plot_overall( + scores_quantiles, + fig_file_dir = NULL, + write_files = FALSE +) } \arguments{ \item{scores_quantiles}{A tibble of scores by location, forecast date, date and model, containing the outputs of \code{scoringutils::score()} on quantiles plus metadata transformed into a tibble.} + +\item{write_files}{boolean indicating whether to save the file, default is +\code{FALSE}} + +\item{fig_file_fir}{string indicating directory to save figure, +default is NULL} } \value{ a ggplot object with the overall QQ plot colored by model. diff --git a/wweval/man/order_locations.Rd b/wweval/man/order_locations.Rd new file mode 100644 index 00000000..08d70736 --- /dev/null +++ b/wweval/man/order_locations.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/order_elements.R +\name{order_locations} +\alias{order_locations} +\title{Get the order of the locations for plotting} +\usage{ +order_locations(df) +} +\arguments{ +\item{df}{a dataframe containing the column name \code{phase} which will +contain character strings indicating the phase of the epidemic +(increasing, decreasing, peak, or nadir) of the score/quantile/sample.} +} +\value{ +a dataframe containing the same columns as \code{df} but with the +addition of \code{fig_order} and reordered in terms of \code{fig_order} for plotting. +} +\description{ +Get the order of the locations for plotting +} From 6a48e11dfa769a5845039a0dd1e1a848ef4697c7 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 21:38:49 +0000 Subject: [PATCH 073/110] make coverage plot horizontal --- _targets_eval_postprocessing.R | 4 +- wweval/R/ms_fig4.R | 58 +++++++++++++----------- wweval/man/make_fig4_rel_crps_overall.Rd | 9 +++- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 6e5d92b8..bdb4e829 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1031,7 +1031,9 @@ manuscript_figures <- list( tar_target( name = fig4_rel_crps_overall, command = make_fig4_rel_crps_overall( - scores_filtered + scores_filtered, + fig_file_dir = eval_config$ms_fig_dir, + write_files = TRUE ) ), tar_target( diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 5d250038..2fc60b50 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -396,6 +396,9 @@ make_fig4_rel_crps_by_location <- function(scores) { #' @param horizons_to_show A vector of strings indicating the names of the #' `horizon` that we want to show on the plot, must be a subset of #' `nowcast`, `1 wk`, `2 wks`,`3 wks`, `4 wks` and `overall` +#' @param fig_file_dir string indicating directory to save fig, default is NULL +#' @param write_files boolean indicating whether or not to save file, default +#' is FALSE #' #' @return A ggplot object containing plots of the distribution of relative #' CRPS scores across location and forecast dates @@ -405,7 +408,9 @@ make_fig4_rel_crps_overall <- function(scores, "nowcast", "1 wk", "4 wks", "overall" - )) { + ), + fig_file_dir = NULL, + write_files = FALSE) { scores_by_horizon <- scores scores_overall <- scores |> dplyr::mutate( @@ -418,45 +423,33 @@ make_fig4_rel_crps_overall <- function(scores, ) relative_crps <- scores_comb |> - compute_relative_crps(id_cols = c( - "location", "forecast_date", - "horizon", "date" - )) |> - dplyr::filter(!is.na(horizon)) |> + dplyr::group_by(forecast_date, location, model, horizon) |> + dplyr::summarize(mean_crps = mean(crps)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps, + id_cols = c("horizon", "forecast_date", "location") + ) |> + dplyr::mutate( + rel_crps = ww / hosp + ) |> order_horizons() colors <- plot_components() - mean_rel_crps <- relative_crps |> - dplyr::group_by(horizon) |> - dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) - quartiled_rel_crps <- relative_crps |> - dplyr::group_by(horizon) |> - dplyr::summarize( - lb_25th = quantile(rel_crps, probs = 0.25), - ub_75 = quantile(rel_crps, probs = 0.75) - ) |> - tidyr::pivot_longer(!horizon) p <- ggplot(relative_crps) + - tidybayes::stat_halfeye( + tidybayes::stat_dotsinterval( aes( x = horizon, y = rel_crps, - fill = horizon, - point_interval = "mean_qi" + fill = horizon, color = horizon ), + point_interval = "mean_qi", alpha = 0.5, position = position_dodge(width = 0.75), show.legend = FALSE ) + - geom_point( - data = mean_rel_crps, - aes(x = horizon, y = mean_rel_crps), - size = 1, - shape = 17, - color = "blue" - ) + geom_hline(aes(yintercept = 1), linetype = "dashed") + xlab("Horizon") + ylab("Relative CRPS") + @@ -469,6 +462,17 @@ make_fig4_rel_crps_overall <- function(scores, scale_fill_manual(values = colors$horizon_colors) + scale_color_manual(values = colors$horizon_colors) + if (isTRUE(write_files)) { + ggsave(p, + filename = file.path( + fig_file_dir, + glue::glue("sfig_hist_overall_rel_crps_all_time.png") + ), + height = 4, + width = 6 + ) + } + return(p) } @@ -571,7 +575,7 @@ make_plot_coverage_range <- function(scores_quantiles, geom_line() + geom_point() + geom_hline(aes(yintercept = range), linetype = "dashed") + - facet_wrap(~named_facet, scales = "free_y", ncol = 1) + + facet_wrap(~named_facet, scales = "free_y") + labs( y = "Proportion of data within interval", x = "Forecast horizon", diff --git a/wweval/man/make_fig4_rel_crps_overall.Rd b/wweval/man/make_fig4_rel_crps_overall.Rd index b2645936..632cc2bb 100644 --- a/wweval/man/make_fig4_rel_crps_overall.Rd +++ b/wweval/man/make_fig4_rel_crps_overall.Rd @@ -6,7 +6,9 @@ \usage{ make_fig4_rel_crps_overall( scores, - horizons_to_show = c("nowcast", "1 wk", "4 wks", "overall") + horizons_to_show = c("nowcast", "1 wk", "4 wks", "overall"), + fig_file_dir = NULL, + write_files = FALSE ) } \arguments{ @@ -17,6 +19,11 @@ transformed into a tibble.} \item{horizons_to_show}{A vector of strings indicating the names of the \code{horizon} that we want to show on the plot, must be a subset of \code{nowcast}, \verb{1 wk}, \verb{2 wks},\verb{3 wks}, \verb{4 wks} and \code{overall}} + +\item{fig_file_dir}{string indicating directory to save fig, default is NULL} + +\item{write_files}{boolean indicating whether or not to save file, default +is FALSE} } \value{ A ggplot object containing plots of the distribution of relative From 5036380ffeccdfa114314ea46a81e0e0a9007a68 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 21:40:14 +0000 Subject: [PATCH 074/110] fix size of supp fig --- wweval/R/ms_fig4.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 2fc60b50..cff24954 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -593,8 +593,8 @@ make_plot_coverage_range <- function(scores_quantiles, fig_file_dir, glue::glue("sfig_coverage_range_retro_all_time.png") ), - height = 10, - width = 4 + height = 4, + width = 10 ) } return(p) From 2dac20d4312cfdcdfe550a90c0960a5c7489687a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 3 Dec 2024 23:15:27 +0000 Subject: [PATCH 075/110] add real time relative figure --- _targets_eval_postprocessing.R | 93 +++-- wweval/NAMESPACE | 3 + wweval/R/ms_fig4.R | 317 +++++++++++++++++- wweval/R/ms_fig5.R | 62 +--- wweval/R/order_elements.R | 6 +- wweval/man/get_plot_rel_wis_distrib.Rd | 17 + wweval/man/make_fig4_avg_wis_over_time.Rd | 24 ++ ...el_wis.Rd => make_fig4_heatmap_rel_wis.Rd} | 8 +- wweval/man/make_fig4_rel_wis_by_location.Rd | 20 ++ wweval/man/make_fig4_rel_wis_over_time.Rd | 20 ++ wweval/man/make_fig5.Rd | 14 +- wweval/man/order_locations.Rd | 5 +- 12 files changed, 486 insertions(+), 103 deletions(-) create mode 100644 wweval/man/get_plot_rel_wis_distrib.Rd create mode 100644 wweval/man/make_fig4_avg_wis_over_time.Rd rename wweval/man/{make_fig5_heatmap_rel_wis.Rd => make_fig4_heatmap_rel_wis.Rd} (78%) create mode 100644 wweval/man/make_fig4_rel_wis_by_location.Rd create mode 100644 wweval/man/make_fig4_rel_wis_over_time.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index bdb4e829..08df2d96 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -981,7 +981,7 @@ manuscript_figures <- list( locs = c("DC", "OH", "NH", "CO") ) ), - ## Fig 4: retro all-time-------------------------------------------------- + ## Fig 4: retro relative-------------------------------------------------- tar_target(fig4_rel_crps_heatmap, command = get_plot_rel_crps_heatmap( scores = scores_filtered, @@ -1053,7 +1053,7 @@ manuscript_figures <- list( write_files = TRUE ) ), - ### Fig 4 combined--------------------------------------------------- + ### Fig 4 retro relative combined--------------------------------------------- tar_target( name = fig4, command = make_fig4( @@ -1535,16 +1535,6 @@ hub_comparison_plots <- list( ) ), ## Real-time Hub comparison top row------------------------------------------ - # This will be the real-time relative WIS across the models submitted - tar_target( - name = fig5_plot_real_time_rel_wis, - command = make_fig5_heatmap_rel_wis( - rel_real_time_wis, - time_period = "Feb-Mar 2024", - analysis_type = "Real-time", - fig_file_dir = eval_config$ms_fig_dir - ) - ), # This will be the real-time density of relative CRPS compared # to covidhub baseline (will need to get the summary stats for this too) tar_target( @@ -1573,17 +1563,80 @@ hub_comparison_plots <- list( time_period = "Feb-Mar 2024" ) ), - - ## Retro Hub comparison top row------------------------------------------- + ## Fig 4 real-time relative combined----------------------------------------- tar_target( - name = fig5_plot_all_time_rel_wis, - command = make_fig5_heatmap_rel_wis( - rel_all_time_wis, - time_period = "Oct 2023-Mar 2024", - analysis_type = "Retrospective", + name = wis_scores_rt, + command = real_time_wis_both_models |> + dplyr::anti_join(as.data.frame( + eval_config$ww_forecast_date_locs_to_excl + ) |> + dplyr::mutate(forecast_date = lubridate::ymd(forecast_date))) + ), + tar_target( + name = rel_real_time_wis_submitted, + command = rel_real_time_wis |> + dplyr::anti_join(as.data.frame( + eval_config$ww_forecast_date_locs_to_excl + ) |> + dplyr::mutate(forecast_date = lubridate::ymd(forecast_date))) + ), + tar_target( + name = fig4_rel_wis_heatmap, + command = make_fig4_heatmap_rel_wis( + rel_scores = rel_real_time_wis_submitted, + time_period = "Feb-Mar 2024", + analysis_type = "Real-time" + ) + ), + tar_target( + name = fig4_rel_wis_hist, + command = get_plot_rel_wis_distrib( + wis_scores = wis_scores_rt + ) + ), + tar_target( + name = fig4_natl_admissions_rt, + command = make_fig4_admissions_overall( + eval_hosp_data, + first_forecast_date = lubridate::ymd("2024-02-05") - lubridate::days(7), + last_forecast_date = max(eval_config$forecast_date_ww) + ) + ), + tar_target( + name = fig4_avg_wis, + command = make_fig4_avg_wis_over_time( + wis_scores_rt + ) + ), + tar_target( + name = fig4_rel_wis_over_time, + command = make_fig4_rel_wis_over_time( + wis_scores_rt + ) + ), + tar_target( + name = fig4_rel_wis_by_location, + command = make_fig4_rel_wis_by_location( + wis_scores_rt + ) + ), + ### Fig 4 real-time relative combined--------------------------------------------- + tar_target( + name = fig4_rt, + command = make_fig4( + fig4_rel_crps_heatmap = fig4_rel_wis_heatmap, + fig4_rel_crps_hist = fig4_rel_wis_hist, + fig4_avg_crps = fig4_avg_wis, + fig4_natl_admissions = fig4_natl_admissions_rt, + fig4_rel_crps_over_time = fig4_rel_wis_over_time, + fig4_rel_crps_by_location = fig4_rel_wis_by_location, + time_period = "real_time", fig_file_dir = eval_config$ms_fig_dir ) ), + + + ## Retro Hub comparison top row------------------------------------------- tar_target( name = fig5_density_all_time, command = make_fig5_density( @@ -1679,10 +1732,8 @@ hub_comparison_plots <- list( command = make_fig5( fig5_plot_wis_t_real_time = fig5_plot_wis_t_real_time, fig5_density_real_time = fig5_density_real_time, - fig5_plot_real_time_rel_wis = fig5_plot_real_time_rel_wis, fig5_plot_wis_t_all_time = fig5_plot_wis_t_all_time, fig5_density_all_time = fig5_density_all_time, - fig5_plot_all_time_rel_wis = fig5_plot_all_time_rel_wis, fig5_heatmap_rel_wis_all_time = fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar = fig5_heatmap_rel_wis_feb_mar, fig5_qq_plot_all_time = fig5_qq_plot_all_time, diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index c85b7ff3..d5f58560 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -79,11 +79,14 @@ export(make_fig3_forecast_comp_fig) export(make_fig4) export(make_fig4_admissions_overall) export(make_fig4_avg_crps_over_time) +export(make_fig4_avg_wis_over_time) export(make_fig4_pct_better_w_ww) export(make_fig4_rel_crps_by_location) export(make_fig4_rel_crps_by_phase) export(make_fig4_rel_crps_over_time) export(make_fig4_rel_crps_overall) +export(make_fig4_rel_wis_by_location) +export(make_fig4_rel_wis_over_time) export(make_fig4_results_table) export(make_fig5) export(make_fig5_average_wis) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index cff24954..d102da3b 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -302,13 +302,18 @@ get_plot_rel_crps_distrib <- function(scores, relative_crps_by_forecast <- scores |> dplyr::group_by(location, model, forecast_date) |> dplyr::summarize(crps = mean(crps)) |> - compute_relative_crps(id_cols = c( - "location", "forecast_date" - )) |> + tidyr::pivot_wider( + names_from = model, + values_from = crps, + id_cols = c( + "location", "forecast_date" + ) + ) |> dplyr::mutate( pct_change_crps = (ww - hosp) / hosp, rel_crps = ww / hosp ) + p_log <- ggplot(relative_crps_by_forecast) + tidybayes::stat_dotsinterval( aes( @@ -321,8 +326,8 @@ get_plot_rel_crps_distrib <- function(scores, ) + get_plot_theme() + ylab("Relative CRPS") + - xlab("Count") + - scale_x_continuous(trans = "log10") + xlab("Density") + + scale_y_continuous(trans = "log10") return(p_log) } @@ -356,7 +361,7 @@ make_fig4_rel_crps_by_location <- function(scores) { dplyr::mutate( rel_crps = ww / hosp ) |> - order_locations() + order_locations(score_name = "rel_crps") colors <- plot_components() @@ -779,6 +784,306 @@ make_fig4_avg_crps_over_time <- function(scores, return(p) } + +#' Get a density plot of the relative WIS distribution +#' +#' @param scores tibble of scores by horizon day, forecast date, and location +#' +#' @return ggplot object of distribution of relative CRPS scores +get_plot_rel_wis_distrib <- function(wis_scores) { + relative_wis_by_forecast <- wis_scores |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c( + "location", + "model", + "forecast_date" + )) |> + tidyr::pivot_wider( + names_from = model, + values_from = interval_score, + id_cols = c( + "location", "forecast_date" + ) + ) |> + dplyr::mutate( + pct_change_crps = (ww - hosp) / hosp, + rel_wis = ww / hosp + ) + p_log <- ggplot(relative_wis_by_forecast) + + tidybayes::stat_dotsinterval( + aes( + y = rel_wis + ), + alpha = 0.5, + position = position_dodge(width = 0.75), + show.legend = FALSE, + fill = "darkblue" + ) + + get_plot_theme() + + ylab("Relative WIS") + + xlab("Density") + + scale_y_continuous(trans = "log10") + + return(p_log) +} + +#' Get a plot of the relative wis from the real-time models +#' +#' @param rel_scores tibble containing the relative wis for each forecast +#' date and location and horizon day +#' @param time_period string indicating dates of analysis, either "Feb-Mar", +#' or "Oct-Mar" +#' @param analysis_type string indicating whether analysis is Real-time +# or Retrospective +#' @param fig_file_dir string indicating the directory to save the figure +#' +#' @return ggplot object of a heatmap of the realtive wis +make_fig4_heatmap_rel_wis <- function(rel_scores, + time_period, + analysis_type, + fig_file_dir) { + avg_rel_scores <- rel_scores |> + dplyr::group_by(forecast_date, location) |> + dplyr::summarise(mean_rel_wis = mean(rel_wis)) |> + dplyr::filter(!is.na(mean_rel_wis)) + + p <- ggplot(avg_rel_scores) + + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + + scale_fill_gradient2( + high = "red", mid = "white", low = "blue", + transform = "log2", + midpoint = 1, + guide = "colourbar", aesthetics = "fill" + ) + + geom_text(aes( + x = forecast_date, y = location, + label = round(mean_rel_wis, 2) + ), size = 1.5) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_text_size = 4 + ) + + scale_x_date( + date_breaks = "1 week", + labels = scales::date_format("%Y-%m-%d") + ) + + xlab("") + + ylab("") + + labs(fill = "Relative WIS") + + ggtitle(glue::glue(" Relative WIS by forecast date and location")) # nolint + + + return(p) +} + +#' Plot average WIS over time for model comparison +#' +#' @param scores A tibble of scores by location, forecast date, date and model, +#' containing the outputs of `scoringutils::score()` on samples plus metadata +#' transformed into a tibble. +#' @param horizon_time_in_weeks horizon time in weeks to summarize over, default +#' is `NULL` which means that the scores are summarized over the nowcast period +#' and the 4 week forecast period +#' +#' @return a ggplot object plotting the magnitude of the avg wiss across +#' locations at each forecast date +#' @export +make_fig4_avg_wis_over_time <- function(wis_scores, + horizon_time_in_weeks = NULL) { + wis_scores_renamed <- wis_scores |> + dplyr::mutate( + model = case_when( + model == "ww" ~ "cfa-wwrenewal(real-time)", + model == "hosp" ~ "cfa-hosponlyrenewal(real-time)" + ) + ) + + if (!is.null(horizon_time_in_weeks)) { + scores_by_forecast_date <- wis_scores_renamed |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c( + "forecast_date", + "model", "horizon" + )) |> + dplyr::filter(horizon_weeks == { + horizon_time_in_weeks + }) + } else { + scores_by_forecast_date <- wis_scores_renamed |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c( + "forecast_date", + "model" + )) + } + + date_lims <- c( + min(wis_scores$forecast_date), + max(wis_scores$forecast_date) + ) + colors <- plot_components() + p <- ggplot(scores_by_forecast_date) + + geom_line( + aes( + x = forecast_date, y = interval_score, + color = model + ), + size = 1 + ) + + geom_point(aes( + x = forecast_date, y = interval_score, + color = model + )) + + labs( + col = "Model", + xlab = "" + ) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_title_size = 8 + ) + + theme(axis.title.x = element_blank()) + + scale_x_date( + date_breaks = "1 week", + date_labels = "%Y-%m-%d", + limits = date_lims + ) + + ylab("WIS") + + scale_color_manual(values = colors$model_colors) + + return(p) +} + +#' Make a CRPS density plot for a subset of locations +#' +#' @param scores A tibble of scores by location, forecast date, date and model, +#' containing the outputs of `scoringutils::score()` on samples plus metadata +#' transformed into a tibble. +#' @return a ggplot object that is a vertical facet of violin plots colored +#' by model type and broken down my horizon +#' @export +make_fig4_rel_wis_over_time <- function(wis_scores) { + scores_overall <- wis_scores |> + dplyr::mutate( + horizon = "overall" + ) + + relative_wis <- scores_overall |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c( + "forecast_date", + "location", + "model", + "horizon" + )) |> + tidyr::pivot_wider( + names_from = model, + values_from = interval_score, + id_cols = c("horizon", "forecast_date", "location") + ) |> + dplyr::mutate( + rel_wis = ww / hosp + ) |> + dplyr::filter(!is.na(rel_wis)) |> + order_locations(score_name = "rel_wis") + + + colors <- plot_components() + date_lims <- c(range(wis_scores$forecast_date)) + + p <- ggplot(relative_wis) + + tidybayes::stat_dotsinterval( + aes( + x = as.factor(forecast_date), y = rel_wis, + fill = horizon + ), + point_interval = "mean_qi", + alpha = 0.5, + position = position_dodge(width = 0.75), + show.legend = FALSE + ) + + geom_hline(aes(yintercept = 1), linetype = "dashed") + + xlab("") + + ylab("Relative WIS") + + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(0.5, 2)) + + get_plot_theme( + x_axis_dates = TRUE, + y_axis_title_size = 8 + ) + + scale_fill_manual(values = colors$horizon_colors) + + scale_color_manual(values = colors$horizon_colors) + + return(p) +} + +#' Make figure that stratifies scores by location across forecast dates +#' +#' @param scores A tibble of scores by location, forecast date, date and model, +#' containing the outputs of `scoringutils::score()` on samples plus metadata +#' transformed into a tibble. +#' +#' @return A ggplot object containing plots of the distribution of relative +#' WIS scores by location, across forecast dates, colored by location +#' @export +make_fig4_rel_wis_by_location <- function(wis_scores) { + scores_overall <- wis_scores |> + dplyr::mutate( + horizon = "overall" + ) + + relative_wis <- scores_overall |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c( + "forecast_date", + "location", + "model", + "horizon" + )) |> + tidyr::pivot_wider( + names_from = model, + values_from = interval_score, + id_cols = c("horizon", "forecast_date", "location") + ) |> + dplyr::mutate( + rel_wis = ww / hosp + ) |> + dplyr::filter(!is.na(rel_wis)) |> + order_locations(score_name = "rel_wis") + + colors <- plot_components() + + p <- ggplot(relative_wis) + + tidybayes::stat_dotsinterval( + aes( + x = location, y = rel_wis, + fill = horizon + ), + point_interval = "mean_qi", + alpha = 0.5, + position = position_dodge(width = 0.75), + show.legend = FALSE + ) + + geom_hline(aes(yintercept = 1), linetype = "dashed") + + theme_bw() + + get_plot_theme( + y_axis_title_size = 8, + x_axis_dates = TRUE + ) + # bc we want them smaller and turned + xlab("") + + ylab("Relative WIS") + + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(0.5, 2)) + + scale_fill_manual(values = colors$horizon_colors) + + scale_color_manual(values = colors$horizon_colors) + + + return(p) +} + + + + #' Make Figure 4 #' #' @param fig4_rel_crps_heatmap heatmap of relative crps by forecast date diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index d2275cf2..0a909317 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -538,62 +538,6 @@ make_fig5_density_rank <- function(scores, } -#' Get a plot of the relative wis from the real-time models -#' -#' @param rel_scores tibble containing the relative wis for each forecast -#' date and location and horizon day -#' @param time_period string indicating dates of analysis, either "Feb-Mar", -#' or "Oct-Mar" -#' @param analysis_type string indicating whether analysis is Real-time -# or Retrospective -#' @param fig_file_dir string indicating the directory to save the figure -#' -#' @return ggplot object of a heatmap of the realtive wis -make_fig5_heatmap_rel_wis <- function(rel_scores, - time_period, - analysis_type, - fig_file_dir) { - avg_rel_scores <- rel_scores |> - dplyr::group_by(forecast_date, location) |> - dplyr::summarise(mean_rel_wis = mean(rel_wis)) |> - dplyr::filter(!is.na(mean_rel_wis)) - - p <- ggplot(avg_rel_scores) + - geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + - scale_fill_gradient2( - high = "red", mid = "white", low = "blue", - transform = "log2", - midpoint = 1, - guide = "colourbar", aesthetics = "fill" - ) + - geom_text(aes( - x = forecast_date, y = location, - label = round(mean_rel_wis, 2) - ), size = 1.5) + - get_plot_theme( - x_axis_dates = TRUE, - y_axis_text_size = 4 - ) + - scale_x_date( - date_breaks = "1 week", - labels = scales::date_format("%Y-%m-%d") - ) + - xlab("") + - ylab("") + - labs(fill = "Relative WIS") + - ggtitle(glue::glue(" Relative WIS of wastewater \n informed model compared to \n hospital admissions-only model")) # nolint - - ggsave(p, - width = 7, height = 6, - filename = file.path( - fig_file_dir, - glue::glue("sfig_heatmap_rel_wis_{time_period}_{analysis_type}.png") - ) - ) - - return(p) -} - #' Make Fig 5 #' @@ -627,10 +571,8 @@ make_fig5_heatmap_rel_wis <- function(rel_scores, #' make_fig5 <- function(fig5_plot_wis_t_real_time, fig5_density_real_time, - fig5_plot_real_time_rel_wis, fig5_plot_wis_t_all_time, fig5_density_all_time, - fig5_plot_all_time_rel_wis, fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar, fig5_qq_plot_all_time, @@ -644,8 +586,6 @@ CCDDEE " fig5_rt <- fig5_density_real_time + fig5_plot_wis_t_real_time + fig5_heatmap_rel_wis_feb_mar + fig5_qq_plot_feb_mar + fig5_std_rank_feb_mar + - fig5_plot_all_time_rel_wis + fig5_density_all_time + fig5_plot_wis_t_all_time + - fig5_heatmap_rel_wis_all_time + fig5_qq_plot_all_time + fig5_std_rank_all_time + patchwork::plot_layout( design = layout, axes = "collect", @@ -665,7 +605,7 @@ CCDDEE ggsave(fig5_rt, filename = file.path(fig_file_dir, "fig5.svg"), - width = 12, height = 20 + width = 12, height = 10 ) diff --git a/wweval/R/order_elements.R b/wweval/R/order_elements.R index 3a78b50d..4bf3667e 100644 --- a/wweval/R/order_elements.R +++ b/wweval/R/order_elements.R @@ -159,14 +159,16 @@ order_phases <- function(df) { #' @param df a dataframe containing the column name `phase` which will #' contain character strings indicating the phase of the epidemic #' (increasing, decreasing, peak, or nadir) of the score/quantile/sample. +#' @param score_name string indicating the name of the score either `rel_crps` +#' or `rel_wis` #' #' @return a dataframe containing the same columns as `df` but with the #' addition of `fig_order` and reordered in terms of `fig_order` for plotting. #' @export -order_locations <- function(df) { +order_locations <- function(df, score_name) { loc_order <- df |> dplyr::group_by(location) |> - dplyr::summarize(geom_mean_crps = exp(mean(log(rel_crps)))) |> + dplyr::summarize(geom_mean_crps = exp(mean(log(!!sym(score_name))))) |> dplyr::arrange(geom_mean_crps, "desc") |> dplyr::pull(location) diff --git a/wweval/man/get_plot_rel_wis_distrib.Rd b/wweval/man/get_plot_rel_wis_distrib.Rd new file mode 100644 index 00000000..7f55d965 --- /dev/null +++ b/wweval/man/get_plot_rel_wis_distrib.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig4.R +\name{get_plot_rel_wis_distrib} +\alias{get_plot_rel_wis_distrib} +\title{Get a density plot of the relative WIS distribution} +\usage{ +get_plot_rel_wis_distrib(wis_scores) +} +\arguments{ +\item{scores}{tibble of scores by horizon day, forecast date, and location} +} +\value{ +ggplot object of distribution of relative CRPS scores +} +\description{ +Get a density plot of the relative WIS distribution +} diff --git a/wweval/man/make_fig4_avg_wis_over_time.Rd b/wweval/man/make_fig4_avg_wis_over_time.Rd new file mode 100644 index 00000000..e85fdc48 --- /dev/null +++ b/wweval/man/make_fig4_avg_wis_over_time.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig4.R +\name{make_fig4_avg_wis_over_time} +\alias{make_fig4_avg_wis_over_time} +\title{Plot average WIS over time for model comparison} +\usage{ +make_fig4_avg_wis_over_time(wis_scores, horizon_time_in_weeks = NULL) +} +\arguments{ +\item{horizon_time_in_weeks}{horizon time in weeks to summarize over, default +is \code{NULL} which means that the scores are summarized over the nowcast period +and the 4 week forecast period} + +\item{scores}{A tibble of scores by location, forecast date, date and model, +containing the outputs of \code{scoringutils::score()} on samples plus metadata +transformed into a tibble.} +} +\value{ +a ggplot object plotting the magnitude of the avg wiss across +locations at each forecast date +} +\description{ +Plot average WIS over time for model comparison +} diff --git a/wweval/man/make_fig5_heatmap_rel_wis.Rd b/wweval/man/make_fig4_heatmap_rel_wis.Rd similarity index 78% rename from wweval/man/make_fig5_heatmap_rel_wis.Rd rename to wweval/man/make_fig4_heatmap_rel_wis.Rd index 5ef1addb..8c0bf3d6 100644 --- a/wweval/man/make_fig5_heatmap_rel_wis.Rd +++ b/wweval/man/make_fig4_heatmap_rel_wis.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ms_fig5.R -\name{make_fig5_heatmap_rel_wis} -\alias{make_fig5_heatmap_rel_wis} +% Please edit documentation in R/ms_fig4.R +\name{make_fig4_heatmap_rel_wis} +\alias{make_fig4_heatmap_rel_wis} \title{Get a plot of the relative wis from the real-time models} \usage{ -make_fig5_heatmap_rel_wis(rel_scores, time_period, analysis_type, fig_file_dir) +make_fig4_heatmap_rel_wis(rel_scores, time_period, analysis_type, fig_file_dir) } \arguments{ \item{rel_scores}{tibble containing the relative wis for each forecast diff --git a/wweval/man/make_fig4_rel_wis_by_location.Rd b/wweval/man/make_fig4_rel_wis_by_location.Rd new file mode 100644 index 00000000..8b14f8e4 --- /dev/null +++ b/wweval/man/make_fig4_rel_wis_by_location.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig4.R +\name{make_fig4_rel_wis_by_location} +\alias{make_fig4_rel_wis_by_location} +\title{Make figure that stratifies scores by location across forecast dates} +\usage{ +make_fig4_rel_wis_by_location(wis_scores) +} +\arguments{ +\item{scores}{A tibble of scores by location, forecast date, date and model, +containing the outputs of \code{scoringutils::score()} on samples plus metadata +transformed into a tibble.} +} +\value{ +A ggplot object containing plots of the distribution of relative +WIS scores by location, across forecast dates, colored by location +} +\description{ +Make figure that stratifies scores by location across forecast dates +} diff --git a/wweval/man/make_fig4_rel_wis_over_time.Rd b/wweval/man/make_fig4_rel_wis_over_time.Rd new file mode 100644 index 00000000..8e46cd5e --- /dev/null +++ b/wweval/man/make_fig4_rel_wis_over_time.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig4.R +\name{make_fig4_rel_wis_over_time} +\alias{make_fig4_rel_wis_over_time} +\title{Make a CRPS density plot for a subset of locations} +\usage{ +make_fig4_rel_wis_over_time(wis_scores) +} +\arguments{ +\item{scores}{A tibble of scores by location, forecast date, date and model, +containing the outputs of \code{scoringutils::score()} on samples plus metadata +transformed into a tibble.} +} +\value{ +a ggplot object that is a vertical facet of violin plots colored +by model type and broken down my horizon +} +\description{ +Make a CRPS density plot for a subset of locations +} diff --git a/wweval/man/make_fig5.Rd b/wweval/man/make_fig5.Rd index 32d1bcc1..11d8f507 100644 --- a/wweval/man/make_fig5.Rd +++ b/wweval/man/make_fig5.Rd @@ -7,10 +7,8 @@ make_fig5( fig5_plot_wis_t_real_time, fig5_density_real_time, - fig5_plot_real_time_rel_wis, fig5_plot_wis_t_all_time, fig5_density_all_time, - fig5_plot_all_time_rel_wis, fig5_heatmap_rel_wis_all_time, fig5_heatmap_rel_wis_feb_mar, fig5_qq_plot_all_time, @@ -27,18 +25,12 @@ each model in real-time (feb-mar)} \item{fig5_density_real_time}{density plot of relative performance across location, forecast_date, day, and model} -\item{fig5_plot_real_time_rel_wis}{heatmap of the relative wis between -the two models} - \item{fig5_plot_wis_t_all_time}{average wis over time across locations for each model in real-time (feb-mar)} \item{fig5_density_all_time}{density plot of relative performance across location, forecast_date, day, and model} -\item{fig5_plot_all_time_rel_wis}{heatmap of the relative wis between -the two models} - \item{fig5_heatmap_rel_wis_all_time}{heatmap comparing WIS across forecast dates for each location for all time} @@ -57,6 +49,12 @@ for the real-time period (Feb-Mar)} for all time} \item{fig_file_dir}{Path to save figures} + +\item{fig5_plot_real_time_rel_wis}{heatmap of the relative wis between +the two models} + +\item{fig5_plot_all_time_rel_wis}{heatmap of the relative wis between +the two models} } \value{ a ggplot object containing all the figures combined diff --git a/wweval/man/order_locations.Rd b/wweval/man/order_locations.Rd index 08d70736..9c200fc8 100644 --- a/wweval/man/order_locations.Rd +++ b/wweval/man/order_locations.Rd @@ -4,12 +4,15 @@ \alias{order_locations} \title{Get the order of the locations for plotting} \usage{ -order_locations(df) +order_locations(df, score_name) } \arguments{ \item{df}{a dataframe containing the column name \code{phase} which will contain character strings indicating the phase of the epidemic (increasing, decreasing, peak, or nadir) of the score/quantile/sample.} + +\item{score_name}{string indicating the name of the score either \code{rel_crps} +or \code{rel_wis}} } \value{ a dataframe containing the same columns as \code{df} but with the From 65c8b37ae5b0f652b9bd7b66fd36567f05ba654a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 03:27:12 +0000 Subject: [PATCH 076/110] fix documentation --- wweval/R/ms_fig4.R | 8 ++++---- wweval/man/get_plot_rel_wis_distrib.Rd | 2 +- wweval/man/make_fig4_avg_wis_over_time.Rd | 8 ++++---- wweval/man/make_fig4_rel_wis_by_location.Rd | 2 +- wweval/man/make_fig4_rel_wis_over_time.Rd | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index d102da3b..b69a5ed2 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -787,7 +787,7 @@ make_fig4_avg_crps_over_time <- function(scores, #' Get a density plot of the relative WIS distribution #' -#' @param scores tibble of scores by horizon day, forecast date, and location +#' @param wis_scores tibble of scores by horizon day, forecast date, and location #' #' @return ggplot object of distribution of relative CRPS scores get_plot_rel_wis_distrib <- function(wis_scores) { @@ -878,7 +878,7 @@ make_fig4_heatmap_rel_wis <- function(rel_scores, #' Plot average WIS over time for model comparison #' -#' @param scores A tibble of scores by location, forecast date, date and model, +#' @param wis_scores A tibble of scores by location, forecast date, date and model, #' containing the outputs of `scoringutils::score()` on samples plus metadata #' transformed into a tibble. #' @param horizon_time_in_weeks horizon time in weeks to summarize over, default @@ -956,7 +956,7 @@ make_fig4_avg_wis_over_time <- function(wis_scores, #' Make a CRPS density plot for a subset of locations #' -#' @param scores A tibble of scores by location, forecast date, date and model, +#' @param wis_scores A tibble of scores by location, forecast date, date and model, #' containing the outputs of `scoringutils::score()` on samples plus metadata #' transformed into a tibble. #' @return a ggplot object that is a vertical facet of violin plots colored @@ -1019,7 +1019,7 @@ make_fig4_rel_wis_over_time <- function(wis_scores) { #' Make figure that stratifies scores by location across forecast dates #' -#' @param scores A tibble of scores by location, forecast date, date and model, +#' @param wis_scores A tibble of scores by location, forecast date, date and model, #' containing the outputs of `scoringutils::score()` on samples plus metadata #' transformed into a tibble. #' diff --git a/wweval/man/get_plot_rel_wis_distrib.Rd b/wweval/man/get_plot_rel_wis_distrib.Rd index 7f55d965..e2c39220 100644 --- a/wweval/man/get_plot_rel_wis_distrib.Rd +++ b/wweval/man/get_plot_rel_wis_distrib.Rd @@ -7,7 +7,7 @@ get_plot_rel_wis_distrib(wis_scores) } \arguments{ -\item{scores}{tibble of scores by horizon day, forecast date, and location} +\item{wis_scores}{tibble of scores by horizon day, forecast date, and location} } \value{ ggplot object of distribution of relative CRPS scores diff --git a/wweval/man/make_fig4_avg_wis_over_time.Rd b/wweval/man/make_fig4_avg_wis_over_time.Rd index e85fdc48..f801457d 100644 --- a/wweval/man/make_fig4_avg_wis_over_time.Rd +++ b/wweval/man/make_fig4_avg_wis_over_time.Rd @@ -7,13 +7,13 @@ make_fig4_avg_wis_over_time(wis_scores, horizon_time_in_weeks = NULL) } \arguments{ +\item{wis_scores}{A tibble of scores by location, forecast date, date and model, +containing the outputs of \code{scoringutils::score()} on samples plus metadata +transformed into a tibble.} + \item{horizon_time_in_weeks}{horizon time in weeks to summarize over, default is \code{NULL} which means that the scores are summarized over the nowcast period and the 4 week forecast period} - -\item{scores}{A tibble of scores by location, forecast date, date and model, -containing the outputs of \code{scoringutils::score()} on samples plus metadata -transformed into a tibble.} } \value{ a ggplot object plotting the magnitude of the avg wiss across diff --git a/wweval/man/make_fig4_rel_wis_by_location.Rd b/wweval/man/make_fig4_rel_wis_by_location.Rd index 8b14f8e4..ea6f1b2e 100644 --- a/wweval/man/make_fig4_rel_wis_by_location.Rd +++ b/wweval/man/make_fig4_rel_wis_by_location.Rd @@ -7,7 +7,7 @@ make_fig4_rel_wis_by_location(wis_scores) } \arguments{ -\item{scores}{A tibble of scores by location, forecast date, date and model, +\item{wis_scores}{A tibble of scores by location, forecast date, date and model, containing the outputs of \code{scoringutils::score()} on samples plus metadata transformed into a tibble.} } diff --git a/wweval/man/make_fig4_rel_wis_over_time.Rd b/wweval/man/make_fig4_rel_wis_over_time.Rd index 8e46cd5e..368487f8 100644 --- a/wweval/man/make_fig4_rel_wis_over_time.Rd +++ b/wweval/man/make_fig4_rel_wis_over_time.Rd @@ -7,7 +7,7 @@ make_fig4_rel_wis_over_time(wis_scores) } \arguments{ -\item{scores}{A tibble of scores by location, forecast date, date and model, +\item{wis_scores}{A tibble of scores by location, forecast date, date and model, containing the outputs of \code{scoringutils::score()} on samples plus metadata transformed into a tibble.} } From c3b965991bc41005d00505eecd8106ce12794f60 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 03:33:15 +0000 Subject: [PATCH 077/110] fix docs --- wweval/R/ms_fig4.R | 2 -- wweval/man/make_fig4.Rd | 4 ---- 2 files changed, 6 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index b69a5ed2..2ec8b157 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -1095,8 +1095,6 @@ make_fig4_rel_wis_by_location <- function(wis_scores) { #' @param fig4_rel_crps_over_time relative crps across locations by forecast #' date #' @param fig4_rel_crps_by_location avg crps across forecast dates by state -#' @param fig4_qq_plot_overall overall qq plot -#' @param fig4_plot_coverage_range interval coverage plots at 3 intervals #' @param time_period string to save fig as, either "real_time" or "all_time" #' @param fig_file_dir Path to save figures #' diff --git a/wweval/man/make_fig4.Rd b/wweval/man/make_fig4.Rd index 8dfa082c..78f90f7a 100644 --- a/wweval/man/make_fig4.Rd +++ b/wweval/man/make_fig4.Rd @@ -34,10 +34,6 @@ date} \item{time_period}{string to save fig as, either "real_time" or "all_time"} \item{fig_file_dir}{Path to save figures} - -\item{fig4_qq_plot_overall}{overall qq plot} - -\item{fig4_plot_coverage_range}{interval coverage plots at 3 intervals} } \value{ ggplot object with all the elements combined From ffdba087e95bd7a4462cc67d19016eb35cf345fe Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 03:41:48 +0000 Subject: [PATCH 078/110] more doc fixes --- wweval/R/ms_fig5.R | 4 ---- wweval/man/make_fig5.Rd | 6 ------ 2 files changed, 10 deletions(-) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 0a909317..f45c0f0b 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -545,14 +545,10 @@ make_fig5_density_rank <- function(scores, #' each model in real-time (feb-mar) #' @param fig5_density_real_time density plot of relative performance #' across location, forecast_date, day, and model -#' @param fig5_plot_real_time_rel_wis heatmap of the relative wis between -#' the two models #' @param fig5_plot_wis_t_all_time average wis over time across locations for #' each model in real-time (feb-mar) #' @param fig5_density_all_time density plot of relative performance #' across location, forecast_date, day, and model -#' @param fig5_plot_all_time_rel_wis heatmap of the relative wis between -#' the two models #' @param fig5_heatmap_rel_wis_all_time heatmap comparing WIS across #' forecast dates for each location for all time #' @param fig5_heatmap_rel_wis_feb_mar heatmap comparing WIS across diff --git a/wweval/man/make_fig5.Rd b/wweval/man/make_fig5.Rd index 11d8f507..a16a3be9 100644 --- a/wweval/man/make_fig5.Rd +++ b/wweval/man/make_fig5.Rd @@ -49,12 +49,6 @@ for the real-time period (Feb-Mar)} for all time} \item{fig_file_dir}{Path to save figures} - -\item{fig5_plot_real_time_rel_wis}{heatmap of the relative wis between -the two models} - -\item{fig5_plot_all_time_rel_wis}{heatmap of the relative wis between -the two models} } \value{ a ggplot object containing all the figures combined From 4e242df823a4a579b5915111d1219a54ab3e1f46 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 03:47:38 +0000 Subject: [PATCH 079/110] doc fix take 17 --- wweval/R/ms_fig4.R | 2 +- wweval/man/make_qq_plot_overall.Rd | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 2ec8b157..eb5b7650 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -489,7 +489,7 @@ make_fig4_rel_crps_overall <- function(scores, #' @param scores_quantiles A tibble of scores by location, forecast date, #' date and model, containing the outputs of `scoringutils::score()` on #' quantiles plus metadata transformed into a tibble. -#' @param fig_file_fir string indicating directory to save figure, +#' @param fig_file_dir string indicating directory to save figure, #' default is NULL #' @param write_files boolean indicating whether to save the file, default is #' `FALSE` diff --git a/wweval/man/make_qq_plot_overall.Rd b/wweval/man/make_qq_plot_overall.Rd index 6b4a8753..80e75c27 100644 --- a/wweval/man/make_qq_plot_overall.Rd +++ b/wweval/man/make_qq_plot_overall.Rd @@ -15,11 +15,11 @@ make_qq_plot_overall( date and model, containing the outputs of \code{scoringutils::score()} on quantiles plus metadata transformed into a tibble.} +\item{fig_file_dir}{string indicating directory to save figure, +default is NULL} + \item{write_files}{boolean indicating whether to save the file, default is \code{FALSE}} - -\item{fig_file_fir}{string indicating directory to save figure, -default is NULL} } \value{ a ggplot object with the overall QQ plot colored by model. From e9bf2a22e97afaefc0325d8cca94b41bed7b2e71 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 13:45:29 +0000 Subject: [PATCH 080/110] add horizontal line at 1 --- wweval/R/ms_fig4.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index eb5b7650..515cc11d 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -324,6 +324,7 @@ get_plot_rel_crps_distrib <- function(scores, show.legend = FALSE, fill = "darkblue" ) + + geom_hline(aes(yintercept = 1), linetype = "dashed") + get_plot_theme() + ylab("Relative CRPS") + xlab("Density") + @@ -819,6 +820,7 @@ get_plot_rel_wis_distrib <- function(wis_scores) { show.legend = FALSE, fill = "darkblue" ) + + geom_hline(aes(yintercept = 1), linetype = "dashed") + get_plot_theme() + ylab("Relative WIS") + xlab("Density") + From 75fe273e1afe43380ffa4d8710676558034b7552 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 18:10:05 +0000 Subject: [PATCH 081/110] replace ww wis with github scores, tweak plots --- _targets_eval_postprocessing.R | 68 +++++++++++-------------- wweval/NAMESPACE | 1 + wweval/R/ms_fig3.R | 5 +- wweval/R/ms_fig4.R | 6 ++- wweval/R/ms_fig5.R | 4 +- wweval/R/score_real_time_outputs.R | 59 +++++++++++++++++++-- wweval/R/supplement_analyses_and_figs.R | 5 +- wweval/man/combine_hub_and_local_wis.Rd | 20 ++++++++ wweval/man/score_real_time_outputs.Rd | 6 ++- 9 files changed, 124 insertions(+), 50 deletions(-) create mode 100644 wweval/man/combine_hub_and_local_wis.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 08df2d96..f8a1c992 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -375,14 +375,6 @@ head_to_head_targets <- list( any_flags_ww == FALSE, any_flags_hosp == FALSE ) |> - dplyr::anti_join( - ww_forecast_date_locs_to_excl |> - dplyr::mutate(forecast_date = lubridate::ymd(forecast_date)), - by = c( - "location", - "forecast_date" - ) - ) |> dplyr::left_join( last_hosp_data_date_map, by = c("location", "forecast_date") @@ -447,14 +439,6 @@ head_to_head_targets <- list( dplyr::left_join(table_of_loc_dates_w_ww, by = c("location", "forecast_date") ) |> - dplyr::anti_join( - ww_forecast_date_locs_to_excl |> - dplyr::mutate(forecast_date = lubridate::ymd(forecast_date)), - by = c( - "location", - "forecast_date" - ) - ) |> dplyr::filter(ww_sufficient) |> dplyr::left_join( convergence_df, @@ -1258,7 +1242,7 @@ real_time_rel_targets <- list( ) ), tar_target( - name = real_time_wis_both_models, + name = real_time_wis_hosp_only, command = score_real_time_outputs( score_type = "wis", real_time_output_dir = eval_config$real_time_output_dir, @@ -1269,7 +1253,15 @@ real_time_rel_targets <- list( to = lubridate::ymd("2024-03-11"), by = "week" )), - eval_data = eval_hosp_data + eval_data = eval_hosp_data, + hosp_only = TRUE + ) + ), + tar_target( + name = real_time_wis_both_models, + command = combine_hub_and_local_wis( + cfa_real_time_scores, + real_time_wis_hosp_only ) ), tar_target( @@ -1281,6 +1273,18 @@ real_time_rel_targets <- list( command = rel_real_time_wis |> dplyr::ungroup() |> dplyr::summarise(mean_rel_wis = mean(rel_wis, na.rm = TRUE)) + ), + tar_target( + name = rel_mean_wis_real_time, + command = real_time_wis_both_models |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c("model")) |> + dplyr::select(model, interval_score) |> + tidyr::pivot_wider( + names_from = model, + values_from = interval_score + ) |> + dplyr::mutate(rel_wis = ww / hosp) ) ) @@ -1563,27 +1567,17 @@ hub_comparison_plots <- list( time_period = "Feb-Mar 2024" ) ), - ## Fig 4 real-time relative combined----------------------------------------- + ## Real-time relative----------------------------------------- tar_target( - name = wis_scores_rt, + name = wis_scores_rt_summarized, command = real_time_wis_both_models |> - dplyr::anti_join(as.data.frame( - eval_config$ww_forecast_date_locs_to_excl - ) |> - dplyr::mutate(forecast_date = lubridate::ymd(forecast_date))) - ), - tar_target( - name = rel_real_time_wis_submitted, - command = rel_real_time_wis |> - dplyr::anti_join(as.data.frame( - eval_config$ww_forecast_date_locs_to_excl - ) |> - dplyr::mutate(forecast_date = lubridate::ymd(forecast_date))) + data.table::as.data.table() |> + scoringutils::summarise_scores() ), tar_target( name = fig4_rel_wis_heatmap, command = make_fig4_heatmap_rel_wis( - rel_scores = rel_real_time_wis_submitted, + rel_scores = rel_real_time_wis, time_period = "Feb-Mar 2024", analysis_type = "Real-time" ) @@ -1591,7 +1585,7 @@ hub_comparison_plots <- list( tar_target( name = fig4_rel_wis_hist, command = get_plot_rel_wis_distrib( - wis_scores = wis_scores_rt + wis_scores = wis_scores_rt_summarized ) ), tar_target( @@ -1605,19 +1599,19 @@ hub_comparison_plots <- list( tar_target( name = fig4_avg_wis, command = make_fig4_avg_wis_over_time( - wis_scores_rt + wis_scores_rt_summarized ) ), tar_target( name = fig4_rel_wis_over_time, command = make_fig4_rel_wis_over_time( - wis_scores_rt + wis_scores_rt_summarized ) ), tar_target( name = fig4_rel_wis_by_location, command = make_fig4_rel_wis_by_location( - wis_scores_rt + wis_scores_rt_summarized ) ), ### Fig 4 real-time relative combined--------------------------------------------- diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index d5f58560..e383ff5b 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -6,6 +6,7 @@ export(clean_and_filter_nwss_data) export(clean_ww_data) export(cleanup_secrets) export(combine_and_summarize_ww_data) +export(combine_hub_and_local_wis) export(combine_outputs) export(compute_relative_crps) export(create_hub_submissions) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index 67a46037..bb8e18b7 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -175,7 +175,8 @@ make_fig3_single_loc_comp <- function(scores, x_axis_text_size = 6 ) + scale_y_continuous(trans = "log10") + # , limits = c(0.25, 4.0)) + - labs(color = "Model") + labs(color = "Model") + + coord_cartesian(ylim = c(1 / 6, 6)) # Also make a bar chart of the two average crps scores @@ -345,7 +346,7 @@ make_fig3_crps_underlay_fig <- function(scores, labels = scales::date_format("%Y-%m-%d"), limits = date_lims ) + - coord_cartesian(ylim = c(0, max_crps + 0.05)) + + coord_cartesian(ylim = c(0, 1)) + get_plot_theme( x_axis_dates = TRUE, y_axis_title_size = 8, diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 515cc11d..6a432a64 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -328,7 +328,8 @@ get_plot_rel_crps_distrib <- function(scores, get_plot_theme() + ylab("Relative CRPS") + xlab("Density") + - scale_y_continuous(trans = "log10") + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(1 / 3.5, 3.5)) return(p_log) } @@ -824,7 +825,8 @@ get_plot_rel_wis_distrib <- function(wis_scores) { get_plot_theme() + ylab("Relative WIS") + xlab("Density") + - scale_y_continuous(trans = "log10") + scale_y_continuous(trans = "log10") + + coord_cartesian(ylim = c(1 / 3.5, 3.5)) return(p_log) } diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index f45c0f0b..bfbc604d 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -587,7 +587,7 @@ CCDDEE axes = "collect", guides = "collect" ) & theme( - legend.position = "none" + legend.position = "bottom" ) # legend.justification = "left" #nolint # ) #+ plot_annotation(tag_levels = "A") #nolint, not working @@ -612,7 +612,7 @@ CCDDEE axes = "collect", guides = "collect" ) & theme( - legend.position = "none" + legend.position = "bottom" ) # legend.justification = "left" #nolint # ) #+ plot_annotation(tag_levels = "A") #nolint, not working diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index b1810f83..cd87c8f2 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -12,6 +12,8 @@ #' @param dates A vector of forecast dates to pull #' @param eval_data a tibble of hospital admissions evaluation data to be used #' for scoring. +#' @param hosp_only boolean indicating if we should only pull the hospital +#' admissions model #' #' @return A large tibble containing crps scores for every location and #' forecast date, conditioned on the presence of wastewater and model @@ -22,8 +24,13 @@ score_real_time_outputs <- function(score_type, table_of_run_ids, locations, dates, - eval_data) { - model_types <- c("ww", "hosp") + eval_data, + hosp_only = FALSE) { + if (isTRUE(hosp_only)) { + model_types <- c("hosp") + } else { + model_types <- c("ww", "hosp") + } all_scores <- c() data_type <- ifelse(score_type == "crps", "draws", "quantiles") @@ -168,7 +175,8 @@ score_real_time_outputs <- function(score_type, ) |> scoringutils::check_forecasts() |> scoringutils::score() |> - tibble::tibble() + tibble::tibble() |> + dplyr::filter(scale == "log") } else { scores <- c() } @@ -235,3 +243,48 @@ format_scores_for_comparison <- function(real_time_scores, return(formatted_scores) } + +#' Combine thehosp only real-time scores and cfa real +#' time scores from github +#' +#' @param cfa_real_time_scores Hub formatted scores for +#' only the ww model, `cfa-wwrenewal(real-time)` +#' @param real_time_wis_hosp_only hosp only +#' wis scores calculated from local data +#' +#' @return +#' @export +#' +#' @examples +combine_hub_and_local_wis <- function( + cfa_real_time_scores, + real_time_wis_hosp_only) { + real_time_wis_ho <- real_time_wis_hosp_only |> + dplyr::select(-failed_convergence) + + loc_map_table <- cfa_real_time_scores |> + dplyr::distinct(location) |> + dplyr::left_join(wweval::flusight_location_table, + by = c("location" = "location_code") + ) + + rt_reformatted <- cfa_real_time_scores |> + dplyr::rename(location_code = location) |> + dplyr::left_join(loc_map_table, + by = c("location_code" = "location") + ) |> + dplyr::rename( + location = short_name, + date = target_end_date, + ) |> + dplyr::mutate( + model = "ww" + ) |> + dplyr::select(colnames(real_time_wis_ho)) + + real_time_wis_both_models <- dplyr::bind_rows( + rt_reformatted, + real_time_wis_ho + ) + return(real_time_wis_both_models) +} diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 9048dfb5..e550bf46 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -1065,13 +1065,12 @@ get_rel_wis_real_time <- function(all_scores) { dplyr::filter(scale == "log") |> as.data.table() |> scoringutils::summarise_scores( - by = c("forecast_date", "model", "location", "failed_convergence") + by = c("forecast_date", "model", "location") ) |> dplyr::select( - forecast_date, model, location, failed_convergence, + forecast_date, model, location, interval_score ) |> - dplyr::filter(failed_convergence == FALSE) |> tidyr::pivot_wider( names_from = model, values_from = interval_score diff --git a/wweval/man/combine_hub_and_local_wis.Rd b/wweval/man/combine_hub_and_local_wis.Rd new file mode 100644 index 00000000..ace4d0df --- /dev/null +++ b/wweval/man/combine_hub_and_local_wis.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/score_real_time_outputs.R +\name{combine_hub_and_local_wis} +\alias{combine_hub_and_local_wis} +\title{Combine thehosp only real-time scores and cfa real +time scores from github} +\usage{ +combine_hub_and_local_wis(cfa_real_time_scores, real_time_wis_hosp_only) +} +\arguments{ +\item{cfa_real_time_scores}{Hub formatted scores for +only the ww model, \code{cfa-wwrenewal(real-time)}} + +\item{real_time_wis_hosp_only}{hosp only +wis scores calculated from local data} +} +\description{ +Combine thehosp only real-time scores and cfa real +time scores from github +} diff --git a/wweval/man/score_real_time_outputs.Rd b/wweval/man/score_real_time_outputs.Rd index aea04811..12524c4c 100644 --- a/wweval/man/score_real_time_outputs.Rd +++ b/wweval/man/score_real_time_outputs.Rd @@ -10,7 +10,8 @@ score_real_time_outputs( table_of_run_ids, locations, dates, - eval_data + eval_data, + hosp_only = FALSE ) } \arguments{ @@ -31,6 +32,9 @@ pull, this should be all jurisdictions} \item{eval_data}{a tibble of hospital admissions evaluation data to be used for scoring.} + +\item{hosp_only}{boolean indicating if we should only pull the hospital +admissions model} } \value{ A large tibble containing crps scores for every location and From e2083a9966997f8b19f3b018f9fde90964a62d9f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Wed, 4 Dec 2024 21:00:25 +0000 Subject: [PATCH 082/110] add loc summaries rt relative --- _targets_eval_postprocessing.R | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index f8a1c992..f77a26c5 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -342,7 +342,8 @@ head_to_head_targets <- list( ), tar_target( name = ww_forecast_date_locs_to_excl, - command = as.data.frame(eval_config$ww_forecast_date_locs_to_excl) + command = as.data.frame(eval_config$ww_forecast_date_locs_to_excl) |> + dplyr::mutate(forecast_date = lubridate::ymd(forecast_date)) ), # Get the full set of quantiles, filtered down to only states and @@ -1258,12 +1259,22 @@ real_time_rel_targets <- list( ) ), tar_target( - name = real_time_wis_both_models, + name = real_time_wis_both_models_raw, command = combine_hub_and_local_wis( cfa_real_time_scores, real_time_wis_hosp_only ) ), + # For the real-time comparison, we exclude the forecasts that are the + # same + tar_target( + name = real_time_wis_both_models, + command = real_time_wis_both_models_raw |> + dplyr::anti_join(ww_forecast_date_locs_to_excl) |> + # Could eventually replace this with what is on the Hub + dplyr::left_join(table_of_loc_dates_w_ww) |> + dplyr::filter(ww_sufficient) + ), tar_target( name = rel_real_time_wis, command = get_rel_wis_real_time(real_time_wis_both_models) @@ -1285,6 +1296,19 @@ real_time_rel_targets <- list( values_from = interval_score ) |> dplyr::mutate(rel_wis = ww / hosp) + ), + tar_target( + name = rel_mean_wis_rt_locs, + command = real_time_wis_both_models |> + dplyr::filter(location %in% c("TX", "FL", "IL", "MI")) |> + data.table::as.data.table() |> + scoringutils::summarise_scores(by = c("model", "location")) |> + dplyr::select(model, interval_score, location) |> + tidyr::pivot_wider( + names_from = model, + values_from = interval_score + ) |> + dplyr::mutate(rel_wis = ww / hosp) ) ) @@ -1467,7 +1491,7 @@ hub_targets <- list( tar_target( name = cfa_hosp_real_time_scores, command = format_scores_for_comparison( - real_time_scores = real_time_wis_both_models, + real_time_scores = real_time_wis_both_models_raw, other_real_time_scores = cfa_real_time_scores ) ), From 162c9e62ad48822abb302d0b6ab1329de202a19e Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 5 Dec 2024 00:22:12 +0000 Subject: [PATCH 083/110] tweaks to figs and summaries --- _targets_eval_postprocessing.R | 2 +- wweval/R/ms_fig3.R | 1 + wweval/R/ms_fig4.R | 12 +++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index f77a26c5..4ce3f60e 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -963,7 +963,7 @@ manuscript_figures <- list( name = loc_summary, command = get_loc_rel_crps( scores_filtered, - locs = c("DC", "OH", "NH", "CO") + locs = c("DC", "OH", "NH", "CO", "IL", "IN") ) ), ## Fig 4: retro relative-------------------------------------------------- diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index bb8e18b7..e4b8e056 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -170,6 +170,7 @@ make_fig3_single_loc_comp <- function(scores, theme_bw() + scale_color_manual(values = colors$horizon_colors) + scale_fill_manual(values = colors$horizon_colors) + + geom_hline(aes(yintercept = 1), linetype = "dashed") + get_plot_theme( y_axis_title_size = 8, x_axis_text_size = 6 diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 6a432a64..1a02e568 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -233,11 +233,13 @@ make_fig4_admissions_overall <- function(eval_hosp_data, get_loc_rel_crps <- function(scores, locs) { relative_crps <- scores |> dplyr::filter(location %in% locs) |> - compute_relative_crps(id_cols = c( - "location", "forecast_date", "date" - )) |> - dplyr::group_by(location) |> - dplyr::summarise(mean = mean(rel_crps)) + dplyr::group_by(location, model) |> + dplyr::summarise(mean_crps = mean(crps)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps + ) |> + dplyr::mutate(rel_mean_crps = ww / hosp) return(relative_crps) } From a51c0235201171d41c246977544c954cdfc22efa Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 5 Dec 2024 14:45:13 +0000 Subject: [PATCH 084/110] add qq plot and coverage range plot for real time --- _targets_eval_postprocessing.R | 30 +++++++++++++++++++++++++ wweval/R/ms_fig4.R | 10 ++++++--- wweval/R/score_real_time_outputs.R | 5 ++--- wweval/man/combine_hub_and_local_wis.Rd | 4 ++++ wweval/man/make_plot_coverage_range.Rd | 3 +++ wweval/man/make_qq_plot_overall.Rd | 3 +++ 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 4ce3f60e..c6f5d408 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1025,6 +1025,7 @@ manuscript_figures <- list( name = fig4_qq_plot_overall, command = make_qq_plot_overall( scores_quantiles_filtered, + time_period = "retro_all_time", fig_file_dir = eval_config$ms_fig_dir, write_files = TRUE ) @@ -1034,6 +1035,7 @@ manuscript_figures <- list( command = make_plot_coverage_range( scores_quantiles_filtered, ranges = c(30, 60, 90), + time_period = "retro_all_time", fig_file_dir = eval_config$ms_fig_dir, write_files = TRUE ) @@ -1638,6 +1640,34 @@ hub_comparison_plots <- list( wis_scores_rt_summarized ) ), + tar_target( + name = fig4_qq_plot_rt, + command = make_qq_plot_overall( + real_time_wis_both_models, + time_period = "real_time", + fig_file_dir = eval_config$ms_fig_dir, + write_files = TRUE + ) + ), + tar_target( + name = fig4_plot_coverage_range_rt, + command = make_plot_coverage_range( + scores_quantiles = real_time_wis_both_models |> + dplyr::mutate( + horizon_days = as.integer(date - forecast_date), + horizon = case_when( + horizon_days <= 7 ~ "1 wk", + horizon_days <= 14 & horizon_days > 7 ~ "2 wks", + horizon_days <= 21 & horizon_days > 14 ~ "3 wks", + horizon_days <= 28 & horizon_days > 21 ~ "4 wks" + ) + ), + ranges = c(30, 60, 90), + time_period = "real_time", + fig_file_dir = eval_config$ms_fig_dir, + write_files = TRUE + ) + ), ### Fig 4 real-time relative combined--------------------------------------------- tar_target( name = fig4_rt, diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 1a02e568..37711d4e 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -493,6 +493,7 @@ make_fig4_rel_crps_overall <- function(scores, #' @param scores_quantiles A tibble of scores by location, forecast date, #' date and model, containing the outputs of `scoringutils::score()` on #' quantiles plus metadata transformed into a tibble. +#' @param time_period string indicating time period of fig to save #' @param fig_file_dir string indicating directory to save figure, #' default is NULL #' @param write_files boolean indicating whether to save the file, default is @@ -501,6 +502,7 @@ make_fig4_rel_crps_overall <- function(scores, #' @return a ggplot object with the overall QQ plot colored by model. #' @export make_qq_plot_overall <- function(scores_quantiles, + time_period, fig_file_dir = NULL, write_files = FALSE) { colors <- plot_components() @@ -514,13 +516,13 @@ make_qq_plot_overall <- function(scores_quantiles, ylab = "Percent of data below quantile", col = "Model" ) + - theme(legend.position = "none") + + theme(legend.position = "right") + scale_color_manual(values = colors$model_colors) if (isTRUE(write_files)) { ggsave(p, filename = file.path( fig_file_dir, - glue::glue("sfig_qq_plot_retro_all_time.png") + glue::glue("sfig_qq_plot_{time_period}.png") ) ) } @@ -537,6 +539,7 @@ make_qq_plot_overall <- function(scores_quantiles, #' #' @param ranges A numeric vector of credible interval ranges to plot, #' spanning from 0 to 100. +#' @param time_period string indicating time period of fig to save #' @param fig_file_dir string indicating directory to save figure in, #' default is `NULL` #' @param write_files boolean indicating whether to save file, default is FALSE @@ -545,6 +548,7 @@ make_qq_plot_overall <- function(scores_quantiles, #' make_plot_coverage_range <- function(scores_quantiles, ranges, + time_period, fig_file_dir = NULL, write_files = FALSE) { scores_by_horizon <- scores_quantiles |> @@ -600,7 +604,7 @@ make_plot_coverage_range <- function(scores_quantiles, ggsave(p, filename = file.path( fig_file_dir, - glue::glue("sfig_coverage_range_retro_all_time.png") + glue::glue("sfig_coverage_range_{time_period}.png") ), height = 4, width = 10 diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index cd87c8f2..f7c534bc 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -252,10 +252,9 @@ format_scores_for_comparison <- function(real_time_scores, #' @param real_time_wis_hosp_only hosp only #' wis scores calculated from local data #' -#' @return +#' @return a df formatted the same way as the real_time_wis_hosp_only scores, +#' but for both models #' @export -#' -#' @examples combine_hub_and_local_wis <- function( cfa_real_time_scores, real_time_wis_hosp_only) { diff --git a/wweval/man/combine_hub_and_local_wis.Rd b/wweval/man/combine_hub_and_local_wis.Rd index ace4d0df..2d598aa5 100644 --- a/wweval/man/combine_hub_and_local_wis.Rd +++ b/wweval/man/combine_hub_and_local_wis.Rd @@ -14,6 +14,10 @@ only the ww model, \code{cfa-wwrenewal(real-time)}} \item{real_time_wis_hosp_only}{hosp only wis scores calculated from local data} } +\value{ +a df formatted the same way as the real_time_wis_hosp_only scores, +but for both models +} \description{ Combine thehosp only real-time scores and cfa real time scores from github diff --git a/wweval/man/make_plot_coverage_range.Rd b/wweval/man/make_plot_coverage_range.Rd index 1103917d..fbe3843f 100644 --- a/wweval/man/make_plot_coverage_range.Rd +++ b/wweval/man/make_plot_coverage_range.Rd @@ -7,6 +7,7 @@ make_plot_coverage_range( scores_quantiles, ranges, + time_period, fig_file_dir = NULL, write_files = FALSE ) @@ -19,6 +20,8 @@ quantiles plus metadata transformed into a tibble.} \item{ranges}{A numeric vector of credible interval ranges to plot, spanning from 0 to 100.} +\item{time_period}{string indicating time period of fig to save} + \item{fig_file_dir}{string indicating directory to save figure in, default is \code{NULL}} diff --git a/wweval/man/make_qq_plot_overall.Rd b/wweval/man/make_qq_plot_overall.Rd index 80e75c27..95eb3c22 100644 --- a/wweval/man/make_qq_plot_overall.Rd +++ b/wweval/man/make_qq_plot_overall.Rd @@ -6,6 +6,7 @@ \usage{ make_qq_plot_overall( scores_quantiles, + time_period, fig_file_dir = NULL, write_files = FALSE ) @@ -15,6 +16,8 @@ make_qq_plot_overall( date and model, containing the outputs of \code{scoringutils::score()} on quantiles plus metadata transformed into a tibble.} +\item{time_period}{string indicating time period of fig to save} + \item{fig_file_dir}{string indicating directory to save figure, default is NULL} From 7b6db676b589ccd3e7aaba169f04dc10f50478f1 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 5 Dec 2024 15:45:40 +0000 Subject: [PATCH 085/110] fix metadata heatmaps --- _targets_eval_postprocessing.R | 25 ++++--- wweval/R/get_date_locs_excluded.R | 21 ++++++ wweval/R/ms_fig4.R | 1 - wweval/R/supplement_analyses_and_figs.R | 92 ++++++++++++++++--------- wweval/man/get_heatmap_metadata_hub.Rd | 5 +- 5 files changed, 97 insertions(+), 47 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index c6f5d408..a1d8ab59 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -506,16 +506,6 @@ manuscript_figures <- list( include_manual_exclusions = FALSE ) ), - tar_target( - name = granular_ww_metadata_used_hub, - command = get_add_ww_metadata( - granular_ww_metadata, - ww_forecast_date_locs_to_excl, - convergence_df, - table_of_loc_dates_w_ww, - include_manual_exclusions = TRUE - ) - ), tar_target( name = summary_metadata, command = get_summary_metadata( @@ -531,10 +521,19 @@ manuscript_figures <- list( ) ), tar_target( - name = sfig_heatmap_metadata_hub, + name = sfig_heatmap_metadata_hub_retro, command = get_heatmap_metadata_hub( - granular_ww_metadata_used_hub, - fig_file_dir = eval_config$ms_fig_dir + granular_ww_metadata_used, + fig_file_dir = eval_config$ms_fig_dir, + analysis_type = "retro" + ) + ), + tar_target( + name = sfig_heatmap_metadata_hub_rt, + command = get_heatmap_metadata_hub( + granular_ww_metadata_used, + fig_file_dir = eval_config$ms_fig_dir, + analysis_type = "real_time" ) ), tar_target( diff --git a/wweval/R/get_date_locs_excluded.R b/wweval/R/get_date_locs_excluded.R index d89f3ea8..b30ead3a 100644 --- a/wweval/R/get_date_locs_excluded.R +++ b/wweval/R/get_date_locs_excluded.R @@ -27,3 +27,24 @@ get_date_locs_excluded <- function(dates) { } return(table_of_exclusions) } + +get_date_locs_hosp_used <- function(dates) { + table_of_replacements <- tibble::tibble() + for (i in seq_along(dates)) { + date <- dates[i] + + yaml_path <- file.path("output", "forecasts", date, "metadata.yaml") + + metadata <- yaml::read_yaml(yaml_path) + + locs_to_exclude <- unlist(metadata$`States we chose to use hospital admissions only model on`) + locs_wout_ww <- unlist(metadata$`States without wastewaster data`) + this_dates_replacements <- tibble::tibble( + location = c(locs_to_exclude, locs_wout_ww), + forecast_date = rep(date, length(c(locs_to_exclude, locs_wout_ww))) + ) + + table_of_replacements <- rbind(table_of_replacements, this_dates_replacements) + } + return(table_of_replacements) +} diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 37711d4e..9024dac2 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -510,7 +510,6 @@ make_qq_plot_overall <- function(scores_quantiles, data.table::as.data.table() |> scoringutils::summarise_scores(by = c("model", "quantile")) |> scoringutils::plot_quantile_coverage() + - ggtitle(glue::glue("QQ plot all-time")) + get_plot_theme() + labs( ylab = "Percent of data below quantile", diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index e550bf46..752459a0 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -985,46 +985,74 @@ get_heatmap_metadata <- function(metadata, #' Get a heatmap of the metadata of Hub models submitted #' #' @param metadata a tibble of location -forecast date metadata +#' @param analysis_type string indicating whether this is the +#' real-time or retro analysis, which dictates how metadata is gathered #' @param fig_file_dir string indicating where to save figs #' #' @return a ggplot object with a heatmap colored by reason for excluding #' @export get_heatmap_metadata_hub <- function(metadata, + analysis_type, fig_file_dir) { - metadata_summarized <- metadata |> - dplyr::select( - forecast_date, location, ww_data_present, - ww_exclude_manual, ww_sufficient, - any_flags_hosp, any_flags_ww - ) |> - dplyr::ungroup() |> - dplyr::mutate( - model_submitted = - dplyr::case_when( - ww_data_present != 1 ~ "hosp", - ww_sufficient != TRUE ~ "hosp", - any_flags_ww == TRUE ~ "hosp", - ww_exclude_manual == TRUE ~ "hosp", - TRUE ~ "ww" - ) - ) |> - dplyr::mutate( - model_name = "cfa-wwrenewal(retro)" - ) + if (analysis_type == "retro") { + metadata_summarized <- metadata |> + dplyr::select( + forecast_date, location, ww_data_present, + ww_sufficient, + any_flags_hosp, any_flags_ww + ) |> + dplyr::ungroup() |> + dplyr::mutate( + model_submitted = + dplyr::case_when( + ww_data_present != 1 ~ "hosp", + ww_sufficient != TRUE ~ "hosp", + any_flags_ww == TRUE ~ "hosp", + TRUE ~ "ww" + ) + ) |> + dplyr::mutate( + model_name = "cfa-wwrenewal(retro)" + ) - metadata_hosp_only <- metadata_summarized |> - dplyr::mutate( - model_submitted = "hosp", - model_name = "cfa-hosponlyrenewal(retro)" + metadata_hosp_only <- metadata_summarized |> + dplyr::mutate( + model_submitted = "hosp", + model_name = "cfa-hosponlyrenewal(retro)" + ) + + all_metadata <- dplyr::bind_rows( + metadata_summarized, metadata_hosp_only + ) + } else if (analysis_type == "real_time") { + # Then we need to get this info on metadata from our github! + dates <- seq( + from = lubridate::ymd("2024-02-05"), + to = lubridate::ymd("2024-03-11"), + by = "week" ) - metadata_real_time <- metadata_summarized |> - dplyr::filter(forecast_date >= "2024-02-05") |> - dplyr::mutate(model_name = "cfa-wwrenewal(real_time)") + df_replacements <- get_date_locs_hosp_used(dates) |> + dplyr::mutate( + model_submitted = "hosp" + ) + locs <- unique(metadata$location) + metadata_grid <- expand.grid(location = locs, forecast_date = dates) + metadata_ww <- metadata_grid |> + dplyr::left_join( + df_replacements + ) |> + dplyr::mutate( + model_submitted = ifelse(is.na(model_submitted), "ww", "hosp"), + model_name = "cfa-wwrenewal(real-time)" + ) + metadata_hosp <- metadata_grid |> + dplyr::mutate( + model_submitted = "hosp", + model_name = "cfa-hosponlyrenewal(real-time)" + ) + all_metadata <- dplyr::bind_rows(metadata_ww, metadata_hosp) + } - all_metadata <- dplyr::bind_rows( - metadata_summarized, metadata_hosp_only, - metadata_real_time - ) colors <- plot_components() p <- ggplot(all_metadata) + geom_tile(aes(x = forecast_date, y = location, fill = model_submitted)) + @@ -1048,7 +1076,7 @@ get_heatmap_metadata_hub <- function(metadata, height = 7, width = 12, filename = file.path( fig_file_dir, - glue::glue("sfig_heatmap_hub_metadata.png") + glue::glue("sfig_heatmap_hub_metadata_{analysis_type}.png") ) ) } diff --git a/wweval/man/get_heatmap_metadata_hub.Rd b/wweval/man/get_heatmap_metadata_hub.Rd index 2d39c4dd..fa34f595 100644 --- a/wweval/man/get_heatmap_metadata_hub.Rd +++ b/wweval/man/get_heatmap_metadata_hub.Rd @@ -4,11 +4,14 @@ \alias{get_heatmap_metadata_hub} \title{Get a heatmap of the metadata of Hub models submitted} \usage{ -get_heatmap_metadata_hub(metadata, fig_file_dir) +get_heatmap_metadata_hub(metadata, analysis_type, fig_file_dir) } \arguments{ \item{metadata}{a tibble of location -forecast date metadata} +\item{analysis_type}{string indicating whether this is the +real-time or retro analysis, which dictates how metadata is gathered} + \item{fig_file_dir}{string indicating where to save figs} } \value{ From 532676d6be7839f37ba9039149b4b8b9a57682ee Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 5 Dec 2024 15:58:39 +0000 Subject: [PATCH 086/110] remove the retro models from the bar chart --- _targets_eval_postprocessing.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index a1d8ab59..afec4517 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1528,7 +1528,11 @@ hub_comparison_plots <- list( tar_target( name = fig5_summary_table_Feb_Mar, command = make_fig5_table_and_plot( - combine_scores_feb_mar, + combine_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-hosponlyrenewal(retro)", + "cfa-wwrenewal(retro)" + )), time_period = "Feb-Mar", fig_file_dir = eval_config$ms_fig_dir ) From 5a3ef421df52385f8834b4408d3bef413b83f6d0 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Mon, 9 Dec 2024 16:12:47 +0000 Subject: [PATCH 087/110] save summary metadata ww files --- _targets_eval_postprocessing.R | 3 ++- wweval/R/combine_and_summarize_ww_data.R | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index afec4517..e75ddc62 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -540,7 +540,8 @@ manuscript_figures <- list( name = list_of_summary_ww_tables, command = get_summary_ww_table( granular_ww_metadata_used, - hosp_quantiles_filtered + hosp_quantiles_filtered, + output_dir = eval_config$output_dir ) ), ## Figure specifications---------------------------------------- diff --git a/wweval/R/combine_and_summarize_ww_data.R b/wweval/R/combine_and_summarize_ww_data.R index 9651e86d..7c7ef2b0 100644 --- a/wweval/R/combine_and_summarize_ww_data.R +++ b/wweval/R/combine_and_summarize_ww_data.R @@ -300,11 +300,14 @@ get_add_ww_metadata <- function(granular_ww_metadata, #' quantiled forecasts for the wastewater and hospital admissions only models #' after it has been filtered for convergence, wastewater data quality, #' manual exclusions, and dates that don't have any wastewater present +#' @param output_dir string indicating where to save the ww metadata tables #' #' @return a list containing a summary overall table, a summary by forecast #' date and a summary by state #' @export -get_summary_ww_table <- function(ww_metadata, hosp_quantiles_filtered) { +get_summary_ww_table <- function(ww_metadata, + hosp_quantiles_filtered, + output_dir) { # First, get the true number of forecast-date locations with wastewater # in the current analysis n_w_ww_actual <- hosp_quantiles_filtered |> @@ -401,6 +404,10 @@ get_summary_ww_table <- function(ww_metadata, hosp_quantiles_filtered) { avg_avg_sampling_freq = mean(.data$avg_sampling_freq, na.rm = TRUE), n_states_w_duplicate_obs = sum(.data$n_duplicate_obs > 0, na.rm = TRUE) ) + saveRDS(forecast_date_summary_table, file = file.path( + output_dir, + "forecast_date_summary_table.rds" + )) # Summarize across forecast dates by state state_summary_table <- @@ -413,6 +420,10 @@ get_summary_ww_table <- function(ww_metadata, hosp_quantiles_filtered) { avg_avg_sampling_frequency = mean(.data$avg_sampling_freq, na.rm = TRUE), n_forecast_dates_w_duplicate_obs = sum(.data$n_duplicate_obs > 0, na.rm = TRUE) ) + saveRDS(state_summary_table, file = file.path( + output_dir, + "state_summary_table.rds" + )) ww_metadata_list <- list( From 40cd8a9361615410c47d9a40cd14a572d905cbfe Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Mon, 9 Dec 2024 16:31:10 +0000 Subject: [PATCH 088/110] add docs --- wweval/man/get_summary_ww_table.Rd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wweval/man/get_summary_ww_table.Rd b/wweval/man/get_summary_ww_table.Rd index 33bf8182..69394363 100644 --- a/wweval/man/get_summary_ww_table.Rd +++ b/wweval/man/get_summary_ww_table.Rd @@ -4,7 +4,7 @@ \alias{get_summary_ww_table} \title{Get wastewater data summary tables} \usage{ -get_summary_ww_table(ww_metadata, hosp_quantiles_filtered) +get_summary_ww_table(ww_metadata, hosp_quantiles_filtered, output_dir) } \arguments{ \item{ww_metadata}{a tibble containing one row for every forecast date @@ -15,6 +15,8 @@ about the wastewater data. This is the output of "get_add_ww_metadata".} quantiled forecasts for the wastewater and hospital admissions only models after it has been filtered for convergence, wastewater data quality, manual exclusions, and dates that don't have any wastewater present} + +\item{output_dir}{string indicating where to save the ww metadata tables} } \value{ a list containing a summary overall table, a summary by forecast From 109fdb402ed92421e1c38ba182f4c6d8c8e8048c Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 10 Dec 2024 12:31:40 +0000 Subject: [PATCH 089/110] add a formatted figure of C(t) --- _targets_eval_postprocessing.R | 31 +++++++ wweval/NAMESPACE | 1 + wweval/R/ms_fig2.R | 148 ++++++++++++++++++++++++++++++++ wweval/man/make_fig2_ct_supp.Rd | 51 +++++++++++ 4 files changed, 231 insertions(+) create mode 100644 wweval/man/make_fig2_ct_supp.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index e75ddc62..35f274af 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1908,6 +1908,37 @@ supp_targets <- list( scores = scores_filtered, threshold = 0.1 ) + ), + tar_target( + name = ww_quants_plot_supp, + command = combine_outputs( + output_type = "ww_quantiles", + scenarios = "status_quo", + forecast_dates = c("2024-02-12"), + locations = c("OH", "IL"), + eval_output_subdir = eval_config$output_dir, + model_type = "ww" + ) + ), + tar_target( + name = ww_plot_supp_OH, + command = make_fig2_ct_supp( + ww_quants_plot_supp, + loc_to_plot = "OH", + max_n_site_labs_to_show = 12, + date_to_plot = "2024-02-12", + ms_fig_dir = eval_config$ms_fig_dir + ) + ), + tar_target( + name = ww_plot_supp_IL, + command = make_fig2_ct_supp( + ww_quants_plot_supp, + loc_to_plot = "IL", + max_n_site_labs_to_show = 12, + date_to_plot = "2024-02-12", + ms_fig_dir = eval_config$ms_fig_dir + ) ) ) diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index e383ff5b..f6aba5d5 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -73,6 +73,7 @@ export(make_baseline_score_table) export(make_df) export(make_fig2) export(make_fig2_ct) +export(make_fig2_ct_supp) export(make_fig2_hosp_t) export(make_fig3) export(make_fig3_crps_underlay_fig) diff --git a/wweval/R/ms_fig2.R b/wweval/R/ms_fig2.R index 2a27e75b..9e84c9d1 100644 --- a/wweval/R/ms_fig2.R +++ b/wweval/R/ms_fig2.R @@ -230,6 +230,154 @@ make_fig2_ct <- function(ww_quantiles, scale_shape_manual(values = colors$observation_status_shapes) return(p) } +#' Make concentration fit and forecast figure for supplement +#' +#' @param ww_quantiles A tibble containing the calibrated wastewater +#' concentrations, the evaluation wastewater concentration data, and the +#' quantiles of the calibrated and forecasted wastewater concentrations +#' @param loc_to_plot A character string indicating the state abbreviation +#' for which state to plot, can only be one state +#' @param date_to_plot A character string indicating what forecast date to plot, +#' in IS08601 format YYYY-MM-DD +#' @param ms_fig_dir A string indicating where to save the figure +#' @param n_forecast_days An integer indicating the number of days to show the +#' forecast for, default is `28` +#' @param n_calib_days An integer indicating the number of days to show the +#' calibration data for, default is `90` +#' @param max_n_site_labs_to_show An integer indicating the maximum number +#' of site-labs to show in the figure, default is `3` +#' @param site_lab_names_to_show a vector of character strings indicating +#' the site lab names to be displayed in the plot. If NULL, the first +#' `max_n_site_labs_to_show` or all are displayed. Default is `NULL`. +#' +#' @return A ggplot object containing a faceted horizontal plot of the +#' calibrated and forecasted wastewater concentrations for 3 or fewer +#' site-lab combinations for a single state +#' @export +make_fig2_ct_supp <- function(ww_quantiles, + loc_to_plot, + date_to_plot, + ms_fig_dir, + n_forecast_days = 28, + n_calib_days = 90, + max_n_site_labs_to_show = 3, + site_lab_names_to_show = NULL) { + if (!is.null(site_lab_names_to_show)) { + ww_quantiles <- ww_quantiles |> + dplyr::filter(site_lab_name %in% c(site_lab_names_to_show)) + } else { + ww_quantiles <- ww_quantiles |> + dplyr::filter(lab_site_index <= !!max_n_site_labs_to_show) + } + + ww <- ww_quantiles |> + dplyr::filter(location == !!loc_to_plot) |> + dplyr::filter(forecast_date == !!date_to_plot) |> + dplyr::filter( + date <= forecast_date + lubridate::days(!!n_forecast_days), + date >= forecast_date - lubridate::days(!!n_calib_days) + ) + + + + stopifnot( + "This function is meant for one location" = + length(unique(ww$location)) <= 1 + ) + + quantiles_wide <- ww |> + dplyr::mutate(log_conc = log(value)) |> + dplyr::filter(quantile %in% c(0.025, 0.25, 0.5, 0.75, 0.975)) |> + tidyr::pivot_wider( + id_cols = c( + location, site_lab_name, forecast_date, period, scenario, + date, eval_data, calib_data, below_LOD, flag_as_ww_outlier + ), + names_from = quantile, + values_from = log_conc + ) |> + dplyr::mutate( + model = "ww", + observation_status = + dplyr::case_when( + flag_as_ww_outlier == 1 ~ "outlier", + below_LOD == 1 ~ "below LOD", + TRUE ~ "standard" + ) + ) + + + + colors <- plot_components() + # Set ribbon and line color for model fit, in this case is always ww model + model_color <- as.character(colors$model_colors["ww"]) + + p <- ggplot(quantiles_wide) + + geom_point(aes(x = date, y = log(eval_data)), + fill = "white", size = 1, shape = 21, + show.legend = FALSE + ) + + geom_point( + aes( + x = date, y = log(calib_data), + color = observation_status, + shape = observation_status + ), + show.legend = FALSE + ) + + geom_line( + aes( + x = date, y = `0.5` + ), + color = model_color, + show.legend = FALSE + ) + + geom_ribbon( + aes( + x = date, ymin = `0.025`, ymax = `0.975`, + ), + fill = model_color, + alpha = 0.2, + show.legend = FALSE + ) + + geom_ribbon( + aes( + x = date, ymin = `0.25`, ymax = `0.75` + ), + fill = model_color, + alpha = 0.1, + show.legend = FALSE + ) + + geom_vline(aes(xintercept = lubridate::ymd(forecast_date)), + linetype = "dashed" + ) + + facet_wrap(~site_lab_name, + scales = "free_y" + ) + + xlab("") + + ylab("Log(genome copies per mL)") + + scale_x_date( + date_breaks = "2 weeks", + labels = scales::date_format("%Y-%m-%d") + ) + + get_plot_theme( + x_axis_dates = TRUE, + x_axis_text_size = 6 + ) + + scale_fill_manual(values = colors$observation_status_colors) + + scale_color_manual(values = colors$observation_status_colors) + + scale_shape_manual(values = colors$observation_status_shapes) + + ggsave(p, + height = 5, + width = 7, + filename = file.path( + ms_fig_dir, + glue::glue("sfig_ww_conc_ex_{loc_to_plot}.png") + ) + ) + return(p) +} #' Make figure 2 diff --git a/wweval/man/make_fig2_ct_supp.Rd b/wweval/man/make_fig2_ct_supp.Rd new file mode 100644 index 00000000..2026907a --- /dev/null +++ b/wweval/man/make_fig2_ct_supp.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig2.R +\name{make_fig2_ct_supp} +\alias{make_fig2_ct_supp} +\title{Make concentration fit and forecast figure for supplement} +\usage{ +make_fig2_ct_supp( + ww_quantiles, + loc_to_plot, + date_to_plot, + ms_fig_dir, + n_forecast_days = 28, + n_calib_days = 90, + max_n_site_labs_to_show = 3, + site_lab_names_to_show = NULL +) +} +\arguments{ +\item{ww_quantiles}{A tibble containing the calibrated wastewater +concentrations, the evaluation wastewater concentration data, and the +quantiles of the calibrated and forecasted wastewater concentrations} + +\item{loc_to_plot}{A character string indicating the state abbreviation +for which state to plot, can only be one state} + +\item{date_to_plot}{A character string indicating what forecast date to plot, +in IS08601 format YYYY-MM-DD} + +\item{ms_fig_dir}{A string indicating where to save the figure} + +\item{n_forecast_days}{An integer indicating the number of days to show the +forecast for, default is \code{28}} + +\item{n_calib_days}{An integer indicating the number of days to show the +calibration data for, default is \code{90}} + +\item{max_n_site_labs_to_show}{An integer indicating the maximum number +of site-labs to show in the figure, default is \code{3}} + +\item{site_lab_names_to_show}{a vector of character strings indicating +the site lab names to be displayed in the plot. If NULL, the first +\code{max_n_site_labs_to_show} or all are displayed. Default is \code{NULL}.} +} +\value{ +A ggplot object containing a faceted horizontal plot of the +calibrated and forecasted wastewater concentrations for 3 or fewer +site-lab combinations for a single state +} +\description{ +Make concentration fit and forecast figure for supplement +} From a813977e9fb8ceaa058bdf6b0158e5c6d11e9726 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Tue, 10 Dec 2024 20:07:06 +0000 Subject: [PATCH 090/110] reorg to find figures more easily --- _targets_eval_postprocessing.R | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 35f274af..417535e8 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -467,7 +467,7 @@ head_to_head_targets <- list( ) ) -# Manuscript figures------------------------------------------------ +# Manuscript analyses ------------------------------------------------ # Note that these are just the components of the figures, not the full # ggarranged, properly formatted figures, and currently require # specification for the figure components that are examples. @@ -576,7 +576,7 @@ manuscript_figures <- list( model_type = "ww" ) ), - ## Fig 2----------------------------------------------------- + ## Fig: Example of forecasts of 3 locs, 1 forecast date------------------- tar_target( name = fig2_hosp_t_1, command = make_fig2_hosp_t( @@ -630,7 +630,7 @@ manuscript_figures <- list( date_to_plot = forecast_date_to_plot ) ), - ## Fig 2 combined-------------------------------------------- + ### Fig combined-------------------------------------------- tar_target( name = fig2, command = make_fig2( @@ -644,7 +644,7 @@ manuscript_figures <- list( ) ), - ## Fig 3------------------------------------------------- + ## Fig: Example 3 locs, all forecast dates------------------------------ tar_target( name = summary_table_crps, command = get_summary_table_fig3( @@ -915,7 +915,7 @@ manuscript_figures <- list( ) ), - ### Fig3 combined--------------------------------------- + ### Fig combined--------------------------------------- tar_target( name = fig3, command = make_fig3( @@ -946,7 +946,7 @@ manuscript_figures <- list( - ## Fig 4------------------------------------------------ + ## Fig: Retrospective relative performance--------------------------------- tar_target( name = fig4_results_tables, command = make_fig4_results_table( @@ -966,7 +966,6 @@ manuscript_figures <- list( locs = c("DC", "OH", "NH", "CO", "IL", "IN") ) ), - ## Fig 4: retro relative-------------------------------------------------- tar_target(fig4_rel_crps_heatmap, command = get_plot_rel_crps_heatmap( scores = scores_filtered, @@ -1040,7 +1039,7 @@ manuscript_figures <- list( write_files = TRUE ) ), - ### Fig 4 retro relative combined--------------------------------------------- + ### Fig combined--------------------------------------------- tar_target( name = fig4, command = make_fig4( @@ -1515,8 +1514,7 @@ hub_targets <- list( ) ) ) -## Hub comparison plots ------------------------------------------------------ -## Fig 5------------------------------------------------------------------- +## Hub comparison ------------------------------------------------------ hub_comparison_plots <- list( tar_target( name = fig5_summary_table, @@ -1568,7 +1566,7 @@ hub_comparison_plots <- list( "cfa-hosponlyrenewal(retro)" ) ), - ## Real-time Hub comparison top row------------------------------------------ + ## Fig: Real-time Hub comparison ------------------------------------------ # This will be the real-time density of relative CRPS compared # to covidhub baseline (will need to get the summary stats for this too) tar_target( @@ -1597,7 +1595,7 @@ hub_comparison_plots <- list( time_period = "Feb-Mar 2024" ) ), - ## Real-time relative----------------------------------------- + ## Fig:Real-time relative----------------------------------------- tar_target( name = wis_scores_rt_summarized, command = real_time_wis_both_models |> @@ -1672,7 +1670,7 @@ hub_comparison_plots <- list( write_files = TRUE ) ), - ### Fig 4 real-time relative combined--------------------------------------------- + ### Fig combined--------------------------------------------- tar_target( name = fig4_rt, command = make_fig4( @@ -1688,7 +1686,7 @@ hub_comparison_plots <- list( ), - ## Retro Hub comparison top row------------------------------------------- + ## Fig: Retrospective Hub comparison------------------------------------------- tar_target( name = fig5_density_all_time, command = make_fig5_density( @@ -1715,7 +1713,6 @@ hub_comparison_plots <- list( real_time_period = "Feb 2024-Mar 2024", ) ), - # Lower rows Hub comparison fig------------------------------------ tar_target( name = fig5_heatmap_rel_wis_all_time, command = make_fig5_heatmap_relative_wis( @@ -1778,7 +1775,7 @@ hub_comparison_plots <- list( time_period = "Oct 2023-Mar 2024" ) ), - ### Fig 5 combined--------------------------------------------------- + ### Fig Real-time and retro Hub combined--------------------------------------------------- tar_target( name = fig5, command = make_fig5( From b65d96d004dc00896f9e2f35e1b6f2655b1e6d19 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:53:05 -0500 Subject: [PATCH 091/110] Update wweval/R/combine_and_summarize_ww_data.R Co-authored-by: Dylan H. Morris --- wweval/R/combine_and_summarize_ww_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/combine_and_summarize_ww_data.R b/wweval/R/combine_and_summarize_ww_data.R index 7c7ef2b0..3390ad15 100644 --- a/wweval/R/combine_and_summarize_ww_data.R +++ b/wweval/R/combine_and_summarize_ww_data.R @@ -246,7 +246,7 @@ load_data_and_summarize <- function(fp_hosp, fp_ww, #' @param table_of_loc_dates_w_ww table containing wastewater metadata #' for every location-forecast date with wastewater #' @param include_manual_exclusions boolean indicating whether or not the -#' ww metadata should include manual exclusiosn, default is FALSE bc isn't +#' ww metadata should include manual exclusions, default is FALSE bc isn't #' used in main retro head to head analysis. #' #' @return a tibble with a number of additional columns indicating whether From 077f407ba07f9b622f3d618a5e755adac6a13f45 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:59:05 -0500 Subject: [PATCH 092/110] Update wweval/R/score_real_time_outputs.R Co-authored-by: Dylan H. Morris --- wweval/R/score_real_time_outputs.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index f7c534bc..a57ff7f2 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -74,7 +74,7 @@ score_real_time_outputs <- function(score_type, date, location, value, - !!sym(col_name) + !!col_name ) |> dplyr::mutate( model = model_types[m], From be3c6472dce8433c6a2c21cfc5144d937fc5767f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:59:28 -0500 Subject: [PATCH 093/110] Update wweval/R/score_real_time_outputs.R Co-authored-by: Dylan H. Morris --- wweval/R/score_real_time_outputs.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index a57ff7f2..11eed233 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -110,7 +110,7 @@ score_real_time_outputs <- function(score_type, date, location, value, - !!sym(col_name) + !!col_name ) |> dplyr::mutate( model = model_types[m], From ba5d4b5790d39420652a4107379f598618cba577 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:00:27 -0500 Subject: [PATCH 094/110] Update wweval/R/score_real_time_outputs.R Co-authored-by: Dylan H. Morris --- wweval/R/score_real_time_outputs.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/score_real_time_outputs.R b/wweval/R/score_real_time_outputs.R index 11eed233..12dfc142 100644 --- a/wweval/R/score_real_time_outputs.R +++ b/wweval/R/score_real_time_outputs.R @@ -244,7 +244,7 @@ format_scores_for_comparison <- function(real_time_scores, return(formatted_scores) } -#' Combine thehosp only real-time scores and cfa real +#' Combine the hosp only real-time scores and cfa real- #' time scores from github #' #' @param cfa_real_time_scores Hub formatted scores for From 7fcf6ecad202d2794d0ac871ddae3d2814e5c16c Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:04:03 -0500 Subject: [PATCH 095/110] Update wweval/R/supplement_analyses_and_figs.R Co-authored-by: Dylan H. Morris --- wweval/R/supplement_analyses_and_figs.R | 1 - 1 file changed, 1 deletion(-) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 752459a0..a0612aef 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -1120,7 +1120,6 @@ get_rel_wis_real_time <- function(all_scores) { scoringutils::summarise_scores( by = c("forecast_date", "model", "date", "location") ) |> - tibble::tibble() |> dplyr::select(location, forecast_date, date, model, interval_score) |> tidyr::pivot_wider( names_from = model, From a63ba571cab28810554ac2666f1623d37c0f7f82 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:06:52 -0500 Subject: [PATCH 096/110] Update wweval/R/ms_fig4.R Co-authored-by: Dylan H. Morris --- wweval/R/ms_fig4.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 9024dac2..a890356b 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -224,7 +224,7 @@ make_fig4_admissions_overall <- function(eval_hosp_data, return(p) } -#' Get the mean relative crps for a location +#' Get the relative mean crps for a location #' #' @param scores tibble of scores by day forecast day model #' @param locs loc to get mean relative score for From 3ab20200cc4534fc5802d4a75dfc43778137b8fa Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:48:55 -0500 Subject: [PATCH 097/110] Update wweval/R/ms_fig4.R Co-authored-by: Dylan H. Morris --- wweval/R/ms_fig4.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index a890356b..bc192138 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -227,7 +227,7 @@ make_fig4_admissions_overall <- function(eval_hosp_data, #' Get the relative mean crps for a location #' #' @param scores tibble of scores by day forecast day model -#' @param locs loc to get mean relative score for +#' @param locs loc to get relative mean score for #' #' @return table of mean relative score for each location get_loc_rel_crps <- function(scores, locs) { From 7331a91cab88d94a9210d56bb4fb5c1f7f5e3b0a Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:49:47 -0500 Subject: [PATCH 098/110] Update wweval/R/ms_fig4.R Co-authored-by: Dylan H. Morris --- wweval/R/ms_fig4.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index bc192138..7cadf88f 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -229,7 +229,7 @@ make_fig4_admissions_overall <- function(eval_hosp_data, #' @param scores tibble of scores by day forecast day model #' @param locs loc to get relative mean score for #' -#' @return table of mean relative score for each location +#' @return table of relative mean score for each location get_loc_rel_crps <- function(scores, locs) { relative_crps <- scores |> dplyr::filter(location %in% locs) |> From 6d530ba467dc1de1ee595f2f5c6487ef237de48f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:50:50 -0500 Subject: [PATCH 099/110] Update wweval/R/ms_fig4.R Co-authored-by: Dylan H. Morris From cffa8fee658e88df006f9ae95f305a6d2a64c580 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:51:12 -0500 Subject: [PATCH 100/110] Update wweval/R/order_elements.R Co-authored-by: Dylan H. Morris --- wweval/R/order_elements.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/order_elements.R b/wweval/R/order_elements.R index 4bf3667e..f300cb9e 100644 --- a/wweval/R/order_elements.R +++ b/wweval/R/order_elements.R @@ -168,7 +168,7 @@ order_phases <- function(df) { order_locations <- function(df, score_name) { loc_order <- df |> dplyr::group_by(location) |> - dplyr::summarize(geom_mean_crps = exp(mean(log(!!sym(score_name))))) |> + dplyr::summarize(geom_mean_rel_score = exp(mean(log(.data[[score_name]])))) |> dplyr::arrange(geom_mean_crps, "desc") |> dplyr::pull(location) From 42ccfa3a7d3b32efc220e40c03ce80559391ce40 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson <94390107+kaitejohnson@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:51:20 -0500 Subject: [PATCH 101/110] Update wweval/R/order_elements.R Co-authored-by: Dylan H. Morris --- wweval/R/order_elements.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wweval/R/order_elements.R b/wweval/R/order_elements.R index f300cb9e..94a93477 100644 --- a/wweval/R/order_elements.R +++ b/wweval/R/order_elements.R @@ -169,7 +169,7 @@ order_locations <- function(df, score_name) { loc_order <- df |> dplyr::group_by(location) |> dplyr::summarize(geom_mean_rel_score = exp(mean(log(.data[[score_name]])))) |> - dplyr::arrange(geom_mean_crps, "desc") |> + dplyr::arrange(geom_mean_rel_score, "desc") |> dplyr::pull(location) if (!"location" %in% colnames(df)) { From ecd569702595f95aecc186bbcb64cd34537f1c0f Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 15:05:42 +0000 Subject: [PATCH 102/110] fix heatmap to relative mean, other tweaks to remove ref to mean rel --- _targets_eval_postprocessing.R | 24 +---------- wweval/R/ms_fig3.R | 21 +--------- wweval/R/ms_fig4.R | 55 ++++++++++++------------- wweval/R/ms_fig5.R | 2 +- wweval/R/supplement_analyses_and_figs.R | 6 +-- wweval/man/combine_hub_and_local_wis.Rd | 4 +- wweval/man/get_add_ww_metadata.Rd | 2 +- wweval/man/get_loc_rel_crps.Rd | 4 +- wweval/man/make_fig4_heatmap_rel_wis.Rd | 6 +-- 9 files changed, 39 insertions(+), 85 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 417535e8..243a7ce9 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1276,16 +1276,6 @@ real_time_rel_targets <- list( dplyr::left_join(table_of_loc_dates_w_ww) |> dplyr::filter(ww_sufficient) ), - tar_target( - name = rel_real_time_wis, - command = get_rel_wis_real_time(real_time_wis_both_models) - ), - tar_target( - name = overall_real_time_rel_wis, - command = rel_real_time_wis |> - dplyr::ungroup() |> - dplyr::summarise(mean_rel_wis = mean(rel_wis, na.rm = TRUE)) - ), tar_target( name = rel_mean_wis_real_time, command = real_time_wis_both_models |> @@ -1415,18 +1405,6 @@ hub_targets <- list( scores_list_hub_submission_oct_mar$log_scale_scores ) ), - tar_target( - name = rel_all_time_wis, - command = get_rel_wis_all_time( - all_scores = scores_list_retro_hub_submissions$log_scale_scores - ) - ), - tar_target( - name = overall_all_time_rel_wis, - command = rel_all_time_wis |> - dplyr::ungroup() |> - dplyr::summarise(mean_rel_wis = mean(rel_wis, na.rm = TRUE)) - ), # Rename the model as retrospective tar_target( name = combine_scores_oct_mar_full, @@ -1605,7 +1583,7 @@ hub_comparison_plots <- list( tar_target( name = fig4_rel_wis_heatmap, command = make_fig4_heatmap_rel_wis( - rel_scores = rel_real_time_wis, + wis_scores = wis_scores_rt_summarized, time_period = "Feb-Mar 2024", analysis_type = "Real-time" ) diff --git a/wweval/R/ms_fig3.R b/wweval/R/ms_fig3.R index e4b8e056..3ad953a1 100644 --- a/wweval/R/ms_fig3.R +++ b/wweval/R/ms_fig3.R @@ -49,29 +49,10 @@ get_summary_table_fig3 <- function(scores, width = 7, height = 4 ) - raw_rel_scores <- scores |> - dplyr::filter( - location %in% locs_to_plot - ) |> - tidyr::pivot_wider( - id_cols = c("location", "date", "forecast_date"), - names_from = "model", - names_prefix = "crps_", - values_from = crps - ) |> - dplyr::mutate(rel_crps = crps_ww / crps_hosp) |> - dplyr::group_by(location) |> - dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) - - scores_summary <- raw_rel_scores |> dplyr::left_join(scores_locs, - by = "location" - ) - - - return(scores_summary) + return(scores_locs) } #' Get an individual forecast score summary for a particular diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index a890356b..7625d1fb 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -16,14 +16,6 @@ make_fig4_results_table <- function(scores) { avg_ae = mean(ae_median) ) - # Above was averaged across models, get avg of rel_crps - overall_all_time_rel_crps <- scores |> - compute_relative_crps(id_cols = c( - "location", - "forecast_date", "date", "horizon" - )) |> - dplyr::summarize(mean_rel_crps = mean(rel_crps, na.rm = TRUE)) - # By period (nowcast vs forecast) scores_by_period <- scores |> @@ -36,8 +28,7 @@ make_fig4_results_table <- function(scores) { scores_tables <- list( scores_overall = scores_overall, - scores_by_period = scores_by_period, - overall_all_time_rel_crps = overall_all_time_rel_crps + scores_by_period = scores_by_period ) return(scores_tables) @@ -255,13 +246,15 @@ get_loc_rel_crps <- function(scores, locs) { get_plot_rel_crps_heatmap <- function(scores, fig_file_dir) { scores_summary <- scores |> - compute_relative_crps(id_cols = c( - "location", - "forecast_date", "date" - )) |> - dplyr::group_by(location, forecast_date) |> - dplyr::summarize( - mean_rel_crps = mean(rel_crps) + dplyr::group_by(forecast_date, location, model) |> + dplyr::summarize(mean_crps = mean(crps)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_crps, + id_cols = c("forecast_date", "location") + ) |> + dplyr::mutate( + mean_rel_crps = ww / hosp ) @@ -312,7 +305,6 @@ get_plot_rel_crps_distrib <- function(scores, ) ) |> dplyr::mutate( - pct_change_crps = (ww - hosp) / hosp, rel_crps = ww / hosp ) @@ -329,7 +321,7 @@ get_plot_rel_crps_distrib <- function(scores, geom_hline(aes(yintercept = 1), linetype = "dashed") + get_plot_theme() + ylab("Relative CRPS") + - xlab("Density") + + xlab("Count") + scale_y_continuous(trans = "log10") + coord_cartesian(ylim = c(1 / 3.5, 3.5)) @@ -813,7 +805,6 @@ get_plot_rel_wis_distrib <- function(wis_scores) { ) ) |> dplyr::mutate( - pct_change_crps = (ww - hosp) / hosp, rel_wis = ww / hosp ) p_log <- ggplot(relative_wis_by_forecast) + @@ -829,7 +820,7 @@ get_plot_rel_wis_distrib <- function(wis_scores) { geom_hline(aes(yintercept = 1), linetype = "dashed") + get_plot_theme() + ylab("Relative WIS") + - xlab("Density") + + xlab("Count") + scale_y_continuous(trans = "log10") + coord_cartesian(ylim = c(1 / 3.5, 3.5)) @@ -838,8 +829,8 @@ get_plot_rel_wis_distrib <- function(wis_scores) { #' Get a plot of the relative wis from the real-time models #' -#' @param rel_scores tibble containing the relative wis for each forecast -#' date and location and horizon day +#' @param wis_scores tibble containing the wis for each forecast +#' date and location and horizon day and model #' @param time_period string indicating dates of analysis, either "Feb-Mar", #' or "Oct-Mar" #' @param analysis_type string indicating whether analysis is Real-time @@ -847,15 +838,21 @@ get_plot_rel_wis_distrib <- function(wis_scores) { #' @param fig_file_dir string indicating the directory to save the figure #' #' @return ggplot object of a heatmap of the realtive wis -make_fig4_heatmap_rel_wis <- function(rel_scores, +make_fig4_heatmap_rel_wis <- function(wis_scores, time_period, analysis_type, fig_file_dir) { - avg_rel_scores <- rel_scores |> - dplyr::group_by(forecast_date, location) |> - dplyr::summarise(mean_rel_wis = mean(rel_wis)) |> - dplyr::filter(!is.na(mean_rel_wis)) - + avg_rel_scores <- wis_scores |> + dplyr::group_by(forecast_date, location, model) |> + dplyr::summarize(mean_wis = mean(interval_score)) |> + tidyr::pivot_wider( + names_from = model, + values_from = mean_wis, + id_cols = c("forecast_date", "location") + ) |> + dplyr::mutate( + mean_rel_wis = ww / hosp + ) p <- ggplot(avg_rel_scores) + geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + scale_fill_gradient2( diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index bfbc604d..6cc78789 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -314,7 +314,7 @@ make_fig5_density <- function(all_scores, p <- ggplot(scores_final) + tidybayes::stat_histinterval( aes( - x = model, y = relative_wis + 1e-8, + x = model, y = relative_wis, fill = model ), point_interval = "mean_qi", diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index a0612aef..2e268d32 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -665,8 +665,7 @@ get_stats_improved_forecasts <- function(scores, "location", "forecast_date" )) |> dplyr::mutate( - pct_change_crps = (ww - hosp) / hosp, - rel_crps = ww / hosp + pct_change_crps = (ww - hosp) / hosp ) relative_crps_raw <- scores |> @@ -674,8 +673,7 @@ get_stats_improved_forecasts <- function(scores, "location", "forecast_date", "date" )) |> dplyr::mutate( - pct_change_crps = (ww - hosp) / hosp, - rel_crps = ww / hosp + pct_change_crps = (ww - hosp) / hosp ) ggplot(relative_crps_by_forecast) + diff --git a/wweval/man/combine_hub_and_local_wis.Rd b/wweval/man/combine_hub_and_local_wis.Rd index 2d598aa5..e11f6741 100644 --- a/wweval/man/combine_hub_and_local_wis.Rd +++ b/wweval/man/combine_hub_and_local_wis.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/score_real_time_outputs.R \name{combine_hub_and_local_wis} \alias{combine_hub_and_local_wis} -\title{Combine thehosp only real-time scores and cfa real +\title{Combine the hosp only real-time scores and cfa real- time scores from github} \usage{ combine_hub_and_local_wis(cfa_real_time_scores, real_time_wis_hosp_only) @@ -19,6 +19,6 @@ a df formatted the same way as the real_time_wis_hosp_only scores, but for both models } \description{ -Combine thehosp only real-time scores and cfa real +Combine the hosp only real-time scores and cfa real- time scores from github } diff --git a/wweval/man/get_add_ww_metadata.Rd b/wweval/man/get_add_ww_metadata.Rd index 13584875..95b1d793 100644 --- a/wweval/man/get_add_ww_metadata.Rd +++ b/wweval/man/get_add_ww_metadata.Rd @@ -28,7 +28,7 @@ date location combination} for every location-forecast date with wastewater} \item{include_manual_exclusions}{boolean indicating whether or not the -ww metadata should include manual exclusiosn, default is FALSE bc isn't +ww metadata should include manual exclusions, default is FALSE bc isn't used in main retro head to head analysis.} } \value{ diff --git a/wweval/man/get_loc_rel_crps.Rd b/wweval/man/get_loc_rel_crps.Rd index 4fa19427..e7fc09b0 100644 --- a/wweval/man/get_loc_rel_crps.Rd +++ b/wweval/man/get_loc_rel_crps.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ms_fig4.R \name{get_loc_rel_crps} \alias{get_loc_rel_crps} -\title{Get the mean relative crps for a location} +\title{Get the relative mean crps for a location} \usage{ get_loc_rel_crps(scores, locs) } @@ -15,5 +15,5 @@ get_loc_rel_crps(scores, locs) table of mean relative score for each location } \description{ -Get the mean relative crps for a location +Get the relative mean crps for a location } diff --git a/wweval/man/make_fig4_heatmap_rel_wis.Rd b/wweval/man/make_fig4_heatmap_rel_wis.Rd index 8c0bf3d6..4424528b 100644 --- a/wweval/man/make_fig4_heatmap_rel_wis.Rd +++ b/wweval/man/make_fig4_heatmap_rel_wis.Rd @@ -4,11 +4,11 @@ \alias{make_fig4_heatmap_rel_wis} \title{Get a plot of the relative wis from the real-time models} \usage{ -make_fig4_heatmap_rel_wis(rel_scores, time_period, analysis_type, fig_file_dir) +make_fig4_heatmap_rel_wis(wis_scores, time_period, analysis_type, fig_file_dir) } \arguments{ -\item{rel_scores}{tibble containing the relative wis for each forecast -date and location and horizon day} +\item{wis_scores}{tibble containing the wis for each forecast +date and location and horizon day and model} \item{time_period}{string indicating dates of analysis, either "Feb-Mar", or "Oct-Mar"} From a8e17176b11c7c0e70924f265128b9a2d1702301 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 15:11:49 +0000 Subject: [PATCH 103/110] update docs --- wweval/man/get_loc_rel_crps.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wweval/man/get_loc_rel_crps.Rd b/wweval/man/get_loc_rel_crps.Rd index e7fc09b0..869414e5 100644 --- a/wweval/man/get_loc_rel_crps.Rd +++ b/wweval/man/get_loc_rel_crps.Rd @@ -9,10 +9,10 @@ get_loc_rel_crps(scores, locs) \arguments{ \item{scores}{tibble of scores by day forecast day model} -\item{locs}{loc to get mean relative score for} +\item{locs}{loc to get relative mean score for} } \value{ -table of mean relative score for each location +table of relative mean score for each location } \description{ Get the relative mean crps for a location From 8897da8354554411180876ed0c4645407523e8d5 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 15:27:08 +0000 Subject: [PATCH 104/110] add bias summary to real time relative --- _targets_eval_postprocessing.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 243a7ce9..65d98d0c 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1580,6 +1580,13 @@ hub_comparison_plots <- list( data.table::as.data.table() |> scoringutils::summarise_scores() ), + tar_target( + name = bias_summary, + command = wis_scores_rt_summarized |> + dplyr::filter(scale == "log") |> + dplyr::group_by(model) |> + dplyr::summarize(avg_bias = mean(bias)) + ), tar_target( name = fig4_rel_wis_heatmap, command = make_fig4_heatmap_rel_wis( From 10213fd539fba3ea14d85f8099c4295a9ffa9874 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 16:47:17 +0000 Subject: [PATCH 105/110] change way of identifying better and worse forecasts --- wweval/R/supplement_analyses_and_figs.R | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 2e268d32..7c589803 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -689,36 +689,30 @@ get_stats_improved_forecasts <- function(scores, forecasts_way_worse <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps > 3) + dplyr::filter(rel_crps > 4) n_forecasts_3x_worse <- forecasts_way_worse |> nrow() forecasts_way_better <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps < -3) + dplyr::filter(rel_crps < 1 / 4) n_forecasts_3x_better <- forecasts_way_better |> nrow() n_forecasts_better <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps < 0) |> + dplyr::filter(rel_crps < 1) |> nrow() n_forecasts_worse <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps > 0) |> + dplyr::filter(rel_crps > 1) |> nrow() n_forecasts_better_thres <- relative_crps_by_forecast |> dplyr::filter( - pct_change_crps < 0, - abs(pct_change_crps) > threshold + rel_crps < 1 / (1 + threshold) ) |> nrow() - n_forecasts_worse <- relative_crps_by_forecast |> - dplyr::filter(pct_change_crps > 0) |> - nrow() - n_forecasts_worse_thres <- relative_crps_by_forecast |> dplyr::filter( - pct_change_crps > 0, - abs(pct_change_crps) > threshold + rel_crps > 1 + threshold ) |> nrow() From f1b323d91a522f27a914940943b827b12c37028b Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 17:01:40 +0000 Subject: [PATCH 106/110] get a summary table of standard ranks --- _targets_eval_postprocessing.R | 12 +++++++++++ wweval/NAMESPACE | 1 + wweval/R/ms_fig5.R | 37 ++++++++++++++++++++++++++++++++ wweval/man/summarize_std_rank.Rd | 18 ++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 wweval/man/summarize_std_rank.Rd diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index 65d98d0c..b3a0f5e9 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1752,6 +1752,14 @@ hub_comparison_plots <- list( time_period = "Feb-Mar 2024" ) ), + tar_target( + name = std_rank_summary_table_rt, + command = summarize_std_rank(summarized_scores_feb_mar |> + dplyr::filter(!model %in% c( + "cfa-wwrenewal(retro)", + "cfa-hosponlyrenewal(retro)" + ))) + ), tar_target( name = fig5_std_rank_all_time, command = make_fig5_density_rank( @@ -1760,6 +1768,10 @@ hub_comparison_plots <- list( time_period = "Oct 2023-Mar 2024" ) ), + tar_target( + name = std_rank_summary_table_at, + command = summarize_std_rank(summarized_scores_oct_mar) + ), ### Fig Real-time and retro Hub combined--------------------------------------------------- tar_target( name = fig5, diff --git a/wweval/NAMESPACE b/wweval/NAMESPACE index f6aba5d5..3bc7534a 100644 --- a/wweval/NAMESPACE +++ b/wweval/NAMESPACE @@ -114,6 +114,7 @@ export(score_hub_submissions) export(score_real_time_outputs) export(setup_secrets) export(soql_is_in) +export(summarize_std_rank) export(trajectories_to_quantiles) import(ggplot2) importFrom(arrow,read_ipc_stream) diff --git a/wweval/R/ms_fig5.R b/wweval/R/ms_fig5.R index 6cc78789..e2adaf60 100644 --- a/wweval/R/ms_fig5.R +++ b/wweval/R/ms_fig5.R @@ -537,6 +537,43 @@ make_fig5_density_rank <- function(scores, return(p) } +#' Summarize standardize rank with medians and 25th,75th percentiles +#' +#' @param scores A tibble of the individual day and location's scores +#' +#' @return A table with median, 25th, and 75th percentiles of standard +#' ranking for each model +#' @export +summarize_std_rank <- function(scores) { + summarized_scores <- scores |> + data.table::as.data.table() |> + scoringutils::summarise_scores( + by = c("model", "location", "forecast_date") + ) + + scores_ranked <- summarized_scores |> + tibble() |> + dplyr::group_by(forecast_date, location) |> + dplyr::mutate( + rank = dplyr::dense_rank(dplyr::desc(interval_score)), + std_rank = rank / max(rank) + ) |> + dplyr::mutate(model = stats::reorder(model, rank, + FUN = function(x) { + quantile(x, probs = 0.25, na.rm = TRUE) + } + )) + + summarize_std_rank <- scores_ranked |> + dplyr::group_by(model) |> + dplyr::summarise( + median_rank = quantile(std_rank, 0.5), + quartile_25th = quantile(std_rank, 0.25), + quartile_75th = quantile(std_rank, 0.75) + ) + return(summarize_std_rank) +} + #' Make Fig 5 diff --git a/wweval/man/summarize_std_rank.Rd b/wweval/man/summarize_std_rank.Rd new file mode 100644 index 00000000..b1842610 --- /dev/null +++ b/wweval/man/summarize_std_rank.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ms_fig5.R +\name{summarize_std_rank} +\alias{summarize_std_rank} +\title{Summarize standardize rank with medians and 25th,75th percentiles} +\usage{ +summarize_std_rank(scores) +} +\arguments{ +\item{scores}{A tibble of the individual day and location's scores} +} +\value{ +A table with median, 25th, and 75th percentiles of standard +ranking for each model +} +\description{ +Summarize standardize rank with medians and 25th,75th percentiles +} From 767c208c70a137d1d5630d45a48f8b3a3e3dd7e7 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 16:29:32 -0500 Subject: [PATCH 107/110] change stats on improved forecasts to fold change --- _targets_eval_postprocessing.R | 2 +- wweval/R/supplement_analyses_and_figs.R | 8 ++++---- wweval/man/get_stats_improved_forecasts.Rd | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/_targets_eval_postprocessing.R b/_targets_eval_postprocessing.R index b3a0f5e9..636c2d52 100644 --- a/_targets_eval_postprocessing.R +++ b/_targets_eval_postprocessing.R @@ -1900,7 +1900,7 @@ supp_targets <- list( name = comp_stats, command = get_stats_improved_forecasts( scores = scores_filtered, - threshold = 0.1 + threshold = 1.1 ) ), tar_target( diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 7c589803..336c9cfe 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -631,8 +631,8 @@ get_avg_scores_model_horizon <- function(scores, #' Get stats on number of improved forecasts #' #' @param scores tibble of scores for every location, forecast date, and horizon -#' @param threshold numeric between 0 and 1 indicating the threshold to call -#' something better or worse +#' @param threshold numeric indicating fold change for considering a forecast +#' improved or worse relative to baseline, e.g. 1.1 #' #' @return table of the number of states with improvements, number of overall #' forecasts with improvements, number that got worse, etc. @@ -706,13 +706,13 @@ get_stats_improved_forecasts <- function(scores, n_forecasts_better_thres <- relative_crps_by_forecast |> dplyr::filter( - rel_crps < 1 / (1 + threshold) + rel_crps < 1 / threshold ) |> nrow() n_forecasts_worse_thres <- relative_crps_by_forecast |> dplyr::filter( - rel_crps > 1 + threshold + rel_crps > threshold ) |> nrow() diff --git a/wweval/man/get_stats_improved_forecasts.Rd b/wweval/man/get_stats_improved_forecasts.Rd index bea983f7..53752abd 100644 --- a/wweval/man/get_stats_improved_forecasts.Rd +++ b/wweval/man/get_stats_improved_forecasts.Rd @@ -9,8 +9,8 @@ get_stats_improved_forecasts(scores, threshold) \arguments{ \item{scores}{tibble of scores for every location, forecast date, and horizon} -\item{threshold}{numeric between 0 and 1 indicating the threshold to call -something better or worse} +\item{threshold}{numeric indicating fold change for considering a forecast +improved or worse relative to baseline, e.g. 1.1} } \value{ table of the number of states with improvements, number of overall From ff68f0ea260fce63f3dfe7ced29a4e8e3743a4e2 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 16:31:55 -0500 Subject: [PATCH 108/110] reflect fold change of 4x not 3 --- wweval/R/supplement_analyses_and_figs.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wweval/R/supplement_analyses_and_figs.R b/wweval/R/supplement_analyses_and_figs.R index 336c9cfe..c29ec400 100644 --- a/wweval/R/supplement_analyses_and_figs.R +++ b/wweval/R/supplement_analyses_and_figs.R @@ -690,11 +690,11 @@ get_stats_improved_forecasts <- function(scores, forecasts_way_worse <- relative_crps_by_forecast |> dplyr::filter(rel_crps > 4) - n_forecasts_3x_worse <- forecasts_way_worse |> nrow() + n_forecasts_4x_worse <- forecasts_way_worse |> nrow() forecasts_way_better <- relative_crps_by_forecast |> dplyr::filter(rel_crps < 1 / 4) - n_forecasts_3x_better <- forecasts_way_better |> nrow() + n_forecasts_4x_better <- forecasts_way_better |> nrow() n_forecasts_better <- relative_crps_by_forecast |> dplyr::filter(rel_crps < 1) |> @@ -726,8 +726,8 @@ get_stats_improved_forecasts <- function(scores, n_forecasts_worse, n_forecasts_better_thres, n_forecasts_worse_thres, - n_forecasts_3x_worse, - n_forecasts_3x_better + n_forecasts_4x_worse, + n_forecasts_4x_better ) return(stats) From 814b8dcd7ed6f833603fcbf8316bd71cff525532 Mon Sep 17 00:00:00 2001 From: Kaitlyn Johnson Date: Thu, 12 Dec 2024 17:05:08 -0500 Subject: [PATCH 109/110] replace mean_rel w rel_mean for clarity --- wweval/R/ms_fig4.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 92e83188..45819470 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -254,12 +254,12 @@ get_plot_rel_crps_heatmap <- function(scores, id_cols = c("forecast_date", "location") ) |> dplyr::mutate( - mean_rel_crps = ww / hosp + rel_mean_crps = ww / hosp ) p <- ggplot(scores_summary) + - geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_crps)) + + geom_tile(aes(x = forecast_date, y = location, fill = rel_mean_crps)) + scale_fill_gradient2( high = "red", mid = "white", low = "blue", transform = "log2", @@ -268,7 +268,7 @@ get_plot_rel_crps_heatmap <- function(scores, ) + geom_text(aes( x = forecast_date, y = location, - label = round(mean_rel_crps, 2) + label = round(rel_mean_crps, 2) ), size = 1.5) + get_plot_theme( x_axis_dates = TRUE, From d201133a31e1c0fdad0a90ba2b51123b84cbaf85 Mon Sep 17 00:00:00 2001 From: "Dylan H. Morris" Date: Thu, 12 Dec 2024 18:16:29 -0500 Subject: [PATCH 110/110] mean_rel wis to real_mean --- wweval/R/ms_fig4.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wweval/R/ms_fig4.R b/wweval/R/ms_fig4.R index 45819470..d6d7bd18 100644 --- a/wweval/R/ms_fig4.R +++ b/wweval/R/ms_fig4.R @@ -851,10 +851,10 @@ make_fig4_heatmap_rel_wis <- function(wis_scores, id_cols = c("forecast_date", "location") ) |> dplyr::mutate( - mean_rel_wis = ww / hosp + rel_mean_wis = ww / hosp ) p <- ggplot(avg_rel_scores) + - geom_tile(aes(x = forecast_date, y = location, fill = mean_rel_wis)) + + geom_tile(aes(x = forecast_date, y = location, fill = rel_mean_wis)) + scale_fill_gradient2( high = "red", mid = "white", low = "blue", transform = "log2", @@ -863,7 +863,7 @@ make_fig4_heatmap_rel_wis <- function(wis_scores, ) + geom_text(aes( x = forecast_date, y = location, - label = round(mean_rel_wis, 2) + label = round(rel_mean_wis, 2) ), size = 1.5) + get_plot_theme( x_axis_dates = TRUE,