diff --git a/NAMESPACE b/NAMESPACE index 687233f7..c6c98fc8 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,6 +5,7 @@ export(create_latex_table) export(create_rda) export(export_rda) export(extract_caps_alttext) +export(extract_sis_data) export(filter_data) export(plot_aa) export(plot_abundance_at_age) diff --git a/R/extract_sis_data.R b/R/extract_sis_data.R new file mode 100644 index 00000000..ce5ccc69 --- /dev/null +++ b/R/extract_sis_data.R @@ -0,0 +1,391 @@ +#' Extract data from model results to send to SIS +#' +#' Semi-automate the extraction of key quantities from model results 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 file. +#' +#' Default: The working directory. +#' +#' @param figures_tables_dir Path. Location of the existing 'figures' and 'tables' directories. +#' +#' Default: The working directory. +#' +#' @details This function acts within the following workflow: +#' +#' 1. When a stock assessment is scheduled to conclude, SIS will generate an +#' attachment or prompt containing metadata and identifiers. +#' 2. The user will open two csv files containing placeholders for all of the data required by SIS: sis_assmt_template.csv (assessment summary data) and sis_ts_template.csv (time series data). There are three ways to obtain these files: +#' 2a. Run `stockplotr::extract_sis_data()`, which will generate, populate, and export the templates with data originating from a converted model results file. +#' 2b. Generate blank files by running `asar::create_blank_sis()`. +#' 2c. Locate blank files in the "report" folder generated by running `asar::create_template()`. +#' 3. The user will add the remaining necessary data into the csv files, ensuring that all required fields are completed. +#' 4. Run `export_to_sis()`, which will format and upload this data to a specific Google Drive folder. +#' 5. The uploaded contents will be resubmitted to SIS to finalize the record. +#' +#' @export +#' +#' @examples +#' \dontrun{ +#' extract_sis_data( +#' sis_data_dir = getwd(), +#' key_quantities_dir = "my_dir", +#' figures_tables_dir = "my_other_dir" +#' ) +#' } +#' +extract_sis_data <- function(sis_data_dir = getwd(), + key_quantities_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 <- read.csv(fs::path("inst/resources/sis_assmt_template.csv"), stringsAsFactors = FALSE) + 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}.") + } + + ts_dat <- read.csv(fs::path("inst/resources/sis_ts_template.csv"), stringsAsFactors = FALSE) + + # 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) + 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}.") + cli::cli_alert_info("To obtain key quantities relevant to the sis_assmt_template.csv, run the following functions and specify `make_rda = TRUE`:") + cli::cli_bullets(c( + "*" = "plot_fishing_mortality()", + "*" = "plot_biomass()", + "*" = "plot_landings()" + )) + } + + if (file.exists(kqs_path)){ + # insert values into the sis_assmt_template.csv file + mapping <- tibble::tribble( + ~key_quantity, ~Variable, + "landings.end.year", "AS_LAST_DATA_YEAR", + "F.MSY.terminal", "AS_FMSY", + "B.msy", "AS_BMSY", + "B.msy.min", "AS_BMSY_MIN", + "B.msy.max", "AS_BMSY_MAX", + "B.terminal.year", "AS_B_YEAR", + "F.terminal.year", "AS_F_YEAR", + "F.target", "AS_FTARGET", + "F.limit", "AS_FLIMIT", + "B.terminal.est", "AS_B_BEST", + "F.terminal.est", "AS_F_BEST", + "B.terminal.min", "AS_B_MIN", + "B.terminal.max", "AS_B_MAX", + "F.terminal.min", "AS_F_MIN", + "F.terminal.max", "AS_F_MAX", + "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)) |> + 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)) |> + 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}.") + cli::cli_alert_danger("Some time series data will not be extracted.") + } else { + fig_ts <- TRUE + # ABUNDANCE + tryCatch( + { + load(fs::path(figures_tables_dir, "figures", "abundance_at_age_figure.rda")) |> suppressWarnings() + aaa <- rda[["figure"]][["layers"]][["geom_line"]]$data + abundance <- aaa |> + dplyr::group_by(year) |> + dplyr::summarise(sum = sum(total_fish)) |> + dplyr::rename(Abundance = sum) + }, + error = function(e) { + cli::cli_alert_warning("Abundance data was not extracted from the 'abundance_at_age_figure.rda' file.") + abundance <<- NULL + } + ) + + # SPAWNERS + 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", "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 + }) + + # 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 + }) + } + if (!dir.exists(fs::path(figures_tables_dir, "tables"))) { + cli::cli_alert_info("'tables' folder not found in {sis_data_dir}.") + cli::cli_alert_danger("Some time series data will not be extracted.") + catch <- NULL + } 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)) { + catch <- catch |> + dplyr::select(-dplyr::any_of(cols_without_catch)) + } + 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")){ + summaries <- c("abundance", "spawning_biomass", "recruitment", "fishing_mortality", "index") + + summaries <- summaries[sapply(summaries, function(x) !is.null(get(x)))] + + # join all summaries by year + all_summaries <- c() + for (i in seq_along(summaries)) { + if (i == 1) { + all_summaries <- get(summaries[i]) + } else { + all_summaries <- dplyr::full_join(all_summaries, + get(summaries[i]), + by = "year") + } + } + } + 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") + 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) + primary_options1 <- c("fishing_mortality", "recruitment", "catch") + primary_options2 <- c("spawning_biomass", "abundance") + + if (length(ts_options) == 0) { + primary <- NA + cli::cli_alert_info("Zero time series summaries were extracted. Please check the figures and tables directories.") + } else if (length(ts_options) == 1) { + primary <- ts_options + cli::cli_alert_info("Only one time series summary was extracted ({primary}) and will be used as the Primary time series.") + } else if (length(ts_options) == 2) { + cli::cli_alert_info("Two time series summaries were extracted ({ts_options}).") + if (any(ts_options %in% primary_options1) & any(ts_options %in% primary_options2)) { + cli::cli_alert_info("These categories will be used as the Primary time series.") + primary <- ts_options + }} else { + cli::cli_alert_info("At most, two categories can be chosen as Primary time series:") + cli::cli_ul(c( + "fishing_mortality OR recruitment OR catch", + "spawning_biomass OR abundance" + )) + if (interactive()) { + primary1 <- readline("Which category should be designated as Primary 1?") + primary2 <- readline("Which category should be designated as Primary 2?") + if (primary1 %notin% ts_options | primary2 %notin% ts_options) { + cli::cli_abort("Invalid Primary category specified. Please choose from: {ts_options}.") + } else { + primary <- c(primary1, primary2) + } + } else { + # choose Fmort as first primary if present, otherwise Recruitment, otherwise Catch; and choose Spawners if present, otherwise Biomass + cli::cli_alert_info("The following categories will be chosen, in order of preference, as Primary time series:") + cli::cli_ul(c( + "fishing_mortality OR recruitment OR catch, and", + "spawning_biomass OR abundance" + )) + primary1 <- ifelse("fishing_mortality" %in% ts_options, + "fishing_mortality", + ifelse("recruitment" %in% ts_options, + "recruitment", + ifelse("catch" %in% ts_options, + "catch", + NA))) + primary2 <- ifelse("spawning_biomass" %in% ts_options, + "spawning_biomass", + ifelse("abundance" %in% ts_options, + "abundance", + NA)) + primary <- c(primary1, primary2) + primary <- primary[!is.na(primary)] + if (length(primary) == 0) { + cli::cli_alert_danger("No valid Primary categories found.") + primary <- NA + } else { + cli::cli_alert_info("Primary categor{?y/ies} set to {primary} by default in non-interactive mode.") + } + } + } + + if (length(primary) == 0) {primary <- NA} + + category_pairs <- list( + "fishing_mortality" = "Fmort", + "recruitment" = "Recruitment", + "catch" = "Catch", + "spawning_biomass" = "Spawners", + "abundance" = "Abundance", # aka biomass + "index" = "Index" + ) + + primary <- unlist(lapply(primary, function(x) category_pairs[[x]])) + + ts_dat_filled <- all_summaries |> + 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(Primary = ifelse(tolower(Category) == primary, "Y", "")) |> + dplyr::mutate(Description = dplyr::case_when( + Category == "Abundance" ~ "Total Abundance", + Category == "Spawners" ~ as.character(assmt_dat$Value[assmt_dat$Variable == "AS_B_BASIS"]), + Category == "Recruitment" ~ "Recruits - Age 1", + Category == "Fmort" ~ as.character(assmt_dat$Value[assmt_dat$Variable == "AS_F_BASIS"]), + Category == "Index" ~ "Estimated Index", + Category == "Catch" ~ "Estimated Total Catch", + TRUE ~ NA + )) |> + dplyr::mutate(Unit = dplyr::case_when( + Category == "Abundance" ~ "Number of Fish", + Category == "Spawners" ~ as.character(assmt_dat$Value[assmt_dat$Variable == "AS_B_UNIT"]), + Category == "Recruitment" ~ ifelse(kqs$value[kqs$key_quantity == "recruitment.units"] == "mt", "Metric Tons", kqs$value[kqs$key_quantity == "recruitment.units"]), + Category == "Fmort" ~ as.character(assmt_dat$Value[assmt_dat$Variable == "AS_F_UNIT"]), + Category == "Index" ~ "", + Category == "Catch" ~ ifelse(kqs$value[kqs$key_quantity == "tot.catch.units"] == " (mt)", "Metric Tons", kqs$value[kqs$key_quantity == "tot.catch.units"]), + 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.") + } + + # if assmt_dat$Value is NA and Default is 95, change it to Default + for (i in seq_len(nrow(assmt_dat))) { + if (is.na(assmt_dat$Value[i]) & assmt_dat$Default[i] == 95) { + 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): ") + if (tolower(overwrite) == "y") { + write.csv(assmt_dat, assmt_dat_path, row.names = FALSE) + write.csv(ts_dat_filled, ts_dat_path, row.names = FALSE) + cli::cli_alert_success("Files overwritten successfully.") + } else { + cli::cli_alert_info("Files not overwritten. Please rename the files, then rerun this function to save the data extracted in this function.") + } + } else { + write.csv(assmt_dat, assmt_dat_path, row.names = FALSE) + write.csv(ts_dat_filled, ts_dat_path, row.names = FALSE) + cli::cli_alert_success("Files saved successfully in {sis_data_dir}.") + } + + #TODO: show an example of a filled-out template +} diff --git a/inst/WORDLIST b/inst/WORDLIST index 7062e059..cc30343c 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -19,6 +19,7 @@ Subseason aa alttext asar +assmt bam birthseas cha diff --git a/inst/resources/sis_assmt_template.csv b/inst/resources/sis_assmt_template.csv new file mode 100644 index 00000000..67fc2593 --- /dev/null +++ b/inst/resources/sis_assmt_template.csv @@ -0,0 +1,75 @@ +Variable,Explanation,Optional,Default,Value +model_identifier,"Argument used to distinguish between base model and a new, updated model sent in subsequent submission. Options: 'base', 'updated_model_1', 'updated_model_2', etc.",YES,base, +AS_POINT_OF_CONTACT,"The lead/corresponding author for a stock assessment, formatted as an email address.",NO,None, +AS_CATCH_DATA,"Categorical classification describing the availability of catch data for use in the stock assessment. This level should be based on the data that was actually used in the final version of the assessment model. Options: 0 (No quantitative catch data available), 1 (Some catch data, but major gaps for some fishery sectors or historical periods), 2 (Enough catch data to establish magnitude/trends for a major fishery sector for data-limited methods or closed fisheries), 3 (Catch data generally available for all sectors, but some gaps exist), 4 (No data gaps substantially impede assessment, but catch is not without uncertainty), 5 (Very complete knowledge of total catch).",NO,None, +AS_ABUNDANCE_DATA,"Categorical classification describing the availability of abundance data for use in the stock assessment. This level should be based on the data that was actually used in the final version of the assessment model. Options: 0 (No indicator of stock abundance/trend), 1 (Fishery-dependent CPUE available with high uncertainty, or expert opinion), 2 (Fishery-dependent CPUE sufficiently standardized for full assessments; no/insufficient fishery-independent data), 3 (Limited fishery-independent survey(s) provide relative abundance; limited spatiotemporal coverage or high variability), 4 (Complete fishery-independent survey(s) provide relative abundance covering large spatial extent over several years), 5 (Calibrated fishery-independent survey(s) or tag-recapture provide absolute abundance).",NO,None, +AS_BIOLOGICAL_DATA,"Categorical classification describing the availability of biological/life history data for use in the stock assessment. This level should be based on the data that was actually used in the final version of the assessment model. Options: 0 (No life history data), 1 (Most life history factors not based on empirical data; derived using proxies/meta-analyses/borrowed), 2 (Some factors based on empirical data, but at least one derived via proxies/meta-analyses/borrowed), 3 (Most factors based on stock-specific empirical data), 4 (Data sufficient to track changes over time in at least growth), 5 (No major gaps in life history knowledge).",NO,None, +AS_ECOSYSTEM_DATA,"Categorical classification describing the usage of ecosystem linkage data in the stock assessment. This level should be based on the data that was actually used in the final version of the assessment model. Options: 0 (No linkage/consideration of ecosystem dynamic/properties), 1 (Ecosystem-based hypotheses inform structure/inputs, but no explicit linkage to drivers), 2 (Includes some form of variability/effect to account for unidentified ecosystem dynamics), 3 (One or more features linked to dynamic data from environment, climate, habitat, or predator-prey), 4 (Linked to dynamic data supported directly by process studies), 5 (Configured to be coupled or linked with an ecosystem process).",NO,None, +AS_COMP_DATA,"Categorical classification describing the availability of size/age composition data for use in the stock assessment. This level should be based on the data that was actually used in the final version of the assessment model. Options: 0 (No composition data collected), 1 (Some collected, but major gaps and not used), 2 (Enough collected to enable data-limited approaches), 3 (Enough collected over sufficient time series to be informative in age/size structured models), 4 (Enough age composition collected over sufficient time series to enable age-structured methods), 5 (Very complete age and size composition data).",NO,None, +AS_MODEL_CAT,"Category of model used to complete the stock assessment (see Table 5.1; NOAA, 2018). Focuses on population dynamics structure, data requirements, and management advice types. If an ensemble approach was used, select the highest category describing one or more models in the ensemble. Options: 1 (Data-limited), 2 (Index-based), 3 (Aggregate Biomass Dynamics), 4 (Virtual Population Analysis), 5 (Statistical Catch-at-Length), 6 (Statistical Catch-at-Age).",NO,None, +AS_TYPE,"Type of stock assessment, with regards to approach, technique, effort level, and complexity (NOAA, 2018). Assigned automatically by SIS. Options: 'Research Stock Assessment' (development/revision of data type/method), 'Research/Operational Stock Assessment' (management advice + substantial revision), 'Operational Assessment' (scientific advice focusing on stock status/catch limits), 'Stock Monitoring Update' (stock-level advice between assessments without changes to methods/data).",NO,None, +AS_REVIEW_TYPE,"Final status of the assessment, chosen from a set of values found in the SIS manual. Options: 1 (Not Reviewed), 2 (Accept Previous Approach, Remand New Attempt), 3 (Full Acceptance), 4 (Partial Acceptance, Fishing Mortality Estimates), 5 (Partial Acceptance, Biomass Estimates), 6 (Partial Acceptance, Status Determinations Only), 7 (Reject, Data Insufficient for Assessment), 8 (Reject, Results Too Uncertain To Be Considered Accurate), 9 (Remand).",NO,None, +ASSESSMENT_ID,Unique numeric identifier assigned to all stock assessment records. Assigned automatically by SIS.,NO,None, +ENTITY_ID,Entity unique identifier value. Assigned automatically by SIS.,NO,None, +AS_YEAR,Year the assessment was completed. Assigned automatically by SIS.,NO,None, +AS_MONTH,Month the assessment was completed. Assigned automatically by SIS.,NO,None, +AS_LAST_DATA_YEAR,Year of the 'latest' data used in the assessment.,NO,Extracted as landings.end.year from key_quantities.csv, +AS_B_BASIS,"The basis of the biomass unit. Options: Spawning Stock Biomass, Total Stock Biomass, Survey-Estimated Biomass, Escapement, Stock Reproductive Output, Survey Index, Total Stock Abundance.",NO,None, +AS_F_BASIS,"The basis of the Fishing Mortality unit. Options: 1 (Max F at Age), 2 (F for Fully-Selected Fish), 3 (Catch / Biomass), 4 (Catch / Exploitable Biomass), 5 (Catch), 6 (Fishing Intensity), 7 (True F).",NO,None, +AS_FMSY,Estimated and/or calculated value of Fishing Mortality at MSY.,NO,Extracted as F.MSY.terminal from key_quantities.csv, +AS_F_BEST,"Best estimate of Fishing Mortality. Typically, Best F = Terminal F for the stock assessment unless transformed (e.g., averaging or retrospective adjustment).",NO,Extracted as F.terminal.est from key_quantities.csv, +AS_FLIMIT_BASIS,"Basis for the recommended fishing mortality limit, calculated or directly estimated. Only utilized in Alaska as assessments utilize catch projections in the current year. Most stocks utilize Flimit = Fmsy. Example: 'F from 2024 asmt corresponding to 2023 OFL'.",YES,NULL, +AS_B_YEAR,Year of the Biomass estimate for the stock.,NO,Extracted as B.terminal.year from key_quantities.csv, +AS_B_MAX,Maximum estimated value within the approved confidence interval of the Biomass estimate. Equivalent to the value of Best B Confidence Interval Upper estimate.,NO,Extracted as B.terminal.max from key_quantities.csv, +AS_BMSY,"Estimated stock size that would, on average, produce the maximum sustainable yield when fished at a level equal to FMSY.",NO,Extracted as B.msy from key_quantities.csv, +AS_B_BMSY_RATIO,Ratio of B / Bmsy. Automatically calculated by SIS.,YES,NULL, +AS_STOCK_LEVEL_BMSY,"Whether the stock is above, near, or below Bmsy based upon the value provided in the AS_B_BMSY_RATIO field. Options: 'Above', 'Near' (between 80% and 99%), 'Below' (<80%).",YES,NULL, +AS_B_MIN,Minimum estimated value within the approved confidence interval of the Biomass estimate. Equivalent to the value of Best B Confidence Interval Lower estimate.,NO,Extracted as B.terminal.max from key_quantities.csv, +AS_B_BEST,"Best estimate of Biomass. Typically, Best B = Terminal B for the stock assessment unless transformed (e.g., averaging or retrospective adjustment).",NO,Extracted as B.terminal.est from key_quantities.csv, +AS_BMSY_BASIS,Basis for the estimated BMSY value. Example: 'B35%'.,NO,None, +AS_FMSY_BASIS,"Estimated fishing mortality rate that, on average, would produce the maximum sustainable yield from a stock at BMSY. Example: 'F35% as proxy'.",NO,None, +AS_FLIMIT,"Recommended fishing mortality limit from the assessment, above which the stock would be considered to be experiencing overfishing.",NO,Extracted as F.limit from key_quantities.csv, +AS_F_YEAR,Terminal year estimate of stock Fishing Mortality. Always corresponds to the year of the Best estimate of Fishing Mortality (AS_F_BEST).,NO,Extracted as F.terminal.year from key_quantities.csv, +AS_F_UNIT,"Unit of measure corresponding to the fishing mortality estimate. Linked to F Basis selections. Options: 1 (Apical F = Max F at Age), 2 (Fully-selected F = F for Fully-Selected Fish), 3 (Exploitation Rate = Catch / Biomass), 4 (Relative F = Catch / Exploitable Biomass), 5 (Metric Tons = Catch), 6 (1 - SPR = Fishing Intensity), 7 (F = Z - M = True F).",NO,None, +AS_B_UNIT,"Unit of measure corresponding to the biomass estimate. Linked to B Basis selections. Options: 1 (Metric Tons = SSB / Total Biomass / Survey-Estimated Biomass), 2 (Thousand Metric Tons = SSB / Total Biomass / Survey-Estimated Biomass), 3 (Adult spawners - Natural & Hatchery - Escapement), 4 (Adult spawners - Hatchery - Escapement), 5 (Adult spawners - Natural - Escapement), 6 (Number of Eggs - Stock Reproductive Output), 7 (kg / tow - Survey Index), 8 (Number of Fish - Total Stock Abundance).",NO,None, +AS_MODEL,Model software package used to complete the final version of the assessment. Example: 'SS'.,NO,None, +AS_MODEL_VERSION,Version of the software package used to complete the final stock assessment. Example: '3.30.22'.,NO,None, +AS_ENSEMBLE_FLAG,"Whether the assessment was completed using an ensemble or multimodeling approach. Options: 'Y' (yes), 'N' (no).",NO,None, +AS_F_TRANSFORM,"Indicator identifying Fishing Mortality best estimates that include terminal year transformations (e.g., retrospective corrections or multi-year averaging). Options: 'Y' (yes), 'N' (no).",NO,None, +AS_B_RANGE_BASIS,"Approach used to calculate the confidence intervals provided for the stock assessment. Options: 'Asymptotic', 'Credible', 'Bootstrapped', user-specified.",YES,NULL, +AS_B_RANGE,Percentile range of the confidence intervals provided for the stock assessment.,YES,95, +AS_B_TRANSFORM,"Indicator identifying Biomass best estimates that include terminal year transformations (e.g., retrospective corrections or multi-year averaging). Options: 'Y' (yes), 'N' (no).",NO,None, +AS_F_MAX,Maximum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to Best F CI Upper estimate.,NO,Extracted as F.terminal.max from key_quantities.csv, +AS_F_MIN,Minimum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to Best F CI Lower estimate.,NO,Extracted as F.terminal.min from key_quantities.csv, +AS_F_RANGE_BASIS,"Approach used to calculate the confidence intervals provided for the stock assessment. Options: 'Asymptotic', 'Credible', 'Bootstrapped', user-specified.",YES,NULL, +AS_F_RANGE,Percentile range of the confidence intervals provided for the stock assessment.,YES,95, +AS_FMSY_MAX,Maximum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to Fmsy CI Upper estimate.,NO,Extracted as F.MSY.terminal.max from key_quantities.csv, +AS_FMSY_MIN,Minimum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to Fmsy CI Lower estimate.,NO,Extracted as F.MSY.terminal.min from key_quantities.csv, +AS_FMSY_RANGE_BASIS,"Approach used to calculate the confidence intervals provided for the stock assessment. Options: 'Asymptotic', 'Credible', 'Bootstrapped', user-specified.",YES,NULL, +AS_FMSY_RANGE,Percentile range of the confidence intervals provided for the stock assessment.,YES,95, +AS_FTARGET,Value of the Ftarget estimate produced by a stock assessment. Often used for stocks in a rebuilding plan.,NO,Extracted as F.target from key_quantities.csv, +AS_FTARGET_BASIS,Approach used to calculate the Ftarget estimate produced by a stock assessment.,NO,None, +AS_MSY,Value of the MSY estimated by the assessment.,NO,None, +AS_MSY_UNIT,"Unit associated with the MSY value. Options: Metric tons, Thousand metric tons, lbs, Thousand lbs, Number of fish.",NO,None, +AS_MSY_MAX,Maximum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to MSY CI Upper estimate.,NO,None, +AS_MSY_MIN,Minimum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to MSY CI Lower estimate.,NO,None, +AS_MSY_RANGE_BASIS,"Approach used to calculate the confidence intervals provided for the stock assessment. Options: 'Asymptotic', 'Credible', 'Bootstrapped', user-specified.",YES,NULL, +AS_MSY_RANGE,Percentile range of the confidence intervals provided for the stock assessment.,YES,95, +AS_BMSY_MAX,Maximum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to Bmsy CI Upper estimate.,NO,Extracted as B.msy.max from key_quantities.csv, +AS_BMSY_MIN,Minimum estimated value within the approved confidence interval of the Fishing Mortality estimate. Equivalent to Bmsy CI Lower estimate.,NO,Extracted as B.msy.min from key_quantities.csv, +AS_BMSY_RANGE_BASIS,"Approach used to calculate the confidence intervals provided for the stock assessment. Options: 'Asymptotic', 'Credible', 'Bootstrapped', user-specified.",YES,NULL, +AS_BMSY_RANGE,Percentile range of the confidence intervals provided for the stock assessment.,YES,95, +AS_BLIMIT,"Stock size threshold, below which the stock is considered to be overfished.",NO,None, +AS_BLIMIT_BASIS,"Basis for the Blimit estimate. Examples: (0.7*Bmsy), B25%, etc.",NO,None, +AS_B_COMMENT,"Specific comments associated with the best estimate of biomass for this assessment. 1,000 character limit.",NO,None, +AS_F_COMMENT,"Specific comments associated with the best estimate of fishing mortality for this assessment. 1,000 character limit.",NO,None, +AS_IAS_FLIMIT,International commission F limit estimate.,YES,NULL, +AS_IAS_FLIMIT_BASIS,International commission estimate of Flimit estimation method. Example: 'msy'.,YES,NULL, +AS_IAS_FMSY,International commission estimate of Fmsy.,YES,NULL, +AS_IAS_FMSY_BASIS,International commission estimate of Fmsy estimation method.,YES,NULL, +AS_IAS_FTARGET,International commission estimate of Ftarget.,YES,NULL, +AS_IAS_FTARGET_BASIS,International commission estimate of Ftarget estimation method.,YES,NULL, +AS_IAS_BLIMIT,International commission biomass limit estimate.,YES,NULL, +AS_IAS_BLIMIT_BASIS,International commission estimate of Blimit estimation method.,YES,NULL, +AS_IAS_BMSY,International commission estimate of Bmsy.,YES,NULL, +AS_IAS_BMSY_BASIS,International commission estimate of Bmsy estimation method.,YES,NULL, \ No newline at end of file diff --git a/inst/resources/sis_ts_template.csv b/inst/resources/sis_ts_template.csv new file mode 100644 index 00000000..a74c1ad5 --- /dev/null +++ b/inst/resources/sis_ts_template.csv @@ -0,0 +1 @@ +Year,Category,Primary,Description,Unit,Value diff --git a/man/extract_sis_data.Rd b/man/extract_sis_data.Rd new file mode 100644 index 00000000..8ea31a73 --- /dev/null +++ b/man/extract_sis_data.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/extract_sis_data.R +\name{extract_sis_data} +\alias{extract_sis_data} +\title{Extract data from model results to send to SIS} +\usage{ +extract_sis_data( + sis_data_dir = getwd(), + key_quantities_dir = getwd(), + figures_tables_dir = getwd() +) +} +\arguments{ +\item{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.} + +\item{key_quantities_dir}{Path. Location of the existing key_quantities.csv file. + +Default: The working directory.} + +\item{figures_tables_dir}{Path. Location of the existing 'figures' and 'tables' directories. + +Default: The working directory.} +} +\description{ +Semi-automate the extraction of key quantities from model results for eventual transmittance to SIS via `asar::export_to_sis()`. +} +\details{ +This function acts within the following workflow: + +1. When a stock assessment is scheduled to conclude, SIS will generate an + attachment or prompt containing metadata and identifiers. +2. The user will open two csv files containing placeholders for all of the data required by SIS: sis_assmt_template.csv (assessment summary data) and sis_ts_template.csv (time series data). There are three ways to obtain these files: +2a. Run `stockplotr::extract_sis_data()`, which will generate, populate, and export the templates with data originating from a converted model results file. +2b. Generate blank files by running `asar::create_blank_sis()`. +2c. Locate blank files in the "report" folder generated by running `asar::create_template()`. +3. The user will add the remaining necessary data into the csv files, ensuring that all required fields are completed. +4. Run `export_to_sis()`, which will format and upload this data to a specific Google Drive folder. +5. The uploaded contents will be resubmitted to SIS to finalize the record. +} +\examples{ +\dontrun{ +extract_sis_data( + sis_data_dir = getwd(), + key_quantities_dir = "my_dir", + figures_tables_dir = "my_other_dir" +) +} + +}