TeX Typesetting in R Graphics:
The {xdvir} package

Paul Murrell
The University of Auckland

Where do you look?

A bar plot of the concentration of plastic in the Atlantic, plus a line showing the tonnes of discarde plastic in the US, from 1985 to 2008. The discarded plastic is increasing, but the plastic in the Atlantic is, if anything, decreasing. Source: The Economist

How hard can it be?

One slide from an animation explaining the derivation of “adaptive landscape” from a “fitness function”. The plot features a paragraph of explanatory text. Source: Marc-Olivier Beausoleil.

How hard can it be?

One slide from an animation explaining the derivation of “adaptive landscape” from a “fitness function”. The plot features a paragraph of explanatory text. Source: Marc-Olivier Beausoleil.

  • Mathematical notation.

How hard can it be?

One slide from an animation explaining the derivation of “adaptive landscape” from a “fitness function”. The plot features a paragraph of explanatory text. Source: Marc-Olivier Beausoleil.

  • Changes in style (e.g., colour).

How hard can it be?

One slide from an animation explaining the derivation of “adaptive landscape” from a “fitness function”. The plot features a paragraph of explanatory text. Source: Marc-Olivier Beausoleil.

  • Full justification.

How hard can it be?

One slide from an animation explaining the derivation of “adaptive landscape” from a “fitness function”. The plot features a paragraph of explanatory text. Source: Marc-Olivier Beausoleil.

  • Hyphenation.

How hard can it be?

One slide from an animation explaining the derivation of “adaptive landscape” from a “fitness function”. The plot features a paragraph of explanatory text. Source: Marc-Olivier Beausoleil.

  • Typesetting is hard.

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality

  • Manual line breaks.

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality

  • Ugly math.

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality

  • No full justification.

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality

  • No hyphenation.

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality (and {gridtext})

  • Inconsistent line spacing.

How good is R?

A best-effort attempt at emulating the previous plot, just using core R graphics text functionality (and {gridtext})

  • R is pretty bad.

Three problems

  1. Markup
    How to describe the text?
    (e.g., changes in colour)

  2. Typesetting
    How to layout the text?
    (e.g., full justification)

  3. Rendering
    How to draw the text?
    (in R)

Two solutions

  • \({\rm \LaTeX}\) provides a solution for Markup and Typesetting.

    • Mathematical notation

      $\bar z_i$

    • Colour

      \textcolor{red}{fitness function}

    • Full justification by default.

    • Hyphenation by default.

\({\rm \LaTeX}\) markup

  • text.tex

    \documentclass{standalone}
    \usepackage{unicode-math}
    \usepackage{xcolor}
    \begin{document}
    \setmainfont{TeX Gyre Adventor}
    \fontsize{12}{15}
    \selectfont
    \definecolor{Rred}{RGB}{223,83,107}
    \begin{minipage}{3.5in}
    We `move' the original population's mean to a new $\bar z_i$ and 
    calculate the average fitness at that new mean phenotype of the 
    population to get the adaptive landscape, $\bar W_i$, then we 
    combine the population mean and the average fitness to get the 
    \textcolor{Rred}{fitness function}.
    \end{minipage}
    \end{document}

\({\rm \LaTeX}\) layout

  • text.dvi

    x_fnt_def    fontnum=41, ptsize=786432
                 fontname=/usr/share/texmf/fonts/opentype/public/tex-gyre/texgyreadventor-regular.otf [0]
    fnt_num_41
    x_glyph      id=56, x=0, y=0
    x_glyph      id=70, x=731382, y=0 
    w3           b=327116 
    x_glyph      id=113, x=0, y=0
    x_glyph      id=78, x=276038, y=0
    x_glyph      id=80, x=1013711, y=0
    x_glyph      id=87, x=1509163, y=0
    x_glyph      id=70, x=1925186, y=0
    x_glyph      id=114, x=2412774, y=0 
    w0 
    x_glyph      id=85, x=0, y=0
    x_glyph      id=73, x=266600, y=0
    x_glyph      id=70, x=746324, y=0 

Glyphs

Three solutions

  • From R 4.3.0, we can draw glyphs.

    font <- glyphFont(file.path("", "usr", "share", "texmf", "fonts", 
                                "opentype", "public", "tex-gyre", 
                                "texgyreadventor-regular.otf"),
                      0, "TeX Gyre Adventor", 400, "normal")
    glyph <- glyphInfo(id=56, x=0, y=0, font=1, size=36,
                       glyphFontList(font),
                       width=25, height=30)
    grid.glyph(glyph)

  • This solves the rendering problem.

Four problems

  1. Markup
    How to describe the text?
    (e.g., changes in colour)

  2. Typesetting
    How to layout the text?
    (e.g., full justification)

  3. Rendering
    How to draw the text?
    (in R)

  1. Integration
    How to translate \({\rm \LaTeX}\) typesetting into R glyphs?

\({\rm \LaTeX}\) layout

  • text.dvi

      0  :  f7 07 01 83 92 c0 1c 3b 00 00 00 00 03  |  .......;.....
     13  :  e8 1d 20 58 65 54 65 58 20 6f 75 74 70  |  .. XeTeX outp
     26  :  75 74 20 32 30 32 34 2e 30 36 2e 32 37  |  ut 2024.06.27
     39  :  3a 31 30 30 39 8b 00 00 00 01 00 00 00  |  :1009........
     52  :  00 00 00 00 00 00 00 00 00 00 00 00 00  |  .............
     65  :  00 00 00 00 00 00 00 00 00 00 00 00 00  |  .............
     78  :  00 00 00 00 00 00 00 ff ff ff ff ef 2e  |  .............
     91  :  70 64 66 3a 70 61 67 65 73 69 7a 65 20  |  pdf:pagesize 
    104  :  77 69 64 74 68 20 32 35 39 2e 30 33 39  |  width 259.039
    117  :  70 74 20 68 65 69 67 68 74 20 39 39 2e  |  pt height 99.
    130  :  30 32 33 39 39 70 74 9f 1a c1 05 8d a4  |  02399pt......
    143  :  9c f9 dc 8d 8d 91 b7 ba e1 ef 11 63 6f  |  ...........co
    156  :  6c 6f 72 20 70 75 73 68 20 67 72 61 79  |  lor push gray
    169  :  20 30 92 01 59 00 00 ef 09 63 6f 6c 6f  |   0..Y....colo
    182  :  72 20 70 6f 70 8e 8e a9 63 06 24 8d 91  |  r pop...c.$..
    195  :  b7 ba e1 a1 ef                          |  .....         

{xdvir}

{xdvir}

  • The {xdvir} package allows us to use \({\rm \LaTeX}\) markup to describe text and renders the typeset result in R.

    library(xdvir)
    grid.latex("Hello \\LaTeX")

Mathematical notation

grid.latex("$\\bar z_i$")

Changes in style

grid.latex("to get the \\color{red} fitness function",
           packages="xcolor")

Full justification and hyphenation

grid.latex("\\begin{minipage}{2.5in}
            We `move' the original population's mean to a new 
            $\\bar z_i$ and calculate the average fitness at that 
            new mean phenotype
            \\end{minipage}")

What else?

A plot of migration over time for Japan with Japanese labels, some typeset vertically and left-to-right

Limitations

  • Not on CRAN.

  • Slow.

  • Heavy system requirements.

  • {grid} interface only.

Conclusion

  • If you care about text on your plots, and you should, then you desperately need:

    • A way to markup your text.
    • A way to typeset your marked up text.
    • A way to render your typeset text.
  • The {xdvir} package saves your life by integrating \(\LaTeX\) markup and typesetting with R’s glyph rendering.

Acknowledgements

  • The first plot is from the Economist.

  • The first plot image, plus the eyetracking data, were downloaded from the MASSVIS project.

  • The second plot is a simplification of an example provided by Marc-Olivier Beausoleil.

  • The third plot is a combination of data from the Statistics Bureau of Japan, English text generated by ChatGPT, and a Japanese translation by Google Translate.