---
title: "The {xdvir} Package"
author: "Paul Murrell"
output: 
  rmarkdown::html_vignette:
    number_sections: true
bibliography: xdvir-intro.bib
vignette: >
  %\VignetteIndexEntry{The {xdvir} Package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r echo=FALSE}
knitr::opts_chunk$set(
  comment = ''
)
```

*The {xdvir} package provides functions for rendering LaTeX fragments in
R plots.*

```{r}
library(xdvir)
```

```{r echo=FALSE}
if (getOption("xdvir.engine")$name == "null") {
    ## TeX not available
    haveTeX <- FALSE
    warning("TeX not available.  Example code will not be run")
} else {
    haveTeX <- TRUE
    ## Math typesetting by LuaTeX can fall back into mode=base
    ## (which we can't currently handle)
    ## so use XeTeX engine for this vignette
    options("xdvir.engine"="xetex")
}
```

# Rendering LaTeX in R

The plot below, produced with R, features a LaTeX-quality
mathematical equation in the
top-left corner.
Producing an equation like this requires three things:

1.  A **markup** language that allows us to describe the equation. 

2.  A **typesetter** that can select fonts and individual 
     glyphs from within those fonts and determine the exact placement
     of each individual glyph.

3.  A **renderer** that can draw the glyphs from the fonts that the typesetter
    has selected in the locations that the typesetter has determined.

```{r, label="tex", echo=FALSE}
tex <- r"(\huge $\Phi(z) = \frac{1}{\sqrt{2\pi}} \cdot e^{-\frac{z^2}{2}}$)"
```

```{r, echo=FALSE, message=FALSE}
library(gggrid)
```

```{r, gaussian, echo=FALSE}
x <- seq(-4, 4, length.out=100)
df <- data.frame(x=x, y=dnorm(x))
```

```{r ggbase, echo=FALSE}
gg <- ggplot(df) +
    geom_line(aes(x, y))
```

```{r, echo=FALSE, fig.width=6, fig.height=3, message=FALSE}
if (haveTeX) {
    gg +
    grid_panel(latexGrob(tex, x=0, y=1, hjust="left", vjust="top")) +
    xlim(-4, 4) +
    geom_area(aes(x, y), colour=NA, fill="grey90") +
    geom_line(aes(x, y)) +
    scale_x_continuous(expand=expansion(0)) +
    scale_y_continuous(expand=expansion(c(0))) +
    coord_cartesian(clip="off") +
    theme_minimal() +
    theme(panel.grid=element_blank(),
          axis.title=element_blank(),
          axis.text.y=element_blank(),
          plot.margin=unit(rep(4, 4), "mm")) 
} else {
    grid.text("TeX not available")
}
```

The {xdvir} package allows us to use LaTeX as the **markup** language,
a TeX engine as the **typesetter**, and R as the **renderer**.
This allows us to produce high-quality LaTeX typesetting
within R plots, as in the image above.

The main function in {xdvir} is `grid.latex()`,
which takes a LaTeX snippet and draws it on the 
current R graphics device.
For example, the following code
describes the mathematical equation, using LaTeX code, as a character value,
then draws it by calling `grid.latex()` with the character value
as the first argument.

Because LaTeX code tends to contain 
a large number of backslashes, the code below uses the `r"(...)"`
syntax for raw character constants, so that we do not have to
escape each backslash with a double backslash.

```{r}
<<tex>>
```

```{r fig.width=3, fig.height=1, eval=haveTeX}
grid.latex(tex)
```

```{r fig.width=3, fig.height=1, echo=FALSE, eval=!haveTeX}
grid.text("TeX not available")
```

# LaTeX annotations in plots

The function `grid.latex()` only provides a low-level
interface for drawing LaTeX snippets as part of {grid} output.
However, there are ways to combine {grid} output with higher-level
plotting packages.

For example, we can use {grid} within panel functions in the
{lattice} package [@pkg-lattice].  The following code draws a {lattice} plot
and adds the mathematical equation in the top-left corner.
This demonstrates that the `grid.latex()` function has
arguments `x`, `y`, `hjust`, and `vjust` for positioning the
LaTeX output.

```{r}
library(lattice)
```

```{r, eval=FALSE}
<<gaussian>>
```

```{r, label="lattice-init", echo=FALSE, eval=FALSE}
oopt <- lattice.options(layout.widths=list(left.padding=list(x=0),
                                           right.padding=list(x=0)),
                        layout.heights=list(bottom.padding=list(x=0),
                                            top.padding=list(x=0)))
```

```{r, label="lattice-plot", eval=FALSE}
xyplot(y ~ x, df, type="l",
       panel=function(...) {
           panel.xyplot(...)
           grid.latex(tex, 
                      x=unit(2, "mm"),
                      y=unit(1, "npc") - unit(2, "mm"),
                      hjust="left", vjust="top")
       })
```

```{r, label="lattice-final", echo=FALSE, eval=FALSE}
lattice.options(oopt)
```

```{r, echo=FALSE, fig.width=6, fig.height=3}
if (haveTeX) {
<<lattice-init>>
<<lattice-plot>>
<<lattice-final>>
} else {
    grid.text("TeX not available")
}
```

If we want to add {grid} output to a {graphics} plot, we can use the
{gridGraphics} package [@RJ-2015-012; @pkg-gridGraphics].
For example,
the following code draws a {graphics} plot, uses `gridGraphics::grid.echo()` to
convert it to {grid}, navigates to the {grid} viewport that
represents the main plot region, and draws the mathematical equation
in the top-left corner.

```{r}
library(gridGraphics)
```

```{r, label="graphics-init", echo=FALSE, eval=FALSE}
opar <- par(mar=c(4, 4, 1, 1))
```
```{r, label="graphics-plot", eval=FALSE}
plot(y ~ x, df, type="l")
grid.echo()
downViewport("graphics-plot-1")
grid.latex(tex, 
           x=unit(2, "mm"),
           y=unit(1, "npc") - unit(2, "mm"),
           hjust="left", vjust="top")
```
```{r, label="graphics-final", echo=FALSE, eval=FALSE}
par(opar)
```
```{r, echo=FALSE, fig.width=6, fig.height=3, fig.keep="last"}
if (haveTeX) {
<<graphics-init>>
<<graphics-plot>>
<<graphics-final>>
} else {
    grid.text("TeX not available")
}
```

We can add {grid} output to {ggplot2} plots [@pkg-ggplot2]
with the {gggrid}
package [@murrell-gggrid-2021; @pkg-gggrid].
The following
code uses the `latexGrob()` function to generate a "graphical object"
for {ggplot2} to draw, rather than drawing the output immediately as
`grid.latex()` does, and passes that to `gggrid::grid_panel()`
so that the mathematical equation is added in the top-left corner
of the plot.  


```{r, message=FALSE}
library(gggrid)
```

```{r eval=FALSE}
<<ggbase>>
```

```{r, fig.width=6, fig.height=3, eval=haveTeX}
gg +
    grid_panel(latexGrob(tex,
                         x=unit(2, "mm"), 
                         y=unit(1, "npc") - unit(2, "mm"), 
                         hjust="left", vjust="top"))
```

```{r, fig.width=6, fig.height=3, echo=FALSE, eval=!haveTeX}
grid.text("TeX not available")
```

Another way to do this in {ggplot2} is with 
`ggplot2::annotation_custom()`, though precisely positioning the annotation
may be less convenient.

# LaTeX labels in {ggplot2}

The {xdvir} package also provides integration with labels in {ggplot2}
plots.  This allows, for example, the title of a plot to contain
LaTeX code, as shown in the image below.  For this to work, the relevant theme
element must be set using `element_latex()`, as shown in the code below.

```{r, fig.width=6, fig.height=3, message=FALSE, eval=haveTeX}
gg +
    labs(title=paste("The Normal Distribution:", tex)) +
    theme(plot.title=element_latex())
```

```{r, fig.width=6, fig.height=3, message=FALSE, echo=FALSE, eval=!haveTeX}
grid.text("TeX not available")
```

Although the need is probably less, for completeness, there is also
a `geom_latex()` for adding LaTeX-styled data symbols.
For example, the following code adds LaTeX text labels to a 
dot plot.

```{r}
samples <- data.frame(x=rnorm(50), sample=rep(1:5, each=10))
means <- aggregate(samples$x, list(sample=samples$sample), mean)
means$label <- paste0("$\\bar x_", means$sample, "$")
```

```{r, fig.width=6, fig.height=3, message=FALSE, eval=haveTeX}
ggplot(samples) +
    geom_vline(xintercept=0, linetype="solid", colour=1, linewidth=.5) +
    geom_point(aes(x, sample), size=4, alpha=.5) +
    geom_point(aes(x, sample), data=means, colour=2, size=4) +
    geom_latex(aes(x, sample, label=label), data=means, 
               size=6, vjust=-.4, colour=2) +
    scale_y_continuous(expand=expansion(.25))
```

```{r, fig.width=6, fig.height=3, message=FALSE, echo=FALSE, eval=!haveTeX}
grid.text("TeX not available")
```

# Related packages

The {xdvir} package provides similar functionality to the 
{gridtext} and {ggtext} packages [@pkg-gridtext; @pkg-ggtext]
and the {marquee} package [@pkg-marquee].
The main difference is the **markup** language that is supported.
Where those packages are built on markdown, {xdvir} is built on LaTeX,
with all of the joy and pain that that brings.

# Limitations

The {xdvir} package relies on the glyph rendering support that was 
added to the R graphics engine in R version 4.3.0
[@murrell-pedersen-urbanek-glyphs-2023].
Furthermore, this support is only available on specific graphics devices:
the core `pdf()`, Cairo-based devices, and `quartz()` devices, plus
the devices provided by the {ragg} package [@pkg-ragg].
R Studio users should set the graphics backend to 
"AGG" or "cairo" (if either of those is not the default).

The {xdvir} package also relies on there being a TeX installation.
When the package is attached, it reports on the TeX features that
it can find (see the top of this document for an example).
If TeX is not found, the simplest solution is to use
`tinytex::install_tinytex()`.

# References
