RMarkdown and Quarto documents are “dynamic analysis documents that combine code, rendered output (such as figures), and prose”. Since everything in R is an object, lots of R objects (numbers, charts, tables, statistical models, etc.) are created while rendering the document. In large documents, it can be difficult to keep track with where and when these objects are created which sometimes makes debugging a cumbersome and time consuming job.
However, in this blog post, I will show how to use lists to improve clarity throughout the document. Let me give you an example:
Creating a list with named objects
In R, a “list” itself is an object and can be created using the native list() function. In the following code snippet, we save list as an object (“lst.a”) and add one named object which is numeric (‘nmb.1’). The str()function shows all objects our list contains.
lst.a <- list(
nmb.1 = 10
)
str(lst.a)
## List of 1 ## $ nmb.1: num 10
Reusing objects
Next, we try to create a new list and check whether it’s possible to use one object (‘nmb.1’) to compute another object (‘nmb.2’):
lst.b <- list(
nmb.1 = 10,
nmb.2 = nmb.1 + 10
)
## Error: ## ! object 'nmb.1' not found
As we can see, the list() function cannot create objects and reuse them at the same time. Fortunately, the {tibble} package contains the lst() function which is able to do so:
lst.b <- tibble::lst(
nmb.1 = 10,
nmb.2 = nmb.1 + 10
)
str(lst.b)
## List of 2 ## $ nmb.1: num 10 ## $ nmb.2: num 20
Saving plots in lists
Unfortunately, base R plots cannot be saved as object and, thus, cannot be put into a list. When we evaluate the following line of Rcode, we see that the plot() function is evaluated immediately (as a side effect). The object it was assigned to remains empty (“NULL”).
lst.c <- list(
plt = plot(1:10)
)

lst.c$plt
## NULL
However, the {ggplot2} package produces plots which can be assigned to objects and, thus, can be put into lists.
lst.d <- list(
ggplt = data.frame(x = 1:10, y = 1:10) %>% ggplot(aes(x, y)) + geom_point()
)
lst.d$ggplt

Statistical models, data.frames etc.
It probably doesn’t come as a surprise that many more objects can be put into a list. In the following example, we us the ‘mtcars’ data.frame to build a simple linear model explaining horsepower (hp) by miles per gallon (mpg). At the same time, we put this model into a list (‘lst.e’) both as a list (‘mdl.lm’) and a tibble.
put a linear model explaining horsepower (hp) by miles per gallon (mpg) both as a list and a tibble (‘tib.lm’).
lst.e <- lst(
mdl.lm = lm(hp ~ mpg, data = mtcars),
tib.lm = broom::tidy(mdl.lm)
)
str(lst.e, list.len = 5)
## List of 2 ## $ mdl.lm:List of 12 ## ..$ coefficients : Named num [1:2] 324.08 -8.83 ## .. ..- attr(*, "names")= chr [1:2] "(Intercept)" "mpg" ## ..$ residuals : Named num [1:32] -28.7 -28.7 -29.8 -25.1 16 ... ## .. ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ... ## ..$ effects : Named num [1:32] -829.8 296.3 -23.6 -20 19.3 ... ## .. ..- attr(*, "names")= chr [1:32] "(Intercept)" "mpg" "" "" ... ## ..$ rank : int 2 ## ..$ fitted.values: Named num [1:32] 139 139 123 135 159 ... ## .. ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ... ## .. [list output truncated] ## ..- attr(*, "class")= chr "lm" ## $ tib.lm: tibble [2 x 5] (S3: tbl_df/tbl/data.frame) ## ..$ term : chr [1:2] "(Intercept)" "mpg" ## ..$ estimate : num [1:2] 324.08 -8.83 ## ..$ std.error: num [1:2] 27.43 1.31 ## ..$ statistic: num [1:2] 11.81 -6.74 ## ..$ p.value : num [1:2] 8.25e-13 1.79e-07
Using lists with RMarkdown and Quarto
Finally, we are going to save everything into a single list and put the list elements into a text.
lst.final <- lst(
nmb.1 = nrow(mtcars),
nmb.2 = ncol(mtcars),
ggplt = mtcars %>% ggplot(aes(x = hp, y = mpg)) +
geom_point() + geom_smooth(method='lm', se = FALSE) + ggthemes::theme_clean(),
mdl.lm = lm(hp ~ mpg, data = mtcars),
tib.lm = broom::tidy(mdl.lm, conf.int = TRUE)
)
Putting text and R code together
This is just an example text showing how to put text and code into:
The ‘mtcars’ dataset consists of
lst.final$nmb.1rows andlst.final$nmb.2columns.
Rendering to:
The ‘mtcars’ dataset consists of 32 rows and 11 columns.
The relation between horsepower and miles per gallon is visualised in the following figure:
lst.final$ggplt

Statistical models can be easily put into a table using the {gtsummary} package:
library(gtsummary)
tbl_regression(lst.final$mdl.lm, intercept = TRUE) %>%
as_hux_table()
| Characteristic | Beta | 95% CI | p-value |
|---|---|---|---|
| (Intercept) | 324 | 268, 380 | <0.001 |
| mpg | -8.8 | -12, -6.2 | <0.001 |
| Abbreviation: CI = Confidence Interval | |||