knitr::opts_chunk$set(echo = TRUE)
library(matlib) #source(here::here("dev","Eqn.R"))
\LaTeX\ is the de facto standard for communication and publication in scientific documents and it is very easy to typeset mathematical expressions
like Pythagoras' theorem, $a^2 + b^2 = c^2$ (using a^2 + b^2 = c^2
) once you learn
the notation. Writing equations with arrays, matrices and vectors is
somewhat more challenging. Many people rely on interactive \LaTeX\ editors like Overleaf, MathType, or online
versions that provide a menu-driven interface with fill-in templates for
matrices.
There are already some tools available in R for producing \LaTeX\ output for
tables (xtable::xtable()
), R objects (Hmisc::latex()
)
and statistical models (equatiomatic::extract_eq()
).
The matlib
package extends these, providing a collection of functions that simplify using \LaTeX\ notation for matrices, vectors and equations in documentation and in writing:
symbolicMatrix()
: Constructs the \LaTeX\ code for a symbolic matrix, whose elements are a symbol, with row and column subscripts.showEqn()
: Shows what matrices $\mathbf{A}, \mathbf{b}$ look like as the system of linear equations, $\mathbf{A x} = \mathbf{b}$, but written out as a set of equations.Eqn()
: A wrapper to produce LaTeX expressions that can be copied/pasted into documents or
used directly in .Rmd
or .qmd
documents to compile to equations.When used directly in R, they produce their output to the console (using cat()
).
In a .Rmd
or .qmd
document, use the chunk options: results='asis', echo=FALSE
so that knitr
just outputs the text of the equations to the document.
The rendering of the equations is handled by pandoc
.
Note: Some of these functions are still experimental. Their organization and arguments may change. They presently work well for PDF output, but there are limitations in HTML output.
symbolicMatrix()
and Eqn()
symbolicMatrix()
constructs the \LaTeX\ code for a symbolic matrix, whose elements are a symbol, with row and column subscripts. For example, by default (with no arguments) it produces the expression for a matrix whose elements
are $x_{ij}$, for $i = 1, 2, \cdots, n; j = 1, 2, \cdots,m$ in a \LaTeX\ \begin{pmatrix} ... \end{pmatrix}
environment that looks like this:
\begin{pmatrix} x_{11} & x_{12} & \cdots & x_{1m} \\ x_{21} & x_{22} & \cdots & x_{2m} \\ \vdots & \vdots & & \vdots \\ x_{n1} & x_{n2} & \cdots & x_{nm} \\ \end{pmatrix}
The code above appears in the console. To render this as a matrix in a document, this must
be wrapped in a display math environment, which is provided by Eqn()
and used in a code
chunk with the results = 'asis'
option, giving:
symbolicMatrix() |> Eqn(number = FALSE)
For chunk output in a document, you will get a \LaTeX\ error, "missing $ inserted" if you forget
to use Eqn()
or otherwise fail to make a math environment.
Some other examples:
symbolicMatrix()
can be any numeric or character matrix.symbolicMatrix(diag(3), lhs = "\\mathbf{I}_3", matrix="bmatrix") |> Eqn(number = FALSE)
symbolicMatrix()
must be a matrix, so wrap an R vector in matrix()
, supplying nrow=1
(or ncol = 1
):symbolicMatrix(matrix(LETTERS[1:4], nrow=1)) |> Eqn(number = FALSE)
or using Eqn()
directly, which offers less specificity than symbolicMatrix()
.
matrix(letters[1:3], ncol=1) |> Eqn(number = FALSE)
As a more complicated example,
here we write out the \LaTeX\ equation for the singular value decomposition (SVD) of a
general $n \times p$ matrix $\mathbf{X}$
using Eqn()
and symbolicMatrix()
. In Rmd markup, Eqn()
can be given an equation label.
Two calls to Eqn()
produce separate equations in the output.
Both of these equations are numbered (by default).
(Eqn()
uses the \LaTeX\ equation
environment, \begin{equation} ... \end{equation}
,
or equation*
if the equation is not numbered (number = FALSE
)).
The two calls to Eqn()
are rendered as separate equations, center aligned.
Eqn("\\mathbf{X} = \\mathbf{U} \\mathbf{\\Lambda} \\mathbf{V}^\\top", label='eqn:svd') Eqn(symbolicMatrix("u", "n", "k", lhs = ''), symbolicMatrix("\\lambda", "k", "k", diag=TRUE), symbolicMatrix("v", "k", "p", transpose = TRUE))
This produces the two numbered equations:
Eqn("\\mathbf{X} = \\mathbf{U} \\mathbf{\\Lambda} \\mathbf{V}^\\top", label='eqn:svd') Eqn(symbolicMatrix("u", "n", "k", lhs = ''), symbolicMatrix("\\lambda", "k", "k", diag=TRUE), symbolicMatrix("v", "k", "p", transpose = TRUE))
The matrix names in Equation (\ref{eqn:svd}) are printed in a boldface math font, typically used for matrices
and vectors. Note that when using
\LaTeX\ code in R expressions each backslash (\
) must be doubled (\\
) in R because \
is the
escape character.
Note that the first equation can be referenced because it was labeled: "As seen in Equation (\ref{eqn:svd}) \ldots ".
(In Quarto, equation labels must be of the form #eq-label
and equation references are of the form @eq-label
)
As another example, the chunk below shows a system of equations $\mathbf{A} \mathbf{x} = \mathbf{b}$ written out using symbolic matrices.
Eqn(symbolicMatrix("a", nrow = "m", ncol="n", matrix="bmatrix"), symbolicMatrix("x", nrow = "n", ncol=1), "\\quad=\\quad", symbolicMatrix("b", nrow = "m", ncol=1))
You can also align separate equations relative to some symbol like an =
sign to show separate
steps of re-expression, using the option Eqn(..., align=TRUE)
.
Show the singular value decomposition again, but now as two separate equations aligned after the =
sign. Note the locations of the &
operator for alignment, specified as the left-hand side (lhs
)
of the second equation.
Eqn("\\mathbf{X} & = \\mathbf{U} \\mathbf{\\Lambda} \\mathbf{V}^\\top", Eqn_newline(), symbolicMatrix("u", "n", "k", lhs = '&'), symbolicMatrix("\\lambda", "k", "k", diag=TRUE), symbolicMatrix("v", "k", "p", transpose = TRUE), align=TRUE)
Note that in this example, there are three calls to symbolicMatrix()
, wrapped inside Eqn()
.
Eqn_newline()
emits a newline (\\
) between equations.
The symbolicMatrix()
and Eqn()
functions can also generate symbolic equations from numeric or character matrices.
For numeric matrices, it can round the values or show results as fractions.
A <- matrix(1:12, nrow=3, ncol=4, byrow = TRUE) / 6 Eqn(A, number = FALSE)
By default Eqn()
will pass any numeric/character matrix to symbolicMatrix()
using the default inputs. However, for greater specificity symbolicMatrix()
can be called directly, which includes many other formatting options, such as the following reporting of fractions instead.
symbolicMatrix(A, fractions = TRUE) |> Eqn(number = FALSE)
Say we want to show the matrix $[\mathbf{A} | \mathbf{b}]$ involved in the system of equations $\mathbf{A} \mathbf{x} = \mathbf{b}$. Create these as a character matrix and vector:
A <- matrix(paste0('a_', 1:9), 3, 3, byrow = TRUE) |> print() b <- paste0("\\beta_", 1:3) |> print()
Then use cbind(A,b)
and pipe the result to Eqn()
, which will automatically pass any input numeric/character matrix
to symbolicMatrix()
:
cbind(A,b) |> Eqn(number=FALSE)
To demonstrate that this is an augmented matrix the command \bigm|
can be included.
cbind(A, "\\bigm|", b) |> Eqn(number=FALSE)
All the R tricks for creating and modifying matrices can be used in this way.
showEqn()
is designed to show a system of linear equations, $\mathbf{A x} = \mathbf{b}$, but written out as a set of equations individually. With the option latex = TRUE
it writes these out in \LaTeX\ form.
Here, we create a character matrix containing
the elements of a $3 \times 3$ matrix A
, whose elements are of the form
a_{ij}
and two character vectors, b_i
and x_i
.
A <- matrix(paste0("a_{", outer(1:3, 1:3, FUN = paste0), "}"), nrow=3) |> print() b <- paste0("b_", 1:3) x <- paste0("x", 1:3)
showEqn(..., latex = TRUE)
produces the three equations in a single \begin{array} ... \begin{array}
environment.
showEqn(A, b, vars = x, latex=TRUE)
If this line was run in an R console, it would produce:
\begin{array}{lllllll} a_{11} \cdot x_1 &+& a_{12} \cdot x_2 &+& a_{13} \cdot x_3 &=& b_1 \\ a_{21} \cdot x_1 &+& a_{22} \cdot x_2 &+& a_{23} \cdot x_3 &=& b_2 \\ a_{31} \cdot x_1 &+& a_{32} \cdot x_2 &+& a_{33} \cdot x_3 &=& b_3 \\ \end{array}
Evaluating the above code in an unnumbered \LaTeX\ math environment via Eqn()
gives the
desired result:
showEqn(A, b, vars = x, latex=TRUE) |> Eqn(number=FALSE)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.