Beautiful equations in R Markdown and Quarto

R
Package discovery
Author

Philippe Massicotte

Published

August 5, 2022

When writing dynamic documents in R (either R Markdown or Quarto), it can be useful to display model equations. I recently discovered equatiomatic, a very nice package that can do the job.

Photo by Artturi Jalli on Unsplash

The package can be installed from CRAN using install.packages("equatiomatic"). To explore the package’s functionalities, we will build a simple linear model using mtcars data (most examples are taken from the equatiomatic vignette website).

library(equatiomatic)

# Create a simple linear model
mod2 <- lm(mpg ~ ., mtcars)
broom::tidy(mod2)
#> # A tibble: 11 × 5
#>    term        estimate std.error statistic p.value
#>    <chr>          <dbl>     <dbl>     <dbl>   <dbl>
#>  1 (Intercept)  12.3      18.7        0.657  0.518 
#>  2 cyl          -0.111     1.05      -0.107  0.916 
#>  3 disp          0.0133    0.0179     0.747  0.463 
#>  4 hp           -0.0215    0.0218    -0.987  0.335 
#>  5 drat          0.787     1.64       0.481  0.635 
#>  6 wt           -3.72      1.89      -1.96   0.0633
#>  7 qsec          0.821     0.731      1.12   0.274 
#>  8 vs            0.318     2.10       0.151  0.881 
#>  9 am            2.52      2.06       1.23   0.234 
#> 10 gear          0.655     1.49       0.439  0.665 
#> 11 carb         -0.199     0.829     -0.241  0.812

There are different ways to display the model equation. The most basic way is to call the extract_eq() function. This will display the equation without the fitted coefficients.

\[ \operatorname{mpg} = \alpha + \beta_{1}(\operatorname{cyl}) + \beta_{2}(\operatorname{disp}) + \beta_{3}(\operatorname{hp}) + \beta_{4}(\operatorname{drat}) + \beta_{5}(\operatorname{wt}) + \beta_{6}(\operatorname{qsec}) + \beta_{7}(\operatorname{vs}) + \beta_{8}(\operatorname{am}) + \beta_{9}(\operatorname{gear}) + \beta_{10}(\operatorname{carb}) + \epsilon \]

As we can see, this equation is pretty long. It would be best to wrap it over multiple lines. This can be controlled using wrap = TRUE.

extract_eq(mod2, wrap = TRUE)

\[ \begin{aligned} \operatorname{mpg} &= \alpha + \beta_{1}(\operatorname{cyl}) + \beta_{2}(\operatorname{disp}) + \beta_{3}(\operatorname{hp})\ + \\ &\quad \beta_{4}(\operatorname{drat}) + \beta_{5}(\operatorname{wt}) + \beta_{6}(\operatorname{qsec}) + \beta_{7}(\operatorname{vs})\ + \\ &\quad \beta_{8}(\operatorname{am}) + \beta_{9}(\operatorname{gear}) + \beta_{10}(\operatorname{carb}) + \epsilon \end{aligned} \]

The number of terms per line is controlled with terms_per_line.

extract_eq(mod2, wrap = TRUE, terms_per_line = 2)

\[ \begin{aligned} \operatorname{mpg} &= \alpha + \beta_{1}(\operatorname{cyl})\ + \\ &\quad \beta_{2}(\operatorname{disp}) + \beta_{3}(\operatorname{hp})\ + \\ &\quad \beta_{4}(\operatorname{drat}) + \beta_{5}(\operatorname{wt})\ + \\ &\quad \beta_{6}(\operatorname{qsec}) + \beta_{7}(\operatorname{vs})\ + \\ &\quad \beta_{8}(\operatorname{am}) + \beta_{9}(\operatorname{gear})\ + \\ &\quad \beta_{10}(\operatorname{carb}) + \epsilon \end{aligned} \]

There is a lot of styling customization that can be performed.

extract_eq(mod2, wrap = TRUE, greek_colors = "red", subscript_colors = "blue")

\[ \begin{aligned} \operatorname{mpg} &= {\color{red}{\alpha}} + {\color{red}{\beta}}_{{\color{blue}{1}}}(\operatorname{cyl}) + {\color{red}{\beta}}_{{\color{blue}{2}}}(\operatorname{disp}) + {\color{red}{\beta}}_{{\color{blue}{3}}}(\operatorname{hp})\ + \\ &\quad {\color{red}{\beta}}_{{\color{blue}{4}}}(\operatorname{drat}) + {\color{red}{\beta}}_{{\color{blue}{5}}}(\operatorname{wt}) + {\color{red}{\beta}}_{{\color{blue}{6}}}(\operatorname{qsec}) + {\color{red}{\beta}}_{{\color{blue}{7}}}(\operatorname{vs})\ + \\ &\quad {\color{red}{\beta}}_{{\color{blue}{8}}}(\operatorname{am}) + {\color{red}{\beta}}_{{\color{blue}{9}}}(\operatorname{gear}) + {\color{red}{\beta}}_{{\color{blue}{10}}}(\operatorname{carb}) + {\color{red}{\epsilon}} \end{aligned} \]

One can use use_coefs = TRUE to extract the fitted coefficients.

extract_eq(mod2, wrap = TRUE, use_coefs = TRUE)

\[ \begin{aligned} \operatorname{\widehat{mpg}} &= 12.3 - 0.11(\operatorname{cyl}) + 0.01(\operatorname{disp}) - 0.02(\operatorname{hp})\ + \\ &\quad 0.79(\operatorname{drat}) - 3.72(\operatorname{wt}) + 0.82(\operatorname{qsec}) + 0.32(\operatorname{vs})\ + \\ &\quad 2.52(\operatorname{am}) + 0.66(\operatorname{gear}) - 0.2(\operatorname{carb}) \end{aligned} \]

Many types of models are supported by equatiomatic. Further information can be found on the equatiomatic website.

Session info
#> ─ Session info ───────────────────────────────────────────────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.1 (2022-06-23)
#>  os       Linux Mint 21
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language en_CA:en
#>  collate  en_CA.UTF-8
#>  ctype    en_CA.UTF-8
#>  tz       America/Montreal
#>  date     2022-08-10
#>  pandoc   2.18 @ /usr/lib/rstudio/bin/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────
#>  ! package      * version date (UTC) lib source
#>  P assertthat     0.2.1   2019-03-21 [?] RSPM
#>  P backports      1.4.1   2021-12-13 [?] RSPM
#>  P broom          1.0.0   2022-07-01 [?] RSPM (R 4.2.1)
#>  P cachem         1.0.6   2021-08-19 [?] RSPM (R 4.2.0)
#>  P callr          3.7.1   2022-07-13 [?] RSPM (R 4.2.1)
#>  P cli            3.3.0   2022-04-25 [?] RSPM (R 4.2.0)
#>  P crayon         1.5.1   2022-03-26 [?] RSPM (R 4.2.0)
#>  P DBI            1.1.3   2022-06-18 [?] RSPM (R 4.2.0)
#>  P devtools       2.4.4   2022-07-20 [?] RSPM (R 4.2.0)
#>  P digest         0.6.29  2021-12-01 [?] RSPM
#>  P dplyr          1.0.9   2022-04-28 [?] RSPM (R 4.2.0)
#>  P ellipsis       0.3.2   2021-04-29 [?] RSPM
#>  P equatiomatic * 0.3.1   2022-01-30 [?] RSPM (R 4.2.1)
#>  P evaluate       0.15    2022-02-18 [?] RSPM (R 4.2.0)
#>  P fansi          1.0.3   2022-03-24 [?] RSPM (R 4.2.0)
#>  P fastmap        1.1.0   2021-01-25 [?] RSPM
#>  P fs             1.5.2   2021-12-08 [?] RSPM
#>  P generics       0.1.3   2022-07-05 [?] RSPM (R 4.2.1)
#>  P glue           1.6.2   2022-02-24 [?] RSPM (R 4.2.0)
#>  P htmltools      0.5.3   2022-07-18 [?] RSPM (R 4.2.1)
#>  P htmlwidgets    1.5.4   2021-09-08 [?] RSPM (R 4.2.0)
#>  P httpuv         1.6.5   2022-01-05 [?] RSPM (R 4.2.0)
#>  P jsonlite       1.8.0   2022-02-22 [?] RSPM (R 4.2.0)
#>  P knitr          1.39    2022-04-26 [?] RSPM (R 4.2.0)
#>  P later          1.3.0   2021-08-18 [?] RSPM (R 4.2.0)
#>  P lifecycle      1.0.1   2021-09-24 [?] RSPM
#>  P magrittr       2.0.3   2022-03-30 [?] RSPM (R 4.2.0)
#>  P memoise        2.0.1   2021-11-26 [?] CRAN (R 4.2.0)
#>  P mime           0.12    2021-09-28 [?] RSPM
#>  P miniUI         0.1.1.1 2018-05-18 [?] RSPM (R 4.2.0)
#>  P pillar         1.8.0   2022-07-18 [?] RSPM (R 4.2.1)
#>  P pkgbuild       1.3.1   2021-12-20 [?] CRAN (R 4.2.0)
#>  P pkgconfig      2.0.3   2019-09-22 [?] RSPM
#>  P pkgload        1.3.0   2022-06-27 [?] RSPM (R 4.2.0)
#>  P prettyunits    1.1.1   2020-01-24 [?] RSPM
#>  P processx       3.7.0   2022-07-07 [?] RSPM (R 4.2.1)
#>  P profvis        0.3.7   2020-11-02 [?] RSPM (R 4.2.0)
#>  P promises       1.2.0.1 2021-02-11 [?] RSPM (R 4.2.0)
#>  P ps             1.7.1   2022-06-18 [?] RSPM (R 4.2.0)
#>  P purrr          0.3.4   2020-04-17 [?] RSPM
#>  P R6             2.5.1   2021-08-19 [?] RSPM
#>  P Rcpp           1.0.9   2022-07-08 [?] RSPM (R 4.2.1)
#>  P remotes        2.4.2   2021-11-30 [?] CRAN (R 4.2.0)
#>    renv           0.15.5  2022-05-26 [1] RSPM (R 4.2.0)
#>  P rlang          1.0.4   2022-07-12 [?] RSPM (R 4.2.1)
#>  P rmarkdown      2.14    2022-04-25 [?] RSPM (R 4.2.0)
#>  P rstudioapi     0.13    2020-11-12 [?] RSPM
#>  P sessioninfo    1.2.2   2021-12-06 [?] CRAN (R 4.2.0)
#>  P shiny          1.7.2   2022-07-19 [?] RSPM (R 4.2.1)
#>  P stringi        1.7.8   2022-07-11 [?] RSPM (R 4.2.1)
#>  P stringr        1.4.0   2019-02-10 [?] RSPM
#>  P tibble         3.1.8   2022-07-22 [?] RSPM (R 4.2.1)
#>  P tidyr          1.2.0   2022-02-01 [?] RSPM (R 4.2.0)
#>  P tidyselect     1.1.2   2022-02-21 [?] RSPM (R 4.2.0)
#>  P urlchecker     1.0.1   2021-11-30 [?] RSPM (R 4.2.0)
#>  P usethis        2.1.6   2022-05-25 [?] RSPM (R 4.2.0)
#>  P utf8           1.2.2   2021-07-24 [?] RSPM
#>  P vctrs          0.4.1   2022-04-13 [?] RSPM (R 4.2.0)
#>  P xfun           0.31    2022-05-10 [?] RSPM (R 4.2.0)
#>  P xtable         1.8-4   2019-04-21 [?] RSPM (R 4.2.0)
#>  P yaml           2.3.5   2022-02-21 [?] RSPM (R 4.2.0)
#> 
#>  [1] /media/LaCie16TB/work/r-blog/renv/library/R-4.2/x86_64-pc-linux-gnu
#>  [2] /usr/local/lib/R/library
#> 
#>  P ── Loaded and on-disk path mismatch.
#> 
#> ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────