# Identify output file
output_file <- here::here("example_output", "Report.sso")
# convert the output and save it as an rda
petrale <- asar::convert_output(output_file,
save_dir = getwd())Day 3
Objectives
- Walk through an example of a plot and table from
stockplotr - Learn about the value of the
stockplotrR package - Understand how to integrate
stockplotrinto anasar-based reporting workflow
Introduction
Icebreaker
Welcome! Please open the Day 3 communal notes doc and participate in the icebreaker exercise.
Reminder: For comments or questions, please raise your hand, or write them in the chat, at any time. Depending on our schedule, we may ask that you save larger questions for breaks.
Materials for today’s lesson
- Day 3 communal notes doc
- Contains resources (from us and you!) and areas for note-taking
- Sample data
- Sample model output data for coding demonstrations
- Example figure
- Example figure for coding demonstration
Installation
asar, stockplotr, and tinytex should already be installed if you attended Days 1 or 2. If not, please install these packages by following the instructions in the pre-workshop checklist.
Introduction to stockplotr
Convert output (if necessary)
First, you’ll need to convert your model results using the same workflow covered yesterday: asar::convert_output().
You can use the example Report.sso file uploaded to the workshop GitHub or, if you have a compatible output file, your own.
If you have already converted your output: great! Import it into your R environment so that you can handle it as an object like “petrale” in the chunk above.
Package information
This package is an ongoing process to gather contributions in order to expand the number of pre-made tables and figures that can be incorporated into a stock assessment report. All objects are intended to be generalized and not specific to any region.
The following table contains figures and tables that are available in stockplotr:
| Function | Description |
|---|---|
plot_abundance_at_age() |
abundance-at-age |
plot_biomass_at_age() |
biomass-at-age |
plot_biomass() |
biomass time series |
plot_catch_comp() |
catch compositions |
plot_fishing_mortality |
fishing mortality time series |
plot_indices() |
indices |
plot_landings() |
landings time series |
plot_natural_mortality() |
natural mortality time series or at-age |
plot_recruitment_deviations() |
recruitment deviations |
plot_recruitment() |
recruitment time series |
plot_spawn_recruitment() |
spawn recruitment relationship |
plot_spawning_biomass() |
spawning biomass time series |
table_landings() |
landings time series by fleet or other indexing |
table_bnc() |
biomass, landings, and catch time series |
table_harvest_projection() |
harvest projection table according to SAFE standards (to be expanded nationally) |
tables_indices() |
indices by fleet |
Each automated function returns either a ggplot2 object (figure) or flextable object (table). This allows for further customization of the output if desired by using the notation you are familiar with. For a figure, you can continue to add onto the plot any other ggplot2 function or extension using the plus (+) operator. For a table, please use the native pipe (|>) when adding additional formatting, rows, or other pieces to the object.
Example Figure
Run the example below. It should result in a line graph showing biomass over time, including a reference line for the biomass unfished.
stockplotr::plot_biomass(
dat = petrale,
geom = "line",
group = NULL,
facet = NULL,
ref_line = "unfished",
unit_label = "mt",
scale_amount = 1,
relative = FALSE,
interactive = TRUE,
module = NULL
)
Customizing
All figures will automatically identify any indexing variables in the data such as fleet, area, or sex. You can use the group and facet arguments to modify how these indexing variables are displayed in the figure. You can also modify other arguments such as geom, ref_line, and relative to change the appearance of the figure.
Here are some examples of how to customize the biomass figure:
Change the reference line to a specific value (e.g., 260)
In this example we are also telling the function which module to select in order to by-pass this step. We plan to remove grouping of some modules in the future.
stockplotr::plot_biomass(
dat = petrale,
geom = "line",
group = NULL,
facet = NULL,
ref_line = c("target" = 260),
unit_label = "mt",
scale_amount = 1,
relative = FALSE,
# interactive = TRUE,
module = "TIME_SERIES"
)
Plot relative biomass and change the size of the line
In this example, we still are bypassing module selection and we are automatically extracting the reference line value from the data. However, now we are using this reference value to plot relative biomass and changing the linewidth to 2 (an argument inherited from ggplot2).
stockplotr::plot_biomass(
dat = petrale,
geom = "line",
group = NULL,
facet = NULL,
ref_line = c("target" = 260),
unit_label = "mt",
scale_amount = 1,
relative = TRUE,
# interactive = TRUE,
module = "TIME_SERIES",
linewidth = 2
)
The only extended arguments available are the ones found from the ggplot2::geom_XX() function. Thus, any indexed variables can not be changes such as color to fill. Please see the documentation for ggplot2 geom functions for these additional arguments.
Summarize our data
Notice that you can remove the reference line by setting ref_line = NULL.
stockplotr::plot_biomass(
dat = petrale,
geom = "line",
group = "none",
facet = NULL,
ref_line = NULL,
unit_label = "mt",
scale_amount = 1,
relative = FALSE,
# interactive = TRUE,
module = "TIME_SERIES"
)
Remember that figures return ggplot2 objects, so we can make additional customization to these plots.
stockplotr::plot_biomass(
dat = petrale,
geom = "line",
group = "fleet",
facet = NULL,
ref_line = c("target" = 5690),
unit_label = "mt",
scale_amount = 1,
relative = FALSE,
# interactive = TRUE,
module = "TIME_SERIES"
) +
ggplot2::geom_vline(xintercept = 2005, linetype = "dashed", color = "red")
Example Table
Run the following example table. The result is a fully report ready table showing landings over time. Remember that these are exported as flextable objects and can be edited as such.
stockplotr uses the native pipe (|>), so if you decide to customize you table, please also use the native pipe to avoid errors.
# not sure what this will exactly look like so this is a place holder
stockplotr::table_landings(
dat = petrale,
group = "fleet",
unit_label = "mt",
module = NULL
)Next, we can add some different formatting:
stockplotr::table_landings(
dat = petrale,
group = "fleet",
unit_label = "mt",
module = NULL
) |>
flextable::footnote(
i = 6, # row
j = 2, # column
value = flextable::as_paragraph(
"This is an example table from the workflows workshop. Not intended for official use."
)
)or potentially highlight a specific line within the table:
stockplotr::table_landings(
dat = petrale,
group = "fleet",
unit_label = "mt",
module = NULL
) |>
flextable::footnote(
i = 6, # row
j = 2, # column
value = flextable::as_paragraph(
"Not intended for official use."
)
) |>
flextable::bg(
i = 5,
bg = "lightblue",
part = "body"
)rda file
An rda is an R data file that stores R objects and preserves their structure. In this case, you can think of an rda file exported from stockplotr as a list of objects.
Each plot or table has the option to export it as an rda. This rda is a list of 3 associated components for the plot/table to be used in a stock assessment report:
- ggplot or flextable object
- caption
- alternative text (figures only)
- latex object (tables only)
stockplotr::plot_biomass(
dat = petrale,
ref_line = c("target" = 260),
unit_label = "mt",
module = "TIME_SERIES",
make_rda = TRUE,
tables_dir = getwd()
)load("figures/biomass_figure.rda")
rda$figure
rda$cap
rda$alt_textstockplotr::table_landings(
dat = petrale,
group = "fleet",
unit_label = "mt",
make_rda = TRUE,
tables_dir = getwd()
)load("tables/landings_table.rda")
rda$table
rda$cap
rda$latexWe have designed two functions that allow you to automatically create all available figures and tables:
save_all_plots()html_all_figs_tables()
stockplotr figures & tables
For the following, use stockplotr::example_data as the input data.
- Create an abundance-at-age plot. Export it as an rda to your working directory.
- Create a recruitment time series plot. Change the
unit_labelandscale_amountso that the y axis shows recruitment in thousands of fish. Setmodule= “TIME_SERIES”. - Create a fishing mortality plot. Ensure it does not group by fleet. Set
module= “TIME_SERIES”. Add a reference line (“target”) at 0.5. Convert it from a line plot to a scatterplot. - Create a landings table.
Now, use your own data.
- Convert your own dataset using
convert_output(). - Create a spawning biomass plot. Change the theme by applying the
ggplot2::theme_classic().
stockplotr figures & tables
For the following, use stockplotr::example_data as the input data.
- Create an abundance-at-age plot. Export it as an rda to your working directory.
Answer:
stockplotr::plot_abundance_at_age(
dat = stockplotr::example_data,
make_rda = TRUE,
figures_dir = getwd()
)- Create a recruitment time series plot. Change the
unit_labelandscale_amountso that the y axis shows recruitment in thousands of fish. Setmodule= “TIME_SERIES”.
Answer:
stockplotr::plot_recruitment(
dat = stockplotr::example_data,
unit_label = "fish",
scale_amount = 1000,
module = "TIME_SERIES"
)- Create a fishing mortality plot. Ensure it does not group by fleet. Set
module= “TIME_SERIES”. Add a reference line (“target”) at 0.5. Convert it from a line plot to a scatterplot.
Answer:
stockplotr::plot_fishing_mortality(
dat = stockplotr::example_data,
group = "none",
module = "TIME_SERIES",
ref_line = c("target" = 0.5),
geom = "point"
)- Create a landings table.
Answer:
stockplotr::table_landings(
dat = stockplotr::example_data
)Now, use your own data.
- Convert your own dataset using
convert_output().
Answer:
convert_output(
file = "path/to/your_report_file"
# Specify these arguments if you wish: model, fleet_names, save_dir
)- Create a spawning biomass plot. Change the theme by applying the
ggplot2::theme_classic().
Answer:
stockplotr::plot_spawning_biomass(
dat = your_converted_data_object
) +
ggplot2::theme_classic()Integrating stockplotr in the workflow
For the second half of today’s lesson, let’s reorient ourselves. We’ve just learned how to make figures and tables with stockplotr. Now, we’ll cover how to add those plots into your asar report template.
Remember that after running the primary asar function– create_template()- you have a ‘report’ folder with several files in it. These files include the report skeleton; the child documents containing the executive summary, introduction, results, and so on; and, importantly for us right now, the documents that will contain code to display your figures and tables. The files will be named something like ‘08_tables.qmd’ and ‘09_figures.qmd’ (the prefix numbers may vary).
Each file will contain zero figures or tables. Instead, they will contain a statement referring you to {stockplotr} so that you can make your own. Since we’ve created those already, let’s add them to your report!
Adding tables and figures to your report
You can add your figures and tables with two workflows:
- Rerunning
asar::create_tables_doc()andasar::create_figures_doc()
- If you fill in arguments that allow R to find your tables and figures, then it will place them into the respective tables and figures docs automatically.
- Adding your tables and figures manually to each doc.
Option 1: Rerunning asar::create_tables_doc()/asar::create_figures_doc()
This is also known as the rda-based workflow.
Tables
To add tables, first ensure that your folder containing the tables is called “tables”.
Then, there are only two arguments to fill out:
subdir: The location where the new tables doc should be saved (we recommend your ‘report’ folder, so it overwrites the old, empty version)tables_dir: The location of your “tables” folder
create_tables_doc(
subdir = fs::path(getwd(), "report"), # indicates the new tables doc will be saved in your "report" folder, located in the working directory
tables_dir = getwd() # indicates your "tables" folder is located in the working directory
)Now, open your new tables doc and take a look!
You’ll notice the following structure:
Chunk 1 will always create an object saving the location of your tables_dir.
Then, there will be at least two chunks for each table. For tables that are regularly-sized (i.e., small enough that they don’t need to be rotated or split across pages):
Chunk 2 will:
- load an rda containing a table
- give the rda a specific name
- save the table and caption as separate objects
Chunk 3 will:
- display the table
This workflow can also accommodate tables that are wide enough to require rotation into a landscape-view page OR splitting across pages. For more information, please see the “Adding Custom Tables & Figures” vignette.
Figures
Adding figures entails nearly the same process as described for tables. The only differences are:
- Figures will involve captions and alternative text, whereas tables only require captions
- Figures do not require the option to be rotated or split across pages.
Option 2: Manually adding tables/figures
Tables
You can add a regularly-sized1 table/figure manually by following these main steps:
- Create a code chunk
- Add your label and other chunk options
- Add code
- Write caption
- Add a page break between tables (optional but recommended)
Direct coding-in-qmd table workflow
Example from the “Adding Custom Tables & Figures” vignette:
```{r}
#| label: 'tbl-custom1' # choose a label
#| tbl-cap: !expr This is your table caption.
# Import your data
petrale <- load(fs::path("std_output.rda"))
# Make your table
your_table <- head(petrale) |>
dplyr::select(label, year, estimate) |>
flextable::flextable()
# Show your table
your_table
``` 
Then, add a pagebreak:
{{< pagebreak >}}It will be important to add your captions and labels into a csv file when making your documents accessible. You will soon learn more about this in the the “Adding accessibility features” section!
Direct image-based table insertion workflow
We don’t recommended adding tables as images, since it significantly reduces the accessibility of your table. However, we understand that sometimes this is the only format available.
Use the following notation to reference an external table as an image:
{fig-alt="This is the alternative text for my table", #tbl-example}
Notice how there is alternative text added to this method of adding a table. In this scenario, the table is recognized as an image and thus would NOT pass accessibility checks. Please make sure you add alternative text for image-based tables added in this way.
Figures
Direct coding-in-qmd figure workflow
Like with tables, running create_figures_doc() produces a blank figures quarto file. We add figures similarly to tables. In fact, the only major difference is that you must write alternative text for your figure.
Put your alternative text in a chunk option called ‘fig-alt’ (example below).
```{r}
#| label: 'fig-custom1' # choose a label
#| fig-cap: !expr This is your figure caption.
#| fig-alt: !expr This is your figure alternative text.
# Import your data
load(fs::path("std_output.rda"))
petrale <- out_new |>
dplyr::filter(year > 1980) |>
dplyr::filter(module_name == "TIME_SERIES") |>
dplyr::filter(label == "biomass") |>
dplyr::filter(!is.na(fleet))
# Make your figure
your_figure <- ggplot2::ggplot(petrale,
ggplot2::aes(x = year, y = estimate, color = fleet)) +
ggplot2::geom_line(linewidth = 0.75) +
ggplot2::geom_point() +
ggplot2::theme_classic()
# Show your figure
your_figure
``` 
Even though you wrote alt text in the fig-alt area, when you first render your report into a PDF, your alternative text will not show up in your document. Strange, right?! To ensure it shows up, refer to the “Adding accessibility features” section (which we’ll discuss in a moment).
Direct image-based figure insertion workflow
Like tables, you can reference figures not made directly in code chunks. However, in this case, this does not change the accessibility of the figure because you can still add the necessary components to meet Section 508 compliance standards: alternative text and a caption.
{fig-alt="This is the alternative text for my figure", #fig-example}
Referencing your tables or figures in text
Quarto uses a special notation to allow users to link tables and figures throughout their text. Use the following notation to link/reference tables in your text:
@tbl-exampleor
@fig-exampleAdding an @ symbol followed by the chunk label, or label of your table/figure, will create an interactive link that lets the reader navigate to that specific table/figure.
Render your first report draft!
Open your skeleton qmd file, then render the report.
You can render a report in three ways:
In the R console
Run quarto::quarto_render([path/to/your/skeleton.qmd file]) in the console. For example:
quarto::quarto_render(
here::here("report",
"SAR_species_skeleton.qmd") # add your skeleton filename
)In the terminal
Run quarto render [path/to/your/skeleton.qmd file] in the terminal. For example:
Enter quarto render report/SAR_species_skeleton.qmd
- Ensure that you have a ‘figures’ folder and a ‘tables’ folder, each with at least one rda file. If you don’t, export a couple of figures and tables.
- Hint: ensure that the
make_rdaargument is set to TRUE when running thestockplotrfunctions that create figures and tables).
- Hint: ensure that the
- Open up your figures and tables qmds, in the ‘report’ folder. If these documents do not contain the necessary chunks to import and display at least one plot, rerun
create_figures_doc()and/orcreate_tables_doc()to add code that will plot the figures/tables in your ‘figures’ and ‘tables’ folders.- Hint: ensure that the arguments are correct:
subdirandfigures_dir(for the figures doc) /tables_dir(for the tables doc) - Hint: This step practices the “rda-based workflow”.
- Hint: ensure that the arguments are correct:
- Practice adding a figure with markdown notation by adding the image of a landings figure into the figures doc. The figure is located in the ‘example_plots’ folder. Set the caption to “Historical landings by fleet.”, the alternative text to “Cumulative line plot showing historical landings for North and South fleets. The x axis shows the year, which spans from 1850 to 2026. The y axis shows landings in metric tons, which spans from 0 to 2,400.”, and the figure label to “practice-figure-label”.
- Hint: This step practices the “direct image-based workflow”.
- In the Executive Summary, add a reference to the first figure in your figures qmd file.
- Practice adding a figure with markdown notation by adding the image of a landings figure into the figures doc. The figure is located in the ‘example_plots’ folder. Set the caption to “Historical landings by fleet.”, the alternative text to “Cumulative line plot showing historical landings for North and South fleets. The x axis shows the year, which spans from 1850 to 2026. The y axis shows landings in metric tons, which spans from 0 to 2,400.”, and the figure label to “practice-figure-label”. Hint: This step practices the “direct image-based workflow”.
Answer: Add the following chunk to the figures doc:
{fig-alt="Cumulative line plot showing historical landings for North and South fleets. The x axis shows the year, which spans from 1850 to 2026. The y axis shows landings in metric tons, which spans from 0 to 2,400.", #practice-figure-label}- In the Executive Summary, add a reference to the first figure in your figures qmd file.
Answer: If the ‘label’ for that first figure is ‘fig-custom1’, then the in-text reference would be ‘@fig-custom1’.
Adding accessibility features
You’ve made major progress towards completing your first report!
While your rendered report looks superb, it’s probably missing two major components: tags and alternative text.
If you made an HTML-based report, these features would most likely be in your document. But since we’re prioritizing PDFs, there are a few more steps to take before your document will significantly more accessible than it is now. This means that, to achieve compliance with Section 508 criteria, you must complete a couple more tasks.
Add tagging
In your ‘report’ folder, you’ll find a new file with a .tex filetype: ‘SAR_species_skeleton.tex’ (or something similar). This file is a LaTex-based version of your rendered skeleton qmd file. It’s also where we add our remaining accessibility features, since Quarto does not yet offer that functionality within its qmd files.
Tags are structural elements of PDFs. They are signals telling software which information are headers, images, tables, text, and so on. Tags allow people using technology like screen readers to logically navigate PDFs.
We’ll use the asar::add_tagging() function to add tags.
Notice that we are using the withr::with_dir() function as a wrapper for add_tagging(). This allow us to set the “report” folder as a temporary working directory, which is essential for the function to work. Likewise, if you set the “report” folder as the working directory, you could remove this wrapper and add_tagging() would succeed.
path <- getwd()
withr::with_dir(
file.path(path, "report"),
asar::add_tagging(
x = "SAR_species_skeleton.tex", # your .tex report file
dir = getwd(), # the location of the .tex file
compile = FALSE # whether the .tex file should be compiled after tagging. We'll set it to FALSE for now
)
)Now your PDF is tagged! If you compiled your .tex file, it’d look something like this. The tags are on the right side of the PDF viewer.

If you stop here (i.e., you don’t add your own alt text), this function will add the image paths as alt text. We’ll show you how to add your intended alt text in the next step.
Add alternative text
You must add alternative text (“alt text”) for images in a separate csv if you added figures using any of the workflows described above.
Since you’ve used stockplotr to make some figures, you’ve already completed the first step: making a csv that will contain your alt text.
Look at your alt text csv
The file, “captions_alt_text.csv”, should be located in your working directory (enter getwd() if you forget where that is). Open it up.
The file is set up like this:
- Column 1 (“label”) is a shorthand label for your figure or table. Labels should be somewhat short and exclude spaces. Examples include “kobe”, “relative.biomass”, and “fishing.mortality”.
- Column 2 (“type”) contains “figure” or “table”.
- Column 3 (“caption”) contains your caption.
- Column 4 (“alt_text”) contains alternative text for figures. For tables, this column will be blank.
| label | type | caption | alt_text |
|---|---|---|---|
| example_fig | figure | Example caption for figure. | Example alternative text for figure. |
| example_tab | table | Example caption for table. |
Update the csv
Your job is to:
- edit existing entries for your figures already created with
stockplotr. This entails checking the accuracy, and writing the final component, of the existing alt text. - add entries for your custom figures.
Editing existing entries
Using the “label” column, find the row associated with your figure and inspect it.
You’ll see that there’s already some prewritten alt text (in the “alt_text” column) that includes data from the model results file. Now, you must check this information for accuracy and update it where necessary (especially if the default figures were modified).
If you see text that looks like a placeholder (e.g., “The x axis, showing the year, spans from B.start.year to B.end.year…”), that means that there was at least one instance where our tool failed to extract a specific value from the model results, calculate a key quantity (like the start year of a biomass plot- aka “B.start.year”), and substitute it into the placeholder.
While we have extracted key quantities as accurately as possible, we cannot guarantee that each quantity will have been calculated perfectly. Input data varies widely. It’s your responsibility to check the accuracy of your figures’ alt text.
- This prewritten alt text usually contains 3/4 essential ingredients for well-written alt text. The remaining ingredient (#4): the relationship between the variables shown (i.e., what the figure is conveying). Since we can’t program
stockplotrto analyze the figure’s meaning, you must provide this crucial component.
When you’re satisfied, save the csv.
Adding new entries
- Make a new row.
- For “label”, take the “label” of your figure chunk. For example, in the example above, the label would be “fig-custom1”.
- The type will be “figure”.
- The caption should be identical to the caption in your chunk (what you put in “fig-cap”).
- The “alt_text” will contain your alt text. See the “Editing existing entries” section above, and the “Achieve Greater Accessibility” vignette, for help writing alt text.
When you’re satisfied, save the csv.
Add alt text to your report’s images
Now, we’ll use the asar::add_alttext() function to add the alt text into the report’s .tex file. Again, we’ll wrap the function with with_dir() to set a temporary working directory.
path <- getwd()
withr::with_dir(
file.path(path, "report"),
add_alttext(
x = "SAR_species_skeleton.tex", # your .tex report file
dir = getwd(), # the location of the .tex file
alttext_csv_dir = getwd(), # the location of your "captions_alt_text.csv"
figures_dir = path, # location of your "figures" folder
compile = TRUE # now we'll compile the PDF
)
)Now your PDF’s figures have alt text! You can find and edit the alt text by following these steps:



If you haven’t already, add tags to your pdf by running
add_tagging()with the appropriate arguments (includingcompileset to TRUE). Then, open up the report and ensure it was tagged.Open up the “captions_alt_text.csv” file that contains your alternative text and captions. Find the rows that are linked with the figures and tables in your report.
- Read through the captions and alternative text. Edit inaccuracies if necessary.
- For figures, add a sentence or two describing the final ingredient for a solid alternative text: the relationship between the variables shown (i.e., what the figure is conveying).
- If you’ve created custom figures/tables, create new rows for each. Add captions for all, and alternative text for just figures. Ensure that the label matches the chunk label.
Run
add_alttext()withcompileset to TRUE. Then, open up the report and ensure the images contain alt text.
Questions, comments, and feedback
Please navigate to the Feedback heading and tell us what you thought about today’s workshop. Only 3 simple questions!
- What went well?
- What could be improved?
- What is a question you still have?
Footnotes
Again, for tables that require rotating or splitting across pages, please refer to the “Adding Custom Tables & Figures” vignette.↩︎
