The main way to create tables and figures for your asar
report is by using functions within the satf
package.
However, if satf
doesn’t contain the functions to make
tables or figures you need, you may wish to add custom tables or figures
to your report. Here, we provide multiple workflow options for doing
so.
Option |
Summary |
Appropriate if... |
Pros |
Cons |
---|---|---|---|---|
1: direct image insertion workflow |
In this workflow, you will take minimal steps to add an external file to your report in this format: |
- You don't need to package your table/figure, caption, and alternative text in a single file |
- Faster process than option 2 |
- Less reproducible |
2: rda-based workflow |
In this workflow, you will make an rda containing your table/figure, caption, and alternative text, then add each into your report in the same way that non-custom tables/figures are added. |
- You'd like to create and save your custom tables/figures in a manner that's most consistent with your other tables/figures generated with asar's complementary R package, satf |
- More reproducible |
- Slower process than options 1 & 3 |
3: direct coding-in-qmd workflow |
In this workflow, you will code, and plot, your table or figure directly in a Quarto document. |
- You don't need to package your table/figure, caption, and alternative text in a single file |
- Faster process than option 2 |
- Less reproducible |
Using the direct image insertion workflow (option 1)? Skip this step and proceed to the Write captions and alternative text section.
First, write the code to produce (but not export; that’s a future
step!) your custom tables and figures. Save each table and figure as an
object (e.g., in the examples below, your_table
and
your_figure
). Save the script somewhere safe.
# Example dataframe
your_df <- data.frame(
"x" = c(1, 2, 3),
"y" = c(4, 5, 6)
)
# Example table
your_table <- flextable::flextable(your_df)
# Example figure
your_figure <- ggplot2::ggplot(
your_df,
aes(
x = x,
y = y
)
) +
ggplot2::geom_point()
Next, once you know what your tables and figures look like, write your own captions and alternative text. Custom tables will require captions only.
Check out the satf
‘captions_alt_text_template.csv’
file, which contains the templates for each table or figure’s
caption/alternative text, to get a sense of how each description is
structured. Then, refer to the
accessibility vignette’s guide to learn how to write clear and
comprehensive alternative text.
We recommend adding in key quantities, like maximum and minimum
values, to ensure your captions and alternative text clearly describe
your plots. For example, if you’re showing how biomass changed over
time, we recommend providing the maximum and minimum values of biomass
and years shown, instead of simply stating that a figure shows biomass
changing over time. Check out the code within the
satf::write_captions()
function to see how we extract
certain key quantities from the model results files. You are welcome to
use and adapt that code to your own results to calculate key quantities,
or calculate the quantities with your own code.
Using the direct image insertion workflow (option 1)? Skip this step and proceed to Set up Quarto markdown (.qmd) files to display custom tables and figures.
Using the direct coding-in-qmd workflow (option 3)? Skip this step and proceed to Identify table width, orientation, and if splitting is necessary.
Once written, you’ll have to save your captions and alternative text.
Do you have an existing captions_alt_text.csv file? If you’ve already
generated a figure or table rda, this file should exist, most likely in
your working directory. If you don’t have one, run
satf::write_captions()
or another satf
plotting function (e.g., plot_biomass()
,
table_bnc()
) to generate the file.
Open captions_alt_text.csv file, then add your text. The file is set up like this:
label | type | caption | alt_text |
---|---|---|---|
example_fig | figure | Example caption for figure. | Example alternative text for figure. |
example_tab | table | Example caption for table. |
Next, export your tables and figures to rda files. This code was
adapted from functions like satf::plot_biomass
.
Import your csv containing your captions and alternative text and save it as an object. Then, save the captions and alternative text as separate objects. For example:
# Import captions and alternative text
my_text <- read.csv(file = "captions_alt_text.csv")
# Extract table caption
my_table_cap <- my_text |>
dplyr::filter(
label == "example_table",
type == "table"
) |>
dplyr::select(caption) |>
as.character()
# Extract figure caption
my_figure_cap <- my_text |>
dplyr::filter(
label == "example_fig",
type == "figure"
) |>
dplyr::select(caption) |>
as.character()
# Extract figure alternative text
my_figure_alt_text <- my_text |>
dplyr::filter(
label == "example_fig",
type == "figure"
) |>
dplyr::select(alt_text) |>
as.character()
NOTE: Your label must match the label associated with your table or figure in your csv containing the captions and alternative text. If it does not match, the label will not be extracted properly and added to your rdas.
Your rdas will contain your table or figure, caption, and alternative text (if it’s a figure).
rda <- list(
"table" = your_table, # your table object
"cap" = my_table_cap # your table caption
)
rda <- list(
"figure" = your_figure, # your figure object
"cap" = my_figure_cap, # your figure caption
"alt_text" = my_figure_alt_text # your figure alternative text
)
Do you already have an rda_files folder? Hint: it should be in your working directory. If yes: Great! You can skip this step. If not, simply enter the code below to make an rda_files folder.
dir.create(fs::path(getwd(), "rda_files"))
Skip this section if you are not including custom tables.
Your next step is to get a sense of your table dimensions. You’ll ask:
This section contains the steps to answer these questions.
NOTE: This workflow is reflected in the create_tables_doc.R file and its associated functions (such as
render_lg_table()
, which has its own synonymous R file, andID_tbl_width_class()
andexport_split_tbls()
, which are found in the utils.R file).
Run this code:
my_plot_name <- "example_tab_table.rda" # replace this with the filename of your table rda
rda_dir <- getwd() # replace this with the location of your rda_files folder
ID_tbl_width_class(
plot_name = my_plot_name,
rda_dir = rda_dir,
portrait_pg_width = 5 # 5 inches = the threshold for maximum table width before it needs to be resized, rotated, and/or split
)
You will see one of three outputs: regular, wide, or extra-wide.
Classification | Regular | Wide | Extra-wide |
Table width | < 5” | at least 5” and up to 12” | >12” |
If your output is regular, this means that you can display your table in a .qmd chunk without any additional steps. Jump to section Set up Quarto markdown (.qmd) files to display custom tables and figures and proceed.
If your output is wide, this means that you will place your table’s .qmd chunk in special braces that change the page orientation to landscape. Jump to section Set up Quarto markdown (.qmd) files to display custom tables and figures and proceed.
If your output is extra-wide, this means that you will place your table’s .qmd chunk in special braces that change the page orientation to landscape and split it into narrower tables, each of which are displayed on separate pages. Proceed to the section Table splitting (for extra-wide tables only).
Assuming your table is saved as a flextable, run this code:
# assuming your flextable object is called my_flextable
flextable::flextable_dim(my_flextable)[["widths"]] |>
as.numeric()
Refer to the table above in above section (rda-based workflow (option 2)) to find out which category best describes your table width: regular, wide, or extra-wide.
If your table is regular or wide, read the text below the table and jump to the appropriate section.
If your table is extra-wide, please start over and use the rda-based workflow. This workflow is not built for the extra steps needed to split an extra-wide table into multiple smaller tables.
Extra-wide tables will need to be split among multiple pages. Run this code to learn the number of tables into which your original table will be split and export the split tables (as a list) into a new rda:
my_plot_name <- "example_tab_table.rda" # replace this with the filename of your table rda
rda_dir <- getwd() # replace this with the location of your rda_files folder
essential_cols <- 1:2 # replace this with the columns that will be retained between the split tables, formatted as a sequence (e.g., 1:2 for columns 1-2, or 1 for a single column)
export_split_tbls(
rda_dir = rda_dir,
plot_name = my_plot_name,
essential_columns = essential_cols
)
If the number returned was, say, 5, then since each split table must be in its own chunk, you will need 5 chunks to show your split tables. You will also need an additional chunk to load in the data. Each table needs its own chunk, and therefore label, so that it can be cross-referenced in text.
You can check out your split tables in the new rda saved in your rda_dir folder. It will have the same filename as your original rda except that it will contain “_split” in the filename. For instance, split tables created from “example_tab_table.rda” will be saved in “example_tab_table_split.rda”.
You will create one .qmd file for your tables and one .qmd file for your figures.
Open a blank .qmd script (in RStudio, click File -> New File -> Quarto Document -> Create Empty Document (button in the bottom left corner of the popup)).
Remove all text from the new document.
Switch from Visual to Source mode (instructions here).
Save this new file with a clear name in a logical location. We recommend filenames like 08_tables_custom.qmd and 09_figures_custom.qmd, then saving these files in the same report folder as the rest of your report files. We include separate workflows for tables and figures, below.
If you’re using this workflow, your table/figure should be at most 8” wide or can be shrunken to 8” wide and still be legible. Find the width of your image file. Would you prefer to show it on a page with a portrait orientation (can fit 5” width) or landscape orientation (can fit 8” width)?
Identify the preferred width of your image. Keep it in mind for when you add your image in the next section.
Next, add your image in this format (see this Quarto documentation for more information):
{fig-alt="Your alternative text here" width=___in #fig-your_image_label_name}
NOTE: It can be a headache to specify the correct image path. We recommend placing your files in either of these places:
Here are some examples, using the following example folder structure setup:
stock_assessments_2025/
├── captions_alt_text.csv
├── report/
│ ├── 01_executive_summary.qmd
│ ├── 02_introduction.qmd
│ ├── my_custom_figure.png
│ ├── images/
│ │ ├── my_custom_table.png
If you’d like to place your image on a landscape-oriented page, you’ll add landscape braces before and after your table/figure to ensure it will be displayed properly, like this:
{fig-alt="Your alternative text here" width=___in #fig-your_image_label_name}
Then, add three colons to close the braces:
If you are including more than one custom table or figure in a file, we suggest adding a page break to separate the tables/figures:
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom tables to your report.
In your tables doc, add your first R chunk (shown below). This chunk
is used to establish your rda_dir folder and load the library needed to
plot your tables (flextable
).
Click the following links to learn more about cross-references (label) and chunk options (echo, warning, etc.).
```{r}
#| label: 'set-rda-dir-tbls-custom' # you can set this label as you wish, as long as it's not repeated in any other R chunk in, for instance, the 08_tables.qmd or 09_figures.qmd files. Labels are used for cross-referencing in your report text.
#| echo: false
#| warning: false
#| include: false
library(flextable)
rda_dir <- "C:/path/to/your/rda_files" # set the path to your rda_dir
```
Now, follow the instructions in the appropriate section depending on your table width: regular, wide, or extra wide.
Add the following chunk to your script to import your table’s rda and save objects containing the table and caption:
```{r}
#| label: 'tbl-setup-custom1' # choose a label
#| echo: false
#| warning: false
#| include: false
# load your rda and save with a table-specific name, then delete "rda"
load(file.path(rda_dir, "example_tab_table.rda"))
example_table_rda <- rda
rm(rda)
# save table, caption as separate objects
example_table <- example_table_rda$table
example_cap <- example_table_rda$cap
```
Then, add this chunk to display the table in your .qmd when it’s rendered:
```{r}
#| label: 'tbl-custom1' # choose a label
#| echo: false
#| warning: false
#| tbl-cap: example_cap
example_table
```
If you are adding another table, regardless of size, add a page break first:
Keep adding as many tables as you’d like. Keep in mind that each table must have a chunk that imports it, and another chunk that displays it, as shown above.
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom tables to your report.
Add the following chunk to your script to import your table’s rda and save objects containing the table and caption:
```{r}
#| label: 'tbl-setup-custom1' # choose a label
#| echo: false
#| warning: false
#| include: false
# load your rda and save with a table-specific name, then delete "rda"
load(file.path(rda_dir, "example_tab_table.rda"))
example_table_rda <- rda
rm(rda)
# save table, caption as separate objects
example_table <- example_table_rda$table
example_cap <- example_table_rda$cap
```
Before you add your next chunk, add landscape braces to ensure your table will be displayed on a landscape-oriented page:
Then, add this chunk to display the table in your .qmd when it’s rendered:
```{r}
#| label: 'tbl-custom1' # choose a label
#| echo: false
#| warning: false
#| tbl-cap: example_cap
example_table |>
flextable::fit_to_width(max_width = 8) # this extra line ensures the table will be resized to a maximum of 8" wide
```
And add three colons to close the landscape braces:
If you are adding another table, regardless of size, add a page break first:
Keep adding as many tables as you’d like. Keep in mind that each table must have a chunk that imports it, and another chunk that displays it, as shown above.
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom tables to your report.
Add the following chunk to your script to:
```{r}
#| label: 'tbl-labels-custom1' # choose a label
#| echo: false
#| warning: false
#| include: false
# load your original table rda and save with a table-specific name, then delete "rda"
load(file.path(rda_dir, "example_tab_table.rda"))
example_table_rda <- rda
rm(rda)
# save caption as separate object
example_cap <- example_table_rda$cap
# load split table rda and save with a table-specific name, then delete "table_list"
load(file.path(rda_dir, "example_table_split.rda"))
example_table_rda_split <- table_list
rm(table_list)
# extract table caption specifiers
example_cap_split <- names(example_table_rda_split)
```
Example caption specifiers could include fleets only shown in specific tables.
Before you add your next chunk, add landscape braces to ensure your table will be displayed on a landscape-oriented page:
Now, you’ll add as many chunks as you have split tables. Here’s what the first one will look like:
```{r}
#| label: 'tbl-custom1' # choose a label
#| echo: false
#| warning: false
#| tbl-cap: paste0(example_cap, '(', example_cap_split[[1]], ')') # this pastes the original table caption with the specifiers associated with table 1
# plot split table 1
example_table_rda_split[[1]] |>
flextable::fit_to_width(max_width = 8) # this extra line ensures the table will be resized to a maximum of 8" wide
```
Copy and paste this chunk for as many split tables as you have. Then, replace the instances of “1” with the split table number (e.g., 2,3,4, etc.). In the example above, “1” occurs in the chunk options (label, tbl-cap) and the table-plotting code itself.
Now, add three colons to close the landscape braces:
Keep adding as many tables as you’d like. Keep in mind that each table must have a chunk that imports it, and another chunk that displays it, as shown above.
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom tables to your report.
The workflow for figures is very similar to the workflow for regular tables.
In your figures doc, add your first R chunk (shown below). This chunk is used to establish your rda_dir folder.
Click the following links to learn more about cross-references (label) and chunk options (echo, warning, etc.).
```{r}
#| label: 'set-rda-dir-figs-custom' # you can set this label as you wish, as long as it's not repeated in any other R chunk in, for instance, the 08_tables.qmd or 09_figures.qmd files. Labels are used for cross-referencing in your report text.
#| echo: false
#| warning: false
rda_dir <- "C:/path/to/your/rda_files" # set the path to your rda_dir
```
Add the following chunk to your script to import your figure’s rda and save objects containing the figure, caption, and alternative text:
```{r}
#| label: 'fig-setup-custom1' # choose a label
#| echo: false
#| warning: false
#| include: false
# load your rda and save with a figure-specific name, then delete "rda"
load(file.path(rda_dir, "example_fig_figure.rda"))
example_figure_rda <- rda
rm(rda)
# save figure, caption, and alternative text as separate objects
example_plot <- example_figure_rda$figure
example_cap <- example_figure_rda$cap
example_alt_text <- example_figure_rda$alt_text
```
Then, add this chunk to display the figure in your .qmd when it’s rendered:
```{r}
#| label: 'fig-custom1' # choose a label
#| echo: false
#| warning: false
#| fig-cap: example_cap
#| fig-alt: example_alt_text
example_plot
```
If you are adding another figure, add a page break first:
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom figures to your report.
Follow the instructions in the appropriate section depending on your table width: regular or wide.
Add the following chunk to display the table in your .qmd when it’s rendered:
```{r}
#| label: 'tbl-custom1' # choose a label
#| echo: false
#| warning: false
#| tbl-cap: This is your table caption.
# Import your data
your_df <- data.frame(
"x" = c(1, 2, 3),
"y" = c(4, 5, 6)
)
# Make your table
your_table <- flextable::flextable(your_df)
# Show your table
your_table
```
If you are adding another table, regardless of size, add a page break first:
Keep adding as many tables as you’d like. Keep in mind that each table must have a chunk that imports it, and another chunk that displays it, as shown above.
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom tables to your report.
Before you add your first chunk, add landscape braces to ensure your table will be displayed on a landscape-oriented page:
Then, add the following chunk to display the table in your .qmd when it’s rendered:
```{r}
#| label: 'tbl-custom1' # choose a label
#| echo: false
#| warning: false
#| tbl-cap: This is your table caption.
# Import your data
your_df <- data.frame(
"x" = c(1, 2, 3),
"y" = c(4, 5, 6)
)
# Make your table
your_table <- flextable::flextable(your_df) |>
flextable::fit_to_width(max_width = 8) # this extra line ensures the table will be resized to a maximum of 8" wide
# Show your table
your_table
```
And add three colons to close the landscape braces:
If you are adding another table, regardless of size, add a page break first:
Keep adding as many tables as you’d like. Keep in mind that each table must have a chunk that imports it, and another chunk that displays it, as shown above.
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom tables to your report.
The workflow for figures is very similar to the workflow for regular tables.
In your figures doc, add the following chunk to display the figure in your .qmd when it’s rendered:
```{r}
#| label: 'fig-custom1' # choose a label
#| echo: false
#| warning: false
#| fig-cap: This is your figure caption.
#| fig-alt: This is your figure alternative text.
# Import your data
your_df <- data.frame(
"x" = c(1, 2, 3),
"y" = c(4, 5, 6)
)
# Make your figure
your_figure <- ggplot2::ggplot(
your_df,
aes(
x = x,
y = y
)
) +
ggplot2::geom_point()
# Show your figure
your_figure
```
If you are adding another figure, add a page break first:
You’re almost done! Proceed to the last section (Update report skeleton) to finish adding your custom figures to your report.
Finally, the last step is to update the report skeleton so that it imports your new custom table and figure .qmd files.
Open your skeleton .qmd file. Scroll down to the chunks that contain tables and figures (their labels are “tables” and “figures”, respectively).
Your “tables” chunk will look similar, if not identical, to this:
```{r, results='asis'}
#| label: 'tables'
#| eval: true
#| echo: false
#| warning: false
a <- knitr::knit_child("08_tables.qmd", quiet = TRUE)
cat(a, sep = "\n")
```
If you are adding custom tables, copy the two lines of code that start with “a <- knitr::” and “cat”. Paste them below the original two lines of code in the same chunk. Then, in those two new lines, make the following changes:
For example:
```{r, results='asis'}
#| label: 'tables'
#| eval: true
#| echo: false
#| warning: false
a <- knitr::knit_child("08_tables.qmd", quiet = TRUE)
cat(a, sep = "\n")
b <- knitr::knit_child("08_tables_custom.qmd", quiet = TRUE)
cat(b, sep = "\n")
```
If you’re adding custom figures, follow the same steps with the figures chunk.
Save the changes to your skeleton, and you’re done! Your custom tables and figures will be included in your report.