Cross Referenceable Equation with Preview in RMarkdown

February 12, 2017
computer R

Cross-referenceable math equation in RMarkdown

You can cross-reference equations in Rmarkdown if you set output to bookdown::pdf_document2 and write equations within \begin{align} ~ \end{align} or \begin{equation} ~ \end{equation}

To make a tag, put (\#eq:label_name) inside a math environment. The equation can be cross-referenced by \@ref(eq:label_name). See this stackoverflow answer by Yihui Xie and the related section of his bookdown book for more detail.

\begin{equation*} ~ \end{equation*} also produces an equation without number.

Drawback

A drawback of using \begin{align} ~ \end{align} or the like is that RStudio doesn’t support math preview for them (yet). You must embrace the whole math environment with $$.

math preview

The former looks nicer but causes the “Bad math delimiter” error at the time of tex compilation.

Workaround

Step 1

Put the following code snippet in .Rprofile file of the project.

.beginMath = c(
  "\\begin{equation}",
  "\\begin{equation*}",
  "\\begin{align}",
  "\\begin{align*}"
)

.endMath = c(
  "\\end{equation}",
  "\\end{equation*}",
  "\\end{align}",
  "\\end{align*}"
)

.render_for_tex = function(input, ...){
  output_file = gsub("\\.[R|r]md$", ".tex", input)
  lines = readLines(input, encoding = "UTF-8");

  for (i in seq_along(lines)) {
    # Remove $$ before \begin{equation} or the like.
    if (stringr::str_trim(lines[i]) == "$$") {
      if (any(startsWith(lines[i + 1], .beginMath))) {
        lines[i] = ""
      } else if (any(endsWith(lines[i - 1], .endMath))) {
        lines[i] = ""
      }
    }
  }
  writeLines(lines,"temp.Rmd"); on.exit(unlink('temp.Rmd'))
  rmarkdown::render("temp.Rmd", output_file = output_file)
}

Step 2

Add knit: .render_for_math to the YAML header of your Rmd file. Then the Knit button of RStudio is overwritten with the custom renderer with preprocessing defined in .Rprofile.

The YAML fromtmatter looks like

---
title: title
author: author
output:
  bookdown::pdf_document2:
    toc: false
    fig_caption: yes
knit: .render_for_tex
---

Example

This PDF file is generated by the Rmd file and .Rprofile stored here.