From 225345f0ad51ea78bf7e921efb9d12847cfc14f8 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Mon, 28 Sep 2026 11:28:18 -0400 Subject: [PATCH 1/9] feat: plot of SPR timeseries Dynamically plot timeseries of SPR quantities. Valid quantities include SPR, fishing intensity (1-SPR), or SPR Ratio (a potentially user defined SPR quantity. --- R/plot_spr.R | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index a49c8728..fffb1627 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -1,6 +1,15 @@ #' Plot spawning potential ratio (SPR) #' #' @inheritParams plot_spawning_biomass +#' @param quantity String. SPR quantity to plot. +#' +#' Default: "spr". +#' +#' Options: "spr", "fishing_intensity", or "spr_ratio". +#' +#' "spr" plots spawning potential ratio. "fishing_intensity" plots 1-SPR. +#' "spr_ratio" plots quantity associated with SPRratio label (may be user +#' specified in some models; e.g., Stock Synthesis). #' #' @returns A plot showing spawning potential ratio (SPR). #' @@ -16,6 +25,7 @@ #' @examples #' plot_spr( #' dat = stockplotr:::example_data, +#' quantity = "spr", #' unit_label = "metric tons", #' group = "fleet", #' interactive = FALSE, @@ -23,6 +33,7 @@ #' ) #' plot_spr( #' dat = stockplotr:::example_data, +#' quantity = "spr_ratio #' unit_label = "metric tons", #' facet = "fleet", #' interactive = FALSE, @@ -30,6 +41,7 @@ #' ) plot_spr <- function( dat, + quantity = c("spr", "fishing_intensity", "spr_ratio"), geom = "line", group = NULL, facet = NULL, @@ -41,11 +53,15 @@ plot_spr <- function( figures_dir = getwd(), ... ) { + + quantity <- match.arg(quantity) + label_filter <- ifelse(quantity=="spr_ratio", "^spawning_potential_ratio", "spr") + # Filter data for spr prepared_data <- filter_data( dat = dat, - label_name = "^spawning_potential_ratio", + label_name = label_filter, geom = geom, #TODO: change this to era once stockplotr::example_data updated era = NULL, @@ -88,14 +104,13 @@ plot_spr <- function( if (!is.null(group)) { if (group %notin% colnames(prepared_data)) group <- NULL } - - # Extract ref_line value - #TODO: update this once ref_line PR merged - if (is.null(names(ref_line))){ - ref_pt <- calculate_reference_point( - dat = dat, - reference_name = glue::glue("spawning_potential_ratio_{ref_line}") - ) + + # calculate fishing intensity on the fly as 1-SPR + if(quantity=="fishing_intensity"){ + prepared_data <- prepared_data %>% + mutate( + estimate = 1-estimate, + ) } # inital base plot @@ -112,9 +127,19 @@ plot_spr <- function( color = "grey") + ggplot2::geom_hline(yintercept = 0, color = "grey") + - ggplot2::geom_hline(yintercept = ref_pt, - color = "red") + + # ggplot2::geom_hline(yintercept = ref_pt, + # color = "red") + theme_noaa() + + plt <- reference_line( + plot = plt, + dat = dat, + lbs = FALSE, + label_name = "spawning_potential_ratio", + reference = ref_line, + scale_amount = 1 + ) + theme_noaa() + if (length(unique(prepared_data$group_var)) == 1) { plt <- plt + ggplot2::theme(legend.position = "none") From 6c3d0d774193bf5f0fb5d74a446c6a4a8a7da9dd Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Mon, 28 Sep 2026 11:31:38 -0400 Subject: [PATCH 2/9] feat: Custom y-axis labels for plot_spr Allow user to specify y-axis label in `plot_spr`. This is important so users can ammend the default labels, esepcially when SPR quantities are user defined. --- R/plot_spr.R | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index fffb1627..f0936b42 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -10,6 +10,8 @@ #' "spr" plots spawning potential ratio. "fishing_intensity" plots 1-SPR. #' "spr_ratio" plots quantity associated with SPRratio label (may be user #' specified in some models; e.g., Stock Synthesis). +#' +#' @param ylab String. Y-axis label to show. #' #' @returns A plot showing spawning potential ratio (SPR). #' @@ -29,7 +31,8 @@ #' unit_label = "metric tons", #' group = "fleet", #' interactive = FALSE, -#' make_rda = FALSE +#' make_rda = FALSE, +#' ylab = "SPR" #' ) #' plot_spr( #' dat = stockplotr:::example_data, @@ -37,7 +40,8 @@ #' unit_label = "metric tons", #' facet = "fleet", #' interactive = FALSE, -#' make_rda = FALSE +#' make_rda = FALSE, +#' ylab = "(1-SPR)/(1-SPR_ref)" #' ) plot_spr <- function( dat, @@ -51,6 +55,7 @@ plot_spr <- function( interactive = TRUE, make_rda = FALSE, figures_dir = getwd(), + ylab = NULL, ... ) { @@ -75,10 +80,15 @@ plot_spr <- function( dplyr::filter(!is.na(year)) # set y axis label - if (unique(prepared_data$label) == "spawning_potential_ratio_ratio"){ - spr_label <- "Relative Fishing Intensity: (1-SPR)/(1-SPR_50%)" - } else { - spr_label <- "Spawning Potential Ratio" + # default values if ylab not provided + if(is.null(ylab)){ + if(quantity=="spr"){ + ylab <- "SPR (Spawning Potential Ratio)" + }else if(quantity=="fishing_intensity"){ + ylab <- "Fishing Intensity (1-SPR)" + }else{ + ylab <- "SPR Ratio" + } } @@ -118,7 +128,7 @@ plot_spr <- function( dat = prepared_data, y = "estimate", geom = geom, - ylab = spr_label, + ylab = ylab, group = group, facet = facet, ... From e54debeb1efce8ef18cb46b69eff48dc285caed7 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Mon, 28 Sep 2026 11:31:59 -0400 Subject: [PATCH 3/9] test: tests for plot_spr --- tests/testthat/test-plot-spr.R | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/testthat/test-plot-spr.R diff --git a/tests/testthat/test-plot-spr.R b/tests/testthat/test-plot-spr.R new file mode 100644 index 00000000..339ff3c9 --- /dev/null +++ b/tests/testthat/test-plot-spr.R @@ -0,0 +1,54 @@ +test_that("plot_spr generates plots without errors", { + # expect error-free plot with minimal arguments + expect_no_error( + plot_spr(stockplotr::example_data, quantity="spr"), + ) + + expect_no_error( + plot_spr(stockplotr::example_data, quantity="fishing_intensity") + ) + + expect_no_error( + plot_spr(stockplotr::example_data, quantity="spr_ratio") + ) + + + # expect error-free plot with many arguments + expect_no_error( + plot_spr( + stockplotr::example_data, + quantity = "spr_ratio", + ref_line = "biomass_target" + ) + ) + + + # expect ggplot object is returned + expect_s3_class( + plot_spr( + stockplotr::example_data, + ref_line = c("target" = 0.80) + ), + "gg" + ) +}) + +test_that("rda file made when indicated", { + # export rda + plot_spr( + stockplotr::example_data, + ref_line = "biomass_target", + module = "DERIVED_QUANTITIES", + 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", "spr_figure.rda"))) + + # erase temporary testing files + file.remove(fs::path(getwd(), "captions_alt_text.csv")) + file.remove(fs::path(getwd(), "key_quantities.csv")) + unlink(fs::path(getwd(), "figures"), recursive = T) +}) From acddf378d53f9066c0de03da2c14bb37d1fe99e5 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Tue, 29 Sep 2026 12:42:42 -0400 Subject: [PATCH 4/9] refactor: simplified spr vs 1-spr calculation 1-spr is stored as "spr_report" within the SPR_SERIES module. Removed the explicit recalculation of it, and added "spr_report" explicitly to the label filter. --- R/plot_spr.R | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index f0936b42..1e1a46ce 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -60,8 +60,12 @@ plot_spr <- function( ) { quantity <- match.arg(quantity) - - label_filter <- ifelse(quantity=="spr_ratio", "^spawning_potential_ratio", "spr") + + label_filter <- switch(quantity, + "spr"="spr$", # only get SPR from SPR_SERIES + "fishing_intensity"="spr_report$", # spr_report is apparently 1-SPR + "spr_ratio"="^spawning_potential_ratio" + ) # Filter data for spr prepared_data <- filter_data( @@ -82,13 +86,11 @@ plot_spr <- function( # set y axis label # default values if ylab not provided if(is.null(ylab)){ - if(quantity=="spr"){ - ylab <- "SPR (Spawning Potential Ratio)" - }else if(quantity=="fishing_intensity"){ - ylab <- "Fishing Intensity (1-SPR)" - }else{ - ylab <- "SPR Ratio" - } + ylab <- switch(quantity, + "spr"="SPR (Spawning Potential Ratio)", + "fishing_intensity"="Fishing Intensity (1-SPR)", + "spr_ratio"="SPR Ratio" + ) } @@ -115,14 +117,6 @@ plot_spr <- function( if (group %notin% colnames(prepared_data)) group <- NULL } - # calculate fishing intensity on the fly as 1-SPR - if(quantity=="fishing_intensity"){ - prepared_data <- prepared_data %>% - mutate( - estimate = 1-estimate, - ) - } - # inital base plot plt <- plot_timeseries( dat = prepared_data, @@ -131,7 +125,7 @@ plot_spr <- function( ylab = ylab, group = group, facet = facet, - ... + # ... ) + ggplot2::geom_hline(yintercept = 1, color = "grey") + From 671ed48aa1712874f4ebfee4edf60bf698543944 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Tue, 29 Sep 2026 15:32:24 -0400 Subject: [PATCH 5/9] feat: added correct key quantities for correct caption/alt text formatting --- R/plot_spr.R | 16 +++++++++++++--- inst/resources/captions_alt_text_template.csv | 2 +- inst/resources/key_quantity_template.csv | 3 +++ tests/testthat/test-plot-spr.R | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index 1e1a46ce..67cb91c8 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -153,25 +153,35 @@ plot_spr <- function( if (make_rda) { # TODO: Update caption, alt text, and quantities once plot is finalized # Obtain relevant key quantities for captions/alt text + spr.quantity <- switch(quantity, + "spr"="spawning potential ratio (SPR) (SB~current~/SB~unfished~)", + "fishing_intensity"="fishing intensity (1-SPR) (1-SB~current~/SB~unfished~)", + "spr_ratio"="relative fishing intensity (1-SPR)/(1-SPR~target~)" + ) + 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.quantity, spr.start.year, spr.end.year, spr.min, - spr.max + spr.ref.pt ) # Add key quantities to captions/alt text insert_kqs( + spr.quantity, spr.start.year, spr.end.year, spr.min, - spr.max + spr.max, + spr.ref.pt ) create_rda( diff --git a/inst/resources/captions_alt_text_template.csv b/inst/resources/captions_alt_text_template.csv index 3ccf825b..7d4b0f82 100644 --- a/inst/resources/captions_alt_text_template.csv +++ b/inst/resources/captions_alt_text_template.csv @@ -26,7 +26,7 @@ recruitment_deviations,figure,Annual deviations (on natural log scale) in the nu tot.b,figure,Estimated biomass (B) time series. The horizontal dashed line represents the biomass limit reference point at B.ref.pt B.units.,"Line graph showing estimated biomass time series. The x axis shows the year, which spans from B.start.year to B.end.year. The y axis shows estimated biomass in B.units, which spans from B.min to B.max." spawning_biomass,figure,Estimated spawning biomass (SB) time series. The horizontal dashed line represents the spawning biomass associated with the biomass limit reference point (ssb.ref.pt ssb.units).,"Line graph showing estimated spawning biomass. The x axis shows the year, which spans from ssb.start.year to ssb.end.year. The y axis shows estimated spawning biomass in ssb.units, which spans from ssb.min to ssb.max." relative.spawning.biomass,figure,Estimated relative spawning biomass time series. The horizontal dashed line represents the limit reference point calculated as SB/SB(reference point) (ssb.ref.pt ssb.units).,"Line graph showing estimated relative spawning biomass. The x axis shows the year, which spans from ssb.start.year to ssb.end.year. The y axis shows estimated relative spawning biomass (SB/SB~target~), which spans from rel.ssb.min to rel.ssb.max ssb.units." -spr,figure,Estimated spawning potential ratio (SPR) (SB~current~/SB~target~) time series. The horizontal dashed line represents the spawning potential ratio of the limit reference point at spr.ref.pt.,"Line graph showing estimated spawning potential ratio over time. The x axis shows the year, which spans from ssb.start.year to ssb.end.year. The y axis shows estimated spawning potential ratio in SB~current~/SB~target~, which spans from spr.min to spr.max." +spr,figure,Estimated spawning potential ratio (SPR) (SB~current~/SB~target~) time series. The horizontal dashed line represents the spawning potential ratio of the target reference point at spr.ref.pt.,"Line graph showing estimated spr.quantity over time. The x axis shows the year, which spans from spr.start.year to spr.end.year. The y axis shows estimated spr.quantity, which spans from spr.min to spr.max." biomass_at_age,figure,Estimated population numbers at age and population biomass at age over time. The relative size of each bubble for a given year and age indicates the relative abundance or biomass in that category compared with others. ,"Bubble plot showing estimated population numbers at age and population biomass at age. The x axis shows the year, which spans from pop.baa.start.year to pop.baa.end.year. The y axis shows age, which spans from pop.baa.age.min to pop.baa.age.max. The size of the bubbles range from pop.baa.fish.min to pop.baa.fish.max." proj.catch,figure,Forecasted catch in proj.catch.units over future years for different fishing mortality scenarios as indicated in the legend.,"Time series line graph showing forecasted catch over future years for different fishing mortality scenarios. The x axis shows the year, which spans from proj.catch.start.year to proj.catch.end.year. The y axis shows catch in proj.catch.units, which spans from proj.catch.min to proj.catch.max." proj.biomass,table,Forecasted biomass over future years for different fishing mortality scenarios., diff --git a/inst/resources/key_quantity_template.csv b/inst/resources/key_quantity_template.csv index 69a40c36..1c6ff43b 100644 --- a/inst/resources/key_quantity_template.csv +++ b/inst/resources/key_quantity_template.csv @@ -105,6 +105,9 @@ selectivity.length.max,,maximum length for gear selectivity,,,, selectivity.length.min,,minimum length for gear selectivity,,,, selectivity.length.units,,units for selectivity length,,,, selectivity.start.year,,start year for selectivity estimates,,,, +spr.quantity,,type of spawning potential ratio quantity calculated,,,, +spr.start.year,,start year of SPR timeseries,,,, +spr.end.year,,end year of SPR timeseries,,,, spr.max,,maximum spawning potential ratio,,,, spr.min,,minimum spawning potential ratio,,,, spr.ref.pt,,spawning potential ratio reference point,,,, diff --git a/tests/testthat/test-plot-spr.R b/tests/testthat/test-plot-spr.R index 339ff3c9..f6501d0a 100644 --- a/tests/testthat/test-plot-spr.R +++ b/tests/testthat/test-plot-spr.R @@ -37,7 +37,7 @@ test_that("rda file made when indicated", { # export rda plot_spr( stockplotr::example_data, - ref_line = "biomass_target", + ref_line = "msy", module = "DERIVED_QUANTITIES", make_rda = TRUE, figures_dir = getwd() From 36821c313a67e8bc0c8aa4f057952d3572f456c4 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Tue, 29 Sep 2026 16:12:04 -0400 Subject: [PATCH 6/9] Remove unit_label Co-authored-by: Sophie Breitbart --- R/plot_spr.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index 67cb91c8..6384ede7 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -192,7 +192,7 @@ plot_spr <- function( dat = dat, dir = figures_dir, scale_amount = scale_amount, - unit_label = unit_label +scale_amount = scale_amount ) } # Output final plot From 911c42e3d6ca8b0b8f89a8e40f7bc1fbc4974ad5 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Wed, 30 Sep 2026 11:21:36 -0400 Subject: [PATCH 7/9] refactor: rename to plot_spawning_potential_ratio --- R/plot_spr.R | 6 +++--- ...-spr.R => test-plot_spawning_potential_ratio.R} | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) rename tests/testthat/{test-plot-spr.R => test-plot_spawning_potential_ratio.R} (71%) diff --git a/R/plot_spr.R b/R/plot_spr.R index 67cb91c8..e720028c 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -25,7 +25,7 @@ #' @export #' #' @examples -#' plot_spr( +#' plot_spawning_potential_ratio( #' dat = stockplotr:::example_data, #' quantity = "spr", #' unit_label = "metric tons", @@ -34,7 +34,7 @@ #' make_rda = FALSE, #' ylab = "SPR" #' ) -#' plot_spr( +#' plot_spawning_potential_ratio( #' dat = stockplotr:::example_data, #' quantity = "spr_ratio #' unit_label = "metric tons", @@ -43,7 +43,7 @@ #' make_rda = FALSE, #' ylab = "(1-SPR)/(1-SPR_ref)" #' ) -plot_spr <- function( +plot_spawning_potential_ratio <- function( dat, quantity = c("spr", "fishing_intensity", "spr_ratio"), geom = "line", diff --git a/tests/testthat/test-plot-spr.R b/tests/testthat/test-plot_spawning_potential_ratio.R similarity index 71% rename from tests/testthat/test-plot-spr.R rename to tests/testthat/test-plot_spawning_potential_ratio.R index f6501d0a..91ae4b8f 100644 --- a/tests/testthat/test-plot-spr.R +++ b/tests/testthat/test-plot_spawning_potential_ratio.R @@ -1,21 +1,21 @@ -test_that("plot_spr generates plots without errors", { +test_that("plot_spawning_potential_ratio generates plots without errors", { # expect error-free plot with minimal arguments expect_no_error( - plot_spr(stockplotr::example_data, quantity="spr"), + plot_spawning_potential_ratio(stockplotr::example_data, quantity="spr"), ) expect_no_error( - plot_spr(stockplotr::example_data, quantity="fishing_intensity") + plot_spawning_potential_ratio(stockplotr::example_data, quantity="fishing_intensity") ) expect_no_error( - plot_spr(stockplotr::example_data, quantity="spr_ratio") + plot_spawning_potential_ratio(stockplotr::example_data, quantity="spr_ratio") ) # expect error-free plot with many arguments expect_no_error( - plot_spr( + plot_spawning_potential_ratio( stockplotr::example_data, quantity = "spr_ratio", ref_line = "biomass_target" @@ -25,7 +25,7 @@ test_that("plot_spr generates plots without errors", { # expect ggplot object is returned expect_s3_class( - plot_spr( + plot_spawning_potential_ratio( stockplotr::example_data, ref_line = c("target" = 0.80) ), @@ -35,7 +35,7 @@ test_that("plot_spr generates plots without errors", { test_that("rda file made when indicated", { # export rda - plot_spr( + plot_spawning_potential_ratio( stockplotr::example_data, ref_line = "msy", module = "DERIVED_QUANTITIES", From 251f40292c9dffe6a0a56fac5f2fc1b368428119 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Wed, 30 Sep 2026 11:22:37 -0400 Subject: [PATCH 8/9] fix: account for user specifying multiple SPR quantities Set SPR quantity to default value ("spr") if user specified more than 1 quantity in function call. --- R/plot_spr.R | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index e720028c..66552838 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -59,7 +59,10 @@ plot_spawning_potential_ratio <- function( ... ) { - quantity <- match.arg(quantity) + if (length(quantity) > 1) + quantity <- "spr" + else + quantity <- match.arg(quantity) label_filter <- switch(quantity, "spr"="spr$", # only get SPR from SPR_SERIES @@ -125,14 +128,12 @@ plot_spawning_potential_ratio <- function( ylab = ylab, group = group, facet = facet, - # ... + ... ) + ggplot2::geom_hline(yintercept = 1, color = "grey") + ggplot2::geom_hline(yintercept = 0, color = "grey") + - # ggplot2::geom_hline(yintercept = ref_pt, - # color = "red") + theme_noaa() plt <- reference_line( From 42e78143ec1a1e408f7f98efff250328a852b085 Mon Sep 17 00:00:00 2001 From: Joshua Zahner Date: Wed, 30 Sep 2026 11:51:56 -0400 Subject: [PATCH 9/9] fix: remove scale_amount from .rda file creation Co-authored-by: Sam (Schiano) Bredeck <125507018+Schiano-NOAA@users.noreply.github.com> --- R/plot_spr.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/plot_spr.R b/R/plot_spr.R index c4181562..02345d53 100644 --- a/R/plot_spr.R +++ b/R/plot_spr.R @@ -193,7 +193,7 @@ plot_spawning_potential_ratio <- function( dat = dat, dir = figures_dir, scale_amount = scale_amount, -scale_amount = scale_amount +scale_amount = 1 ) } # Output final plot