Technical reports written in R Markdown usually include mathematical symbols. R Markdown addresses that by supporting the inclussion of raw LaTeX code. Depending on the desired output format, the code gets rendered by some LaTeX engine. This feature is very convenient.
The issue here is that writing LaTeX code can be cumbersome and the
result is usually hard to read. Although the use of
newcommand
can alleviate that, in practice people use it
infrequently. The idea behind this package is that if you’re writing an
R Markdown report, you’re already using R, so you might as well use it
to write your LaTeX code as well.
This is best explained through an example. Consider the following equation, encountered in Riemannian geometry:
\[ \frac{d}{dt} \left \langle V,W \right \rangle = \left \langle \frac{DV}{dt}, W \right \rangle + \left \langle V, \frac{DW}{dt} \right \rangle \]
The straightforward way to code that is:
\frac{d}{dt} \left \langle V,W \right \rangle = \left \langle \frac{DV}{dt}, W \right \rangle + \left \langle V, \frac{DW}{dt} \right \rangle
If you were to use latexSymb
, you would proceed as
follows instead. First you would create objects of class
latex_symb
to represent the vector fields:
## Loading required package: purrr
##
## Attaching package: 'latexSymb'
## The following objects are masked from 'package:base':
##
## *, +, -, /, ^
Then you would write R functions to represent the mathematical concepts being used: the inner product, the covariant derivative and the ordinary derivative:
inner <- function(x,y) ang(lsymb(x, ",", y))
cov.der <- function(x) lsymb("D", x)/"dt"
ddt <- function(x) lsymb("d", x)/"dt"
Then you would put everything in an equation
environment:
lenv("equation",
lsymb(
ddt(inner(vf1, vf2)),
"=",
inner(cov.der(vf1), vf2) + inner(vf1, cov.der(vf2))
)
) |> cat()
\[\begin{equation}\frac{ d \langle V , W \rangle }{ dt } = \langle \frac{ D V }{ dt } , W \rangle + \langle V , \frac{ D W }{ dt } \rangle\end{equation}\]
Notice that you need to cat
instead of
print
to avoid double backslashes.
Let us unpack all of this.
Notice first that in the definition of cov.der
an
important feature is being used. Namely, the /
function is
overwritten by latexSymb
so that if either of its arguments
are objects of class latex_symb
, the output is another
object of that class that uses frac
as you would expect.
This is also done with +
, -
, *
and ^
. Additionally, under
adds support for
the use of subscripts.
Also, in the numerator of cov.der
,
lsymb("D", x)
concatenates the string "D"
and
the object x
, and wraps the result in a new
latex_symb
object.
Further, there’s the use of the latexSymb
function
ang
, which provides the dynamic enclosing for the inner
product, thus avoiding the need to write left
and
right
. The functions br
, sqbr
and
pths
do the same for braces, square brackets and
parentheses respectively.
Finally, there is the function lenv
that spares the user
from writing begin
and end
. The second
argument is a list or a vector, whose components represent different
lines. So, for instance, we could have written also
lenv("align*",
c(
lsymb(ddt(inner(vf1, vf2)), "&=\\\\"),
lsymb("&=", inner(cov.der(vf1), vf2) + inner(vf1, cov.der(vf2)))
)
) |> cat()
\[\begin{align*}\frac{ d \langle V , W \rangle }{ dt } &=\\&= \langle \frac{ D V }{ dt } , W \rangle + \langle V , \frac{ D W }{ dt } \rangle\end{align*}\]
latex_symb
also exposes il
, which surrounds
expressions in dollar signs, for inline math environments.
On the whole, latexSymb
may not significantly reduce the
amount of code users have to write compared to raw LaTeX. But I do think
it makes it more readable and hence less prone to errors. Users can
mostly write what they mean, not what they want to see.
Additionally, latexSymb
is not limited to RMarkdown.
Actually, it probably makes more sense in .Rtex
documents.
In any case, any format that knit
can handle will do.
Finally, for very complicated equations, R’s piping should make things even more readable.