From 279abf0ab184f3558623b812fbf973fe67dfa608 Mon Sep 17 00:00:00 2001 From: Schiano-NOAA <125507018+Schiano-NOAA@users.noreply.github.com> Date: Tue, 20 Oct 2026 20:55:54 +0000 Subject: [PATCH] style and docs: run devtools::document() and style with styler or air --- NAMESPACE | 1 + R/convert_output.R | 7 +- R/extract_sis_data.R | 350 +++++++++--------- R/plot_spr.R | 33 +- R/plot_stock_recruitment.R | 2 +- R/table_total_catch.R | 8 +- R/utils_plot.R | 47 ++- man/calculate_reference_point.Rd | 2 +- man/plot_spawning_potential_ratio.Rd | 128 +++++++ tests/testthat/helper-test_functions.R | 42 ++- tests/testthat/test-convert_output.R | 2 +- tests/testthat/test-extract_sis_data.R | 20 +- tests/testthat/test-plot_natural_mortality.R | 2 +- .../test-plot_spawning_potential_ratio.R | 8 +- vignettes/extract-sis-data.Rmd | 2 +- 15 files changed, 403 insertions(+), 251 deletions(-) create mode 100644 man/plot_spawning_potential_ratio.Rd diff --git a/NAMESPACE b/NAMESPACE index 0de5d9df..ab256ecd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,6 +23,7 @@ export(plot_recruitment) export(plot_recruitment_deviations) export(plot_selectivity) export(plot_spawning_biomass) +export(plot_spawning_potential_ratio) export(plot_stock_recruitment) export(plot_timeseries) export(process_data) diff --git a/R/convert_output.R b/R/convert_output.R index b0b8b1f1..863a24de 100644 --- a/R/convert_output.R +++ b/R/convert_output.R @@ -48,18 +48,17 @@ convert_output <- function( fleet_names = NULL, save_dir = NULL ) { - if (is.character(file) && grepl("Report.sso", file)) { lifecycle::deprecate_warn( - when = "2.8.0", - what = I("convert_output(file = 'Report.sso')"), + when = "2.8.0", + what = I("convert_output(file = 'Report.sso')"), details = c( i = "Please use the returned object from `r4ss::ss_output()`", i = "File will be compatible until Oct. 1, 2027" ) ) } - + # check if entered save_dir exists so doesn't waste user time finding this out at the end if (!is.null(save_dir)) { if (!grepl(".rda", save_dir)) { diff --git a/R/extract_sis_data.R b/R/extract_sis_data.R index 9176af07..e5f062a2 100644 --- a/R/extract_sis_data.R +++ b/R/extract_sis_data.R @@ -3,26 +3,26 @@ #' Semi-automate the extraction of key quantities from model results and time #' series data from exported figure/table `.rda` files for eventual transmittance #' to SIS via `asar::export_to_sis()`. -#' +#' #' @param sis_data_dir Path. Location to save the sis_assmt_template.csv and #' sis_ts_template.csv files or, if present, the location of the #' existing sis_assmt_template.csv file. -#' +#' #' Default: The working directory. -#' -#' @param key_quantities_dir Path. Location of the existing key_quantities.csv +#' +#' @param key_quantities_dir Path. Location of the existing key_quantities.csv #' file. -#' +#' #' Default: The working directory. -#' -#' @param figures_tables_dir Path. Location of the existing 'figures' and +#' +#' @param figures_tables_dir Path. Location of the existing 'figures' and #' 'tables' directories. -#' +#' #' Default: The working directory. -#' +#' #' @details See the "Automating data extraction for SIS" vignette for a #' detailed overview of the workflow and requirements for this function. -#' +#' #' @export #' #' @examples @@ -36,30 +36,33 @@ #' extract_sis_data <- function(sis_data_dir = getwd(), key_quantities_dir = getwd(), - figures_tables_dir = getwd() - ) { + figures_tables_dir = getwd()) { # check if existing figures and tables folders exist; if both absent, throw an error if (!dir.exists(fs::path(figures_tables_dir, "figures")) & !dir.exists(fs::path(figures_tables_dir, "tables"))) { cli::cli_abort("Neither 'figures' nor 'tables' folders were found in {figures_tables_dir}. Please check the `figures_tables_dir` path, or export figures and tables, and then try again.") - } - + } + # Check if existing data files exist; if not, start from blank templates if (!file.exists(fs::path(sis_data_dir, "sis_assmt_template.csv"))) { assmt_dat <- utils::read.csv(system.file("resources", "sis_assmt_template.csv", package = "stockplotr")) cli::cli_alert_info("No existing sis_assmt_template.csv found in {sis_data_dir}. Using blank template.") } else { assmt_dat <- read.csv(fs::path(sis_data_dir, "sis_assmt_template.csv"), stringsAsFactors = FALSE) - cli::cli_alert_success("Found existing sis_assmt_template.csv in {sis_data_dir}.") + cli::cli_alert_success("Found existing sis_assmt_template.csv in {sis_data_dir}.") } - + ts_dat <- utils::read.csv(system.file("resources", "sis_ts_template.csv", package = "stockplotr")) - + # extract key quantities from csv and assign to variables kqs_path <- fs::path(key_quantities_dir, "key_quantities.csv") - if (file.exists(kqs_path)){ - kqs <- read.csv(fs::path(key_quantities_dir, - "key_quantities.csv"), - stringsAsFactors = FALSE) + if (file.exists(kqs_path)) { + kqs <- read.csv( + fs::path( + key_quantities_dir, + "key_quantities.csv" + ), + stringsAsFactors = FALSE + ) cli::cli_alert_success("Found existing key_quantities.csv in {key_quantities_dir}.") } else { cli::cli_alert_warning("No existing key_quantities.csv found in {key_quantities_dir}.") @@ -69,8 +72,8 @@ extract_sis_data <- function(sis_data_dir = getwd(), "*" = "plot_biomass()" )) } - - if (file.exists(kqs_path)){ + + if (file.exists(kqs_path)) { # insert values into the sis_assmt_template.csv file mapping <- tibble::tribble( ~key_quantity, ~Variable, @@ -92,20 +95,20 @@ extract_sis_data <- function(sis_data_dir = getwd(), "F.MSY.terminal.max", "AS_FMSY_MAX", "F.MSY.terminal.min", "AS_FMSY_MIN" ) - + # Extract values and format into a key-value matching table - new_vals <- kqs |> - dplyr::inner_join(mapping, by = "key_quantity") |> - dplyr::mutate(value = as.numeric(value)) |> + new_vals <- kqs |> + dplyr::inner_join(mapping, by = "key_quantity") |> + dplyr::mutate(value = as.numeric(value)) |> dplyr::select(Variable, new_value = value) - + # Update assmt_dat - assmt_dat <- assmt_dat |> - dplyr::left_join(new_vals, by = "Variable") |> - dplyr::mutate(Value = ifelse(!is.na(new_value), new_value, Value)) |> + assmt_dat <- assmt_dat |> + dplyr::left_join(new_vals, by = "Variable") |> + dplyr::mutate(Value = ifelse(!is.na(new_value), new_value, Value)) |> dplyr::select(-new_value) } - + # obtain time series data if (!dir.exists(fs::path(figures_tables_dir, "figures"))) { cli::cli_alert_info("'figures' folder not found in {sis_data_dir}.") @@ -127,76 +130,83 @@ extract_sis_data <- function(sis_data_dir = getwd(), biomass <<- NULL } ) - + # SPAWNERS (fits under "abundance" category) - tryCatch({ - load(fs::path(figures_tables_dir, "figures", "spawning_biomass_figure.rda")) |> suppressWarnings() - sb <- rda[["figure"]][["layers"]][["geom_line"]]$data - spawning_biomass <- sb |> - dplyr::group_by(year) |> - dplyr::summarise(sum = sum(estimate)) |> - dplyr::rename(Spawners = sum) - }, - error = function(e) { - cli::cli_alert_warning("Spawning biomass data was not extracted from the 'spawning_biomass_figure.rda' file.") - spawning_biomass <<- NULL - } + tryCatch( + { + load(fs::path(figures_tables_dir, "figures", "spawning_biomass_figure.rda")) |> suppressWarnings() + sb <- rda[["figure"]][["layers"]][["geom_line"]]$data + spawning_biomass <- sb |> + dplyr::group_by(year) |> + dplyr::summarise(sum = sum(estimate)) |> + dplyr::rename(Spawners = sum) + }, + error = function(e) { + cli::cli_alert_warning("Spawning biomass data was not extracted from the 'spawning_biomass_figure.rda' file.") + spawning_biomass <<- NULL + } ) - + # RECRUITMENT - tryCatch({ - load(fs::path(figures_tables_dir, "figures", "abundance_at_age_figure.rda")) |> suppressWarnings() - rec <- rda[["figure"]][["layers"]][["geom_point"]][["data"]] - recruitment <- rec |> - dplyr::filter(age == 1) |> - dplyr::group_by(year) |> - dplyr::summarise(sum = sum(estimate)) |> - dplyr::rename(Recruitment = sum) - }, - error = function(e) { - cli::cli_alert_warning("Recruitment (age 1) data was not extracted from the 'abundance_at_age_figure.rda' file.") - recruitment <<- NULL - - # this is for recruitment in mt- not age-1, which is what SIS expects - # load(fs::path(figures_tables_dir, "figures", "recruitment_figure.rda")) |> suppressWarnings() - # rec <- rda[["figure"]][["layers"]][["geom_line"]]$data - # recruitment <- rec |> - # dplyr::group_by(year) |> - # dplyr::summarise(sum = sum(predicted_recruitment)) |> - # dplyr::rename(Recruitment = sum) - # }, - # error = function(e) { - # cli::cli_alert_warning("Recruitment data was not extracted from the 'recruitment_figure.rda' file.") - # recruitment <<- NULL - }) - + tryCatch( + { + load(fs::path(figures_tables_dir, "figures", "abundance_at_age_figure.rda")) |> suppressWarnings() + rec <- rda[["figure"]][["layers"]][["geom_point"]][["data"]] + recruitment <- rec |> + dplyr::filter(age == 1) |> + dplyr::group_by(year) |> + dplyr::summarise(sum = sum(estimate)) |> + dplyr::rename(Recruitment = sum) + }, + error = function(e) { + cli::cli_alert_warning("Recruitment (age 1) data was not extracted from the 'abundance_at_age_figure.rda' file.") + recruitment <<- NULL + + # this is for recruitment in mt- not age-1, which is what SIS expects + # load(fs::path(figures_tables_dir, "figures", "recruitment_figure.rda")) |> suppressWarnings() + # rec <- rda[["figure"]][["layers"]][["geom_line"]]$data + # recruitment <- rec |> + # dplyr::group_by(year) |> + # dplyr::summarise(sum = sum(predicted_recruitment)) |> + # dplyr::rename(Recruitment = sum) + # }, + # error = function(e) { + # cli::cli_alert_warning("Recruitment data was not extracted from the 'recruitment_figure.rda' file.") + # recruitment <<- NULL + } + ) + # FISHING MORTALITY - tryCatch({ - load(fs::path(figures_tables_dir, "figures", "fishing_mortality_figure.rda")) |> suppressWarnings() - fm <- rda[["figure"]][["layers"]][["geom_line"]]$data - fishing_mortality <- fm |> - dplyr::group_by(year) |> - dplyr::summarise(mean = mean(estimate)) |> - dplyr::rename(Fmort = mean) - }, - error = function(e) { - cli::cli_alert_warning("Fishing mortality data was not extracted from the 'fishing_mortality_figure.rda' file.") - fishing_mortality <<- NULL - }) - + tryCatch( + { + load(fs::path(figures_tables_dir, "figures", "fishing_mortality_figure.rda")) |> suppressWarnings() + fm <- rda[["figure"]][["layers"]][["geom_line"]]$data + fishing_mortality <- fm |> + dplyr::group_by(year) |> + dplyr::summarise(mean = mean(estimate)) |> + dplyr::rename(Fmort = mean) + }, + error = function(e) { + cli::cli_alert_warning("Fishing mortality data was not extracted from the 'fishing_mortality_figure.rda' file.") + fishing_mortality <<- NULL + } + ) + # INDEX - tryCatch({ - load(fs::path(figures_tables_dir, "figures", "index_figure.rda")) |> suppressWarnings() - index <- rda[["figure"]][["layers"]][["geom_line"]]$data - index <- index |> - dplyr::group_by(year) |> - dplyr::summarise(mean = mean(estimate)) |> - dplyr::rename(Index = mean) - }, - error = function(e) { - cli::cli_alert_warning("Index data was not extracted from the 'index_figure.rda' file.") - index <<- NULL - }) + tryCatch( + { + load(fs::path(figures_tables_dir, "figures", "index_figure.rda")) |> suppressWarnings() + index <- rda[["figure"]][["layers"]][["geom_line"]]$data + index <- index |> + dplyr::group_by(year) |> + dplyr::summarise(mean = mean(estimate)) |> + dplyr::rename(Index = mean) + }, + error = function(e) { + cli::cli_alert_warning("Index data was not extracted from the 'index_figure.rda' file.") + index <<- NULL + } + ) } if (!dir.exists(fs::path(figures_tables_dir, "tables"))) { cli::cli_alert_info("'tables' folder not found in {sis_data_dir}.") @@ -205,38 +215,38 @@ extract_sis_data <- function(sis_data_dir = getwd(), } else { table_ts <- TRUE tryCatch( - { - load(fs::path(figures_tables_dir, "tables", "total_catch_table.rda")) |> suppressWarnings() - catch <- rda[["table"]][["_data"]] - catch_cols <- colnames(catch) - cols_without_catch <- c("Sex", "Area", "Season", "Type") - if (any(cols_without_catch %in% catch_cols)) { + { + load(fs::path(figures_tables_dir, "tables", "total_catch_table.rda")) |> suppressWarnings() + catch <- rda[["table"]][["_data"]] + catch_cols <- colnames(catch) + cols_without_catch <- c("Sex", "Area", "Season", "Type") + if (any(cols_without_catch %in% catch_cols)) { + catch <- catch |> + dplyr::select(-dplyr::any_of(cols_without_catch)) + } catch <- catch |> - dplyr::select(-dplyr::any_of(cols_without_catch)) + # remove values in parentheses, if present + dplyr::mutate(dplyr::across(!Year, ~ stringr::str_remove_all(.x, "\\s*\\(.*?\\)"))) |> + dplyr::mutate(dplyr::across(!Year, ~ stringr::str_remove_all(.x, ","))) |> + dplyr::mutate(dplyr::across(!Year, ~ as.numeric(.x))) |> + # summarize non-Year rows + dplyr::rowwise() |> + dplyr::mutate(Catch = sum(dplyr::c_across(!Year), na.rm = TRUE)) |> + dplyr::ungroup() |> + dplyr::select(Year, Catch) + }, + error = function(e) { + cli::cli_alert_warning("Catch data will not be extracted from the 'total_catch_table.rda' file.") + catch <<- NULL } - catch <- catch |> - # remove values in parentheses, if present - dplyr::mutate(dplyr::across(!Year, ~ stringr::str_remove_all(.x, "\\s*\\(.*?\\)"))) |> - dplyr::mutate(dplyr::across(!Year, ~ stringr::str_remove_all(.x, ","))) |> - dplyr::mutate(dplyr::across(!Year, ~ as.numeric(.x))) |> - # summarize non-Year rows - dplyr::rowwise() |> - dplyr::mutate(Catch = sum(dplyr::c_across(!Year), na.rm = TRUE)) |> - dplyr::ungroup() |> - dplyr::select(Year, Catch) - }, - error = function(e) { - cli::cli_alert_warning("Catch data will not be extracted from the 'total_catch_table.rda' file.") - catch <<- NULL - } ) } - - if(exists("fig_ts")){ + + if (exists("fig_ts")) { summaries <- c("biomass", "spawning_biomass", "recruitment", "fishing_mortality", "index") - - summaries <- summaries[sapply(summaries, function(x) !is.null(get(x)))] - + + summaries <- summaries[sapply(summaries, function(x) !is.null(get(x)))] + # join all summaries by year all_summaries <- c() for (i in seq_along(summaries)) { @@ -244,25 +254,27 @@ extract_sis_data <- function(sis_data_dir = getwd(), all_summaries <- get(summaries[i]) } else { all_summaries <- dplyr::full_join(all_summaries, - get(summaries[i]), - by = "year") + get(summaries[i]), + by = "year" + ) } } } - if (exists("table_ts") & !is.null(catch)){ - if (!is.null(all_summaries) & exists("fig_ts")){ + if (exists("table_ts") & !is.null(catch)) { + if (!is.null(all_summaries) & exists("fig_ts")) { catch <- catch |> dplyr::rename(year = Year) all_summaries <- dplyr::full_join(all_summaries, - catch, - by = "year") + catch, + by = "year" + ) summaries <- c(summaries, "catch") } else { all_summaries <- get("catch") summaries <- "catch" } } - + ts_options <- summaries[!is.na(summaries)] cli::cli_alert_info("The following time series summaries were extracted:") cli::cli_ul(ts_options) @@ -281,23 +293,25 @@ extract_sis_data <- function(sis_data_dir = getwd(), if (all(primary_options2 %in% ts_options)) { cli::cli_alert_info("One of the following categories can be a Primary time series:") cli::cli_ul(primary_options2) - if (interactive()) { + if (interactive()) { primary1 <- readline("Which category should be chosen? ") - if (primary1 %notin% primary_options2) { - cli::cli_abort("Invalid Primary category specified. Please choose from: {primary_options2}.") - } else { - primary <- c(primary, primary1) - } + if (primary1 %notin% primary_options2) { + cli::cli_abort("Invalid Primary category specified. Please choose from: {primary_options2}.") } else { - primary <- c(primary, primary_options2[1]) - cli::cli_alert_info("Primary categor{?y/ies} set to {primary} by default in non-interactive mode.") + primary <- c(primary, primary1) } + } else { + primary <- c(primary, primary_options2[1]) + cli::cli_alert_info("Primary categor{?y/ies} set to {primary} by default in non-interactive mode.") + } } else if (any(primary_options2 %in% ts_options)) { primary <- c(primary, ts_options[ts_options %in% primary_options2]) } - - if (length(primary) == 0) {primary <- NA} - + + if (length(primary) == 0) { + primary <- NA + } + category_pairs <- list( "fishing_mortality" = "Fmort", "recruitment" = "Recruitment", @@ -306,41 +320,41 @@ extract_sis_data <- function(sis_data_dir = getwd(), "biomass" = "Biomass", "index" = "Index" ) - + primary <- unlist(lapply(primary, function(x) category_pairs[[x]])) - + # identify sis_assmt_template AS_B_UNIT values if coded b_unit <- assmt_dat$Value[assmt_dat$Variable == "AS_B_UNIT"] if (as.numeric(b_unit) %in% 1:8) { b_unit <- switch(b_unit, - "1" = "Metric Tons", - "2" = "Thousand Metric Tons", - "3" = "Adult spawners - Natural & Hatchery - Escapement", - "4" = "Adult spawners - Hatchery - Escapement", - "5" = "Adult spawners - Natural - Escapement", - "6" = "Number of Eggs", - "7" = "kg / tow", - "8" = "Number of Fish" + "1" = "Metric Tons", + "2" = "Thousand Metric Tons", + "3" = "Adult spawners - Natural & Hatchery - Escapement", + "4" = "Adult spawners - Hatchery - Escapement", + "5" = "Adult spawners - Natural - Escapement", + "6" = "Number of Eggs", + "7" = "kg / tow", + "8" = "Number of Fish" ) } - + # identify sis_assmt_template AS_F_UNIT values if coded f_unit <- assmt_dat$Value[assmt_dat$Variable == "AS_F_UNIT"] if (as.numeric(f_unit) %in% 1:7) { f_unit <- switch(f_unit, - "1" = "Apical F", - "2" = "Fully-selected F", - "3" = "Exploitation Rate", - "4" = "Relative F", - "5" = "Metric Tons", - "6" = "1 - SPR", - "7" = "Z - M" + "1" = "Apical F", + "2" = "Fully-selected F", + "3" = "Exploitation Rate", + "4" = "Relative F", + "5" = "Metric Tons", + "6" = "1 - SPR", + "7" = "Z - M" ) } - - + + ts_dat_filled <- all_summaries |> - dplyr::rename_with(~ "Year", .cols = matches("^year$")) |> + dplyr::rename_with(~"Year", .cols = matches("^year$")) |> tidyr::pivot_longer(cols = -Year, names_to = "Category", values_to = "Value") |> dplyr::mutate(Primary = ifelse(tolower(Category) %in% tolower(primary), "Y", "")) |> dplyr::mutate(Description = dplyr::case_when( @@ -356,16 +370,16 @@ extract_sis_data <- function(sis_data_dir = getwd(), Category == "Biomass" ~ as.character(b_unit), Category == "Spawners" ~ as.character(b_unit), Category == "Fmort" ~ as.character(f_unit), - Category == "Index" ~ "", + Category == "Index" ~ "", Category == "Catch" ~ ifelse(kqs$value[kqs$key_quantity == "tot.catch.units"] == " (mt)", "Metric Tons", kqs$value[kqs$key_quantity == "tot.catch.units"]), Category == "Recruitment" ~ "Number of Fish", TRUE ~ NA )) |> dplyr::relocate(Value, .after = Unit) - + # Ensure ts_dat_filled has same cols as ts_dat if (isFALSE(any(colnames(ts_dat_filled) == colnames(ts_dat)))) { - cli::cli_abort("Time series data does not match template structure.") + cli::cli_abort("Time series data does not match template structure.") } # if assmt_dat$Value is NA and Default is 95, change it to Default @@ -374,11 +388,11 @@ extract_sis_data <- function(sis_data_dir = getwd(), assmt_dat$Value[i] <- assmt_dat$Default[i] } } - + # export files assmt_dat_path <- fs::path(sis_data_dir, "sis_assmt_template.csv") ts_dat_path <- fs::path(sis_data_dir, "sis_ts_template.csv") - + if (file.exists(assmt_dat_path) | file.exists(ts_dat_path)) { cli::cli_alert_info("Existing sis_assmt_template.csv or sis_ts_template.csv found in {sis_data_dir}.") overwrite <- readline("Do you want to overwrite the existing files? (y/n): ") diff --git a/R/plot_spr.R b/R/plot_spr.R index 7b6e00b8..a818c1e2 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -1,7 +1,7 @@ #' Plot spawning potential ratio (SPR) #' #' @inheritParams plot_spawning_biomass -#' +#' #' @param ylab String. Y-axis label to show. #' #' @returns A plot showing spawning potential ratio (SPR). @@ -47,13 +47,12 @@ plot_spawning_potential_ratio <- function( ylab = NULL, ... ) { - # Filter data for spr prepared_data <- filter_data( dat = dat, label_name = "spr", geom = geom, - #TODO: change this to era once stockplotr::example_data updated + # TODO: change this to era once stockplotr::example_data updated era = NULL, group = group, facet = facet, @@ -63,19 +62,19 @@ plot_spawning_potential_ratio <- function( ) |> # filter NA from year dplyr::filter(!is.na(year)) - - if(nrow(prepared_data)==0){ + + if (nrow(prepared_data) == 0) { # We could potentially make this more informative if we know the model type # by reporting the common MODULE used by other packages (e.g., DERIVED_QUANTITIES # for SS3 models, or t.series for BAM models). cli::cli_alert(glue::glue("There is no data available to be plotted. Try selecting a different module.")) } - + # Process data processed_data <- process_data( dat = prepared_data, group = group, - facet = facet# + facet = facet # # method = "sum" ) prepared_data <- processed_data[[1]] @@ -93,7 +92,7 @@ plot_spawning_potential_ratio <- function( if (!is.null(group)) { if (group %notin% colnames(prepared_data)) group <- NULL } - + # inital base plot plt <- plot_timeseries( dat = prepared_data, @@ -104,10 +103,14 @@ plot_spawning_potential_ratio <- function( facet = facet, ... ) + - ggplot2::geom_hline(yintercept = 1, - color = "grey") + - ggplot2::geom_hline(yintercept = 0, - color = "grey") + + ggplot2::geom_hline( + yintercept = 1, + color = "grey" + ) + + ggplot2::geom_hline( + yintercept = 0, + color = "grey" + ) + add_reference_line( dat = dat, ref_line = ref_line, @@ -115,7 +118,7 @@ plot_spawning_potential_ratio <- function( scale_amount = 1 ) + theme_noaa() - + if (length(unique(prepared_data$group_var)) == 1) { plt <- plt + ggplot2::theme(legend.position = "none") @@ -125,13 +128,13 @@ plot_spawning_potential_ratio <- function( if (make_rda) { # TODO: Update caption, alt text, and quantities once plot is finalized # Obtain relevant key quantities for captions/alt text - + spr.start.year <- min(prepared_data$year) spr.end.year <- max(prepared_data$year) spr.min <- min(prepared_data$estimate) |> round(digits = 3) spr.max <- max(prepared_data$estimate) |> round(digits = 3) spr.ref.pt <- as.character(ref_line) - + # calculate & export key quantities export_kqs( spr.start.year, diff --git a/R/plot_stock_recruitment.R b/R/plot_stock_recruitment.R index a7dbe279..aa0f60f6 100644 --- a/R/plot_stock_recruitment.R +++ b/R/plot_stock_recruitment.R @@ -100,7 +100,7 @@ plot_stock_recruitment <- function( # Extract spawning biomass sb <- filter_data( dat = dat |> - dplyr::filter(!is.na(year)), + dplyr::filter(!is.na(year)), label_name = "spawning biomass", geom = "point", era = era, diff --git a/R/table_total_catch.R b/R/table_total_catch.R index bb1f3529..e2d3ca60 100644 --- a/R/table_total_catch.R +++ b/R/table_total_catch.R @@ -58,9 +58,11 @@ table_total_catch <- function( # Filter data for catch prepared_data <- filter_data( dat = dat |> - dplyr::filter(!is.na(year), - !is.na(estimate), - label %in% c("catch_retained", "catch_dead", "catch_selected", "catch")), + dplyr::filter( + !is.na(year), + !is.na(estimate), + label %in% c("catch_retained", "catch_dead", "catch_selected", "catch") + ), label_name = "^catch", geom = "line", era = era, diff --git a/R/utils_plot.R b/R/utils_plot.R index 691b52fd..086eb490 100644 --- a/R/utils_plot.R +++ b/R/utils_plot.R @@ -568,32 +568,32 @@ reference_line <- function( ref_line_val <- ref_line[[1]] reference <- names(ref_line) - switch(direction, + switch(direction, "h" = { - list( - # Add geom for ref line - ggplot2::geom_hline( - data = data.frame(yintercept = ref_line_val, model = model_name, group_var = "1"), - ggplot2::aes( - yintercept = ref_line_val / scale_amount, - color = interaction(model, group_var) # model - ), - linetype = "dashed", - show.legend = FALSE + list( + # Add geom for ref line + ggplot2::geom_hline( + data = data.frame(yintercept = ref_line_val, model = model_name, group_var = "1"), + ggplot2::aes( + yintercept = ref_line_val / scale_amount, + color = interaction(model, group_var) # model ), - # add line annotation - ggplot2::annotate( - geom = "text", - # TODO: need to change this for general process - x = -Inf, - y = ref_line_val / scale_amount, - label = glue::glue("{reference}"), # glue::glue("{stringr::str_replace_all(label_name, '_', '~')}[{reference}]"), # list(bquote(label_name[.(reference)])), - parse = TRUE, - hjust = -0.05, # slight offset so text doesn't hit border - vjust = -0.5 # , #slightly above line - # size = 5 # this is not foolproof - ) + linetype = "dashed", + show.legend = FALSE + ), + # add line annotation + ggplot2::annotate( + geom = "text", + # TODO: need to change this for general process + x = -Inf, + y = ref_line_val / scale_amount, + label = glue::glue("{reference}"), # glue::glue("{stringr::str_replace_all(label_name, '_', '~')}[{reference}]"), # list(bquote(label_name[.(reference)])), + parse = TRUE, + hjust = -0.05, # slight offset so text doesn't hit border + vjust = -0.5 # , #slightly above line + # size = 5 # this is not foolproof ) + ) }, "v" = { list( @@ -622,7 +622,6 @@ reference_line <- function( ) } ) - } #------------------------------------------------------------------------------ diff --git a/man/calculate_reference_point.Rd b/man/calculate_reference_point.Rd index 86e38307..e7f50726 100644 --- a/man/calculate_reference_point.Rd +++ b/man/calculate_reference_point.Rd @@ -13,7 +13,7 @@ returned from \link[stockplotr]{convert_output}. If inputting a list of tibbles, the first tibble's reference point defined in \code{ref_line} is used to plot a reference line or calculate relative spawning biomass.} -\item{reference_name}{a string of the name of the reference point (e.g. "spawning biomass msy")} +\item{reference_name}{String. Name of the reference point (e.g. "spawning biomass msy")} \item{lbs}{Logical. TRUE/FALSE; indicate whether to convert the y-axis values from kilograms to pounds. The default units match the default in the diff --git a/man/plot_spawning_potential_ratio.Rd b/man/plot_spawning_potential_ratio.Rd new file mode 100644 index 00000000..a424822d --- /dev/null +++ b/man/plot_spawning_potential_ratio.Rd @@ -0,0 +1,128 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plot_spr.R +\name{plot_spawning_potential_ratio} +\alias{plot_spawning_potential_ratio} +\title{Plot spawning potential ratio (SPR)} +\usage{ +plot_spawning_potential_ratio( + dat, + geom = "line", + group = NULL, + facet = NULL, + ref_line = "target", + era = "time", + module = NULL, + interactive = TRUE, + make_rda = FALSE, + figures_dir = getwd(), + ylab = NULL, + ... +) +} +\arguments{ +\item{dat}{Data frame or list. A tibble or named list of tibbles (input as \code{list()}) +returned from \link[stockplotr]{convert_output}. + +If inputting a list of tibbles, the first tibble's reference point defined +in \code{ref_line} is used to plot a reference line or calculate relative spawning biomass.} + +\item{geom}{String. Geom used for the plot. + +Default: "line". + +Options: "line", "point", or "area"} + +\item{group}{String. Single column that groups the data. + +Set group = "none" to summarize data over all indexing values. + +Default: NULL +Options: Including, but not limited to: "year", "area", "fleet", "sex", "none", NULL} + +\item{facet}{Character vector. Column name or names used for faceting. + +Default: NULL} + +\item{ref_line}{String or named vector. Reference point name (and value if +custom). When multiple models are being compared, a reference line for each +model will appear, if desired. The following options can be used to customize +the reference line: +\enumerate{ +\item all lines are comparing same ref_line = "msy", ref_line = "target", ref_line = "unfished", etc +\item custom input vector - ref_line = c("sable23_msy"=30, "sable25_msy"=40) -- user must indicate which model in label otherwise it will assign in order of dat +\item input vector of labels - ref_line = c("msy", "target") +} + +Default: "msy" + +Options: (including, but not limited to) "target", "msy", and "unfished" +If the reference point is not found in the data, set ref_line = c("name" = value).} + +\item{era}{String. Era of data. + +Default: "time" + +Options: "early", "time", "fore" (forecast), or NULL (all data)} + +\item{module}{Character vector. (Optional) Module name found in \code{dat$module_name}. +If selecting >1 module, place them in a vector like c("module1", "module2"). + +Default: NULL + +If the interactive and >1 module_name is found, user will select the +module_name in the console. @seealso \code{\link[=filter_data]{filter_data()}}} + +\item{interactive}{Logical. TRUE/FALSE; indicate whether the environment is interactive. + +Default: \code{FALSE}} + +\item{make_rda}{Logical. TRUE/FALSE; indicate whether to save the object and +make an automated caption and alternative text in the form of an \code{rda} object. If TRUE, +the rda will be exported to the folder indicated in the argument "figures_dir". + +Default: \code{FALSE}.} + +\item{figures_dir}{Path. Path to the "figures" folder. + +Default: \code{getwd()} + +The folder is created within the path if it does not exist.} + +\item{ylab}{String. Y-axis label to show.} + +\item{...}{Arguments called from \link[ggplot2]{geom_line} or \link[ggplot2]{geom_point}} +} +\value{ +A plot showing spawning potential ratio (SPR). +} +\description{ +Plot spawning potential ratio (SPR) +} +\details{ +The input is from an assessment model output file +translated to a standardized output (\link[stockplotr]{convert_output}). +There are options to return a \code{ggplot2} object or export an .rda object +containing associated caption and alternative text for the figure. +} +\examples{ +plot_spawning_potential_ratio( + dat = stockplotr:::example_data, + unit_label = "metric tons", + group = "fleet", + interactive = FALSE, + make_rda = FALSE, + ylab = "SPR" +) +plot_spawning_potential_ratio( + dat = stockplotr:::example_data, + unit_label = "metric tons", + facet = "fleet", + module = "DERIVED_QUANTITIES", + interactive = FALSE, + make_rda = FALSE, + ylab = "(1-SPR)/(1-SPR_ref)" +) +} +\seealso{ +\code{\link[=convert_output]{convert_output()}}, \code{\link[=filter_data]{filter_data()}}, \code{\link[=process_data]{process_data()}}, \code{\link[=plot_timeseries]{plot_timeseries()}}, \code{\link[=export_kqs]{export_kqs()}}, \code{\link[=insert_kqs]{insert_kqs()}}, \code{\link[=create_rda]{create_rda()}} +} diff --git a/tests/testthat/helper-test_functions.R b/tests/testthat/helper-test_functions.R index 78688e07..7b35a04e 100644 --- a/tests/testthat/helper-test_functions.R +++ b/tests/testthat/helper-test_functions.R @@ -1,32 +1,34 @@ #' Check for the existence and remove .rda files from test environment -#' +#' #' Checks for the existence of `dir` and `filename` as well as the -#' existence of "captions_alt_text.csv" and "key_quantities.csv". -#' Files are removed upon completion of checks. -#' +#' existence of "captions_alt_text.csv" and "key_quantities.csv". +#' Files are removed upon completion of checks. +#' #' For testing only. -#' +#' #' @param filename String. filename of figure/table .rda file #' @param dir String. directory where filename exists #' @param figs_or_tables String. whether check for a "figures" or "tables" internal directory -#' +#' #' DEFAULT: "figures" -#' -check_and_remove_tmp_files <- function(filename, dir=fs::path(getwd()), figs_or_tables="figures"){ - # expect that both figures dir and the abundance_at_age_figure.rda file exist - expect_true(dir.exists(dir)) # this check needs to exist in case save dir isnt getwd() - expect_true(dir.exists(fs::path(dir, figs_or_tables))) - expect_true(file.exists(fs::path(dir, figs_or_tables, filename))) +#' +check_and_remove_tmp_files <- function(filename, dir = fs::path(getwd()), figs_or_tables = "figures") { + # expect that both figures dir and the abundance_at_age_figure.rda file exist + expect_true(dir.exists(dir)) # this check needs to exist in case save dir isnt getwd() + expect_true(dir.exists(fs::path(dir, figs_or_tables))) + expect_true(file.exists(fs::path(dir, figs_or_tables, filename))) - # erase temporary testing files - captions_file <- fs::path(dir, "captions_alt_text.csv") - keyquant_file <- fs::path(dir, "key_quantities.csv") + # erase temporary testing files + captions_file <- fs::path(dir, "captions_alt_text.csv") + keyquant_file <- fs::path(dir, "key_quantities.csv") - if(fs::file_exists(captions_file)) - fs::file_delete(captions_file) + if (fs::file_exists(captions_file)) { + fs::file_delete(captions_file) + } - if(fs::file_exists(keyquant_file)) - fs::file_delete(keyquant_file) + if (fs::file_exists(keyquant_file)) { + fs::file_delete(keyquant_file) + } - unlink(fs::path(dir, figs_or_tables), recursive = T) + unlink(fs::path(dir, figs_or_tables), recursive = T) } diff --git a/tests/testthat/test-convert_output.R b/tests/testthat/test-convert_output.R index 12b477a8..fc495216 100644 --- a/tests/testthat/test-convert_output.R +++ b/tests/testthat/test-convert_output.R @@ -14,7 +14,7 @@ test_that("convert_output works for SS3", { "BigSkate_2019" ) - models_to_test <- all_models[grepl(paste0(model_names, collapse="|"), all_models)] + models_to_test <- all_models[grepl(paste0(model_names, collapse = "|"), all_models)] # Loop through each model directory and check convert_output function for (i in seq_along(models_to_test)) { diff --git a/tests/testthat/test-extract_sis_data.R b/tests/testthat/test-extract_sis_data.R index 60a09c1f..0d2eb31c 100644 --- a/tests/testthat/test-extract_sis_data.R +++ b/tests/testthat/test-extract_sis_data.R @@ -1,16 +1,20 @@ test_that("extract_sis_data() runs with all possible rdas present", { save_all_plots(stockplotr::example_data) table_total_catch(stockplotr::example_data, - module = "TIME_SERIES", - interactive = FALSE, - make_rda = TRUE) + module = "TIME_SERIES", + interactive = FALSE, + make_rda = TRUE + ) files <- c( - fs::path("figures", - c("biomass_figure.rda", "spawning_biomass_figure.rda", "abundance_at_age_figure.rda", "fishing_mortality_figure.rda", "index_figure.rda") - ), - fs::path("tables", - "total_catch_table.rda") + fs::path( + "figures", + c("biomass_figure.rda", "spawning_biomass_figure.rda", "abundance_at_age_figure.rda", "fishing_mortality_figure.rda", "index_figure.rda") + ), + fs::path( + "tables", + "total_catch_table.rda" + ) ) expect_true(all(file.exists(files))) diff --git a/tests/testthat/test-plot_natural_mortality.R b/tests/testthat/test-plot_natural_mortality.R index fb241f72..59cd88a7 100644 --- a/tests/testthat/test-plot_natural_mortality.R +++ b/tests/testthat/test-plot_natural_mortality.R @@ -2,7 +2,7 @@ test_that("plot_natural_mortality generate without errors", { # expect error-free plot with minimal arguments expect_no_error( plot_natural_mortality( - stockplotr::example_data, + stockplotr::example_data, module = "Natural_Mortality", interactive = FALSE ) diff --git a/tests/testthat/test-plot_spawning_potential_ratio.R b/tests/testthat/test-plot_spawning_potential_ratio.R index 75b19161..aec6d6d9 100644 --- a/tests/testthat/test-plot_spawning_potential_ratio.R +++ b/tests/testthat/test-plot_spawning_potential_ratio.R @@ -3,7 +3,7 @@ test_that("plot_spawning_potential_ratio generates plots without errors", { expect_no_error( plot_spawning_potential_ratio(stockplotr::example_data, interactive = FALSE) ) - + # expect error-free plot with many arguments expect_no_error( plot_spawning_potential_ratio( @@ -14,7 +14,7 @@ test_that("plot_spawning_potential_ratio generates plots without errors", { ) ) - + # expect ggplot object is returned expect_s3_class( plot_spawning_potential_ratio( @@ -35,11 +35,11 @@ test_that("rda file made when indicated", { make_rda = TRUE, figures_dir = getwd() ) - + # expect that both figures dir and the spawning_biomass_figure.rda file exist expect_true(dir.exists(fs::path(getwd(), "figures"))) expect_true(file.exists(fs::path(getwd(), "figures", "spawning_potential_ratio_figure.rda"))) - + # erase temporary testing files file.remove(fs::path(getwd(), "captions_alt_text.csv")) file.remove(fs::path(getwd(), "key_quantities.csv")) diff --git a/vignettes/extract-sis-data.Rmd b/vignettes/extract-sis-data.Rmd index 2c52b7e0..cfe7f33c 100644 --- a/vignettes/extract-sis-data.Rmd +++ b/vignettes/extract-sis-data.Rmd @@ -134,4 +134,4 @@ The `extract_sis_data()` workflow extracts at most one time series for each cate * **Fmort, Recruitment, & Catch**: Multiple time series allowed per category, but exactly one must be marked Primary = Y per category. * **Spawners & Biomass**: Multiple time series allowed across both categories, but only one time series combined across both Spawners and Biomass can be marked Primary = Y. -* **Index**: Multiple time series allowed, but none can be marked Primary = Y (always N). \ No newline at end of file +* **Index**: Multiple time series allowed, but none can be marked Primary = Y (always N).