library(equatiomatic)
# Create a simple linear model
mod2 <- lm(mpg ~ ., mtcars)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).
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.812There 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.
extract_eq(mod2)\[ \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.4.0 (2024-04-24)
#> os Ubuntu 24.04 LTS
#> system x86_64, linux-gnu
#> ui X11
#> language en_CA:en
#> collate en_CA.UTF-8
#> ctype en_CA.UTF-8
#> tz America/Toronto
#> date 2024-05-02
#> pandoc 3.1.3 @ /usr/bin/ (via rmarkdown)
#>
#> ─ Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────
#> ! package * version date (UTC) lib source
#> P backports 1.4.1 2021-12-13 [?] RSPM (R 4.4.0)
#> P broom 1.0.5 2023-06-09 [?] RSPM (R 4.4.0)
#> P cachem 1.0.8 2023-05-01 [?] RSPM (R 4.4.0)
#> P cli 3.6.2 2023-12-11 [?] RSPM (R 4.4.0)
#> P devtools 2.4.5 2022-10-11 [?] RSPM
#> P digest 0.6.35 2024-03-11 [?] RSPM (R 4.4.0)
#> P dplyr 1.1.4 2023-11-17 [?] RSPM (R 4.4.0)
#> P ellipsis 0.3.2 2021-04-29 [?] RSPM (R 4.4.0)
#> P equatiomatic * 0.3.1 2024-05-02 [?] Github (datalorax/equatiomatic@39e8c3e)
#> P evaluate 0.23 2023-11-01 [?] RSPM (R 4.4.0)
#> P fansi 1.0.6 2023-12-08 [?] RSPM (R 4.4.0)
#> P fastmap 1.1.1 2023-02-24 [?] RSPM (R 4.4.0)
#> P fs 1.6.4 2024-04-25 [?] CRAN (R 4.4.0)
#> P generics 0.1.3 2022-07-05 [?] RSPM (R 4.4.0)
#> P glue 1.7.0 2024-01-09 [?] RSPM (R 4.4.0)
#> P htmltools 0.5.8.1 2024-04-04 [?] RSPM (R 4.4.0)
#> P htmlwidgets 1.6.4 2023-12-06 [?] RSPM
#> P httpuv 1.6.15 2024-03-26 [?] RSPM (R 4.4.0)
#> P jsonlite 1.8.8 2023-12-04 [?] RSPM (R 4.4.0)
#> P knitr 1.46 2024-04-06 [?] RSPM (R 4.4.0)
#> P later 1.3.2 2023-12-06 [?] RSPM (R 4.4.0)
#> P lifecycle 1.0.4 2023-11-07 [?] RSPM (R 4.4.0)
#> P magrittr 2.0.3 2022-03-30 [?] RSPM (R 4.4.0)
#> P memoise 2.0.1 2021-11-26 [?] RSPM (R 4.4.0)
#> P mime 0.12 2021-09-28 [?] RSPM (R 4.4.0)
#> P miniUI 0.1.1.1 2018-05-18 [?] RSPM (R 4.4.0)
#> P pillar 1.9.0 2023-03-22 [?] RSPM (R 4.4.0)
#> P pkgbuild 1.4.4 2024-03-17 [?] RSPM (R 4.4.0)
#> P pkgconfig 2.0.3 2019-09-22 [?] RSPM (R 4.4.0)
#> P pkgload 1.3.4 2024-01-16 [?] RSPM
#> P processx 3.8.4 2024-03-16 [?] RSPM (R 4.4.0)
#> P profvis 0.3.8 2023-05-02 [?] RSPM
#> P promises 1.3.0 2024-04-05 [?] RSPM (R 4.4.0)
#> P ps 1.7.6 2024-01-18 [?] RSPM (R 4.4.0)
#> P purrr 1.0.2 2023-08-10 [?] RSPM (R 4.4.0)
#> P quarto * 1.4 2024-03-06 [?] RSPM
#> P R.cache 0.16.0 2022-07-21 [?] RSPM
#> P R.methodsS3 1.8.2 2022-06-13 [?] RSPM
#> P R.oo 1.26.0 2024-01-24 [?] RSPM
#> P R.utils 2.12.3 2023-11-18 [?] RSPM
#> P R6 2.5.1 2021-08-19 [?] RSPM (R 4.4.0)
#> P Rcpp 1.0.12 2024-01-09 [?] RSPM (R 4.4.0)
#> P remotes 2.5.0 2024-03-17 [?] RSPM
#> P renv 1.0.7 2024-04-11 [?] RSPM (R 4.4.0)
#> P rlang 1.1.3 2024-01-10 [?] RSPM (R 4.4.0)
#> P rmarkdown 2.26 2024-03-05 [?] RSPM (R 4.4.0)
#> P rstudioapi 0.16.0 2024-03-24 [?] RSPM
#> P sessioninfo 1.2.2 2021-12-06 [?] RSPM
#> P shiny 1.8.1.1 2024-04-02 [?] RSPM (R 4.4.0)
#> P stringi 1.8.3 2023-12-11 [?] RSPM (R 4.4.0)
#> P stringr 1.5.1 2023-11-14 [?] RSPM (R 4.4.0)
#> P styler * 1.10.3 2024-04-07 [?] RSPM
#> P tibble 3.2.1 2023-03-20 [?] RSPM (R 4.4.0)
#> P tidyr 1.3.1 2024-01-24 [?] RSPM (R 4.4.0)
#> P tidyselect 1.2.1 2024-03-11 [?] RSPM (R 4.4.0)
#> P urlchecker 1.0.1 2021-11-30 [?] RSPM
#> P usethis 2.2.3 2024-02-19 [?] RSPM
#> P utf8 1.2.4 2023-10-22 [?] RSPM (R 4.4.0)
#> P vctrs 0.6.5 2023-12-01 [?] RSPM (R 4.4.0)
#> P xfun 0.43 2024-03-25 [?] RSPM (R 4.4.0)
#> P xtable 1.8-4 2019-04-21 [?] RSPM (R 4.4.0)
#> P yaml 2.3.8 2023-12-11 [?] RSPM (R 4.4.0)
#>
#> [1] /tmp/RtmpC4S8Ab/renv-use-libpath-2e3df224e3b7d5
#> [2] /home/filoche/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/a71ef467
#>
#> P ── Loaded and on-disk path mismatch.
#>
#> ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────