Org Mode & LaTeX


What's the story on using LaTeX with Org Mode?

Introduction

I've spent the past few days understanding how to embed LaTeX into Org Mode documents & I thought I'd write up my learnings as an signpost for anyone else wandering along this path. I'll begin with some background for readers who may not be familiar with either Org Mode or \(\LaTeX\). I'll then lay out my understanding of how LaTeX works with Org Mode, using the problem that gave rise to my inquiries as a touchstone for understanding. This will surface what I consider to be a bug in Org Mode along with a patch. Finally, I'll finish-up with some Emacs Lisp & a demo of what entering math now looks like for me.

Background

If the reader is already familiar with Org Mode and/or LaTeX, they should feel free to skip ahead to How We Can Use LaTeX in Org Mode Documents.

Org Mode

Emacs Org Mode is a fascinating piece of software. At one level, it's another markup language. By which I mean a language in which one describes the structure and formatting of a document in the abstract, leaving it to a publication process to produce the document for final display purposes. Much like Markdown, one can attach metadata to the document, describe headings or chapters, indicate text variants (bold, italics, strikethrough or fixed-width, e.g.) and so on. Here's an example:

#+TITLE: Example Document
#+DATE: <2024-03-18 Mon 20:38>

* Heading One

We can *bold* text, _italicize_ it, +strike it out+ or mark it as =fixed width=.
** This Is A Sub-Heading

We can express lists:

  - with multiple
    + levels
  - [ ] and even indicate "todos"
  - [-] that are in-progress
  - [X] or done

or include tables

|                  |  a | b             |  c | d |
|------------------+----+---------------+----+---|
| [2024-03-16 Sat] | 32 | hello, world! | 64 |   |

or links: The Org Manual... and much, much more.

Beyond merely being a markup language, however, Org Mode is implemented in Emacs, enabling a computational layer on top of the markup. We can, for instance, add formulas to our tables:

| date             | total |
|------------------+-------|
| [2024-03-14 Thu] |     3 |
| [2024-03-15 Fri] |     4 |
| [2024-03-16 Sat] |     2 |
|------------------+-------|
|                  |     9 |
#+TBLFM: @>$2=vsum(@<<..@>>)

or add a little Emacs Lisp for keeping the DATE attribute up-to-date automatically:

(add-to-list 'org-export-options-alist
             '(:autodate "AUTODATE" nil "nil" parse))

(defun sp1ff/org/maybe-update-date ()
  "Update the DATE export keyword, if AUTODATE is non-nil."

  (interactive)
  (when (eq major-mode 'org-mode)
    (let ((auto-date
           (intern
            (org-no-properties
             (org-element-interpret-data
              (plist-get (org-export-get-environment) :autodate))))))
      (if auto-date
          (save-excursion
            (goto-char (point-min))
            (if (re-search-forward "^#\\+DATE:[         ]+\\(.*\\)" nil t)
                (replace-match (format "#+DATE: %s" (format-time-string "<%Y-%m-%d %a %H:%M>")))
              (progn
                (goto-char (point-min))
                ;; We are at the beginning of the buffer; skip one line ahead as long as we're looking at "#+..."
                (while (looking-at "^#\\+")
                  (forward-line))
                (if (bolp)
                    (insert (format "#+DATE: %s\n" (format-time-string "<%Y-%m-%d %a %H:%M>")))
                  (insert (format "\n#+DATE: %s" (format-time-string "<%Y-%m-%d %a %H:%M>")))))))))))

(add-hook 'before-save-hook 'sp1ff/org/maybe-update-date)

Now, if we add the AUTODATE attribute and set it to t, the DATE will be updated on save:

#+TITLE: My Document
#+DATE: <2024-03-18 Mon 20:39>
#+AUTODATE: t

Text here...

Most intriguingly we can embed arbitrary code into an Org Mode document, evaluate it, and pass the results of that evaluation to other source code blocks, perhaps in other languages, making Org Mode documents "live" workbooks:

#+NAME: example-table
| 1 |
| 2 |
| 3 |
| 4 |

#+NAME: table-length
#+BEGIN_SRC emacs-lisp :var table=example-table
  (length table)
#+END_SRC

#+RESULTS: table-length
: 4

#+BEGIN_SRC bash :var len=table-length :results output
  len=$((2*$len))
  echo "Twice the table length is $len."
#+END_SRC

#+RESULTS:
: Twice the table length is 8.

This is just the tip of the iceberg, but salient to this post is the Org Mode export feature to which I alluded above: one may export an Org Mode document to other formats, such as plain text ASCII, Beamer, HTML, LaTeX, Markdown, OpenDocument & Texinfo.

LaTeX

\(\TeX\) was one of the earliest markup languages. It was written by the legendary Donald Knuth in response to his disappointment at the galleys for the second volume of his classic The Art of Computer Programming. The "Hello, world!" TeX document is:

Hello, world!
\bye               % marks the end of the file

TeX will process this file to produce a .dvi file ("dvi" for DeVice Independent). The dvi file can be viewed directly or converted to other formats, PDF being the most common today. Despite dating back to the seventies, it remains the standard for document preparation in academic fields. Of particular note here is the fact that it provides a macro language which has been used to build more specific systems, such as \(\LaTeX\).

LaTeX was originally written by Leslie Lamport in the eighties, and provides authors with higher-level commands, implemented in terms of TeX macros, for salient aspects of authoring articles; things such as chapters, graphics, cross-references, bibliographies & many, many more. It is this TeX variant that is the standard for writing scholarly articles in mathematics, computer science and (as I understand it) the hard sciences altogether.

One aspect of both TeX & LaTeX that is germane to our purposes is that they both employ a distinct "mode" for typesetting mathematical expressions. One may enter math mode in a few ways:

  • inline math mode is used for expressing mathematics interspersed with text, e.g.

    If $x \ge 3$ then we may conclude that \(y \in \Gamma\).
    

    will typeset to "If \(x \ge 3\) then we may conclude that \(y \in \Gamma\)." One marks stretches of text as being in inline math mode by surrounding them with either '$' characters or '\(' & '\)' (while researching this article, I came across an anecdote that Knuth chose the '$' symbol because math was, at the time, considered expensive to typeset)

  • display math mode is used to express equations:

    will display the equation centered on its own line. Historically, '$$' was also used to denote this, but that seems to be deprecated.

  • the equation environment: LaTeX environments are entered with \begin{name} and exited with \end{name} (where "name" identifies the environment being used). Environments are used to apply certain formatting conventions within that portion of the document. The "equation" environment, among other things, enters math mode.

The "Hello, world!" \(\LaTeX\) document is:

which will render as:

hello-world.png

How We Can Use LaTeX in Org Mode Documents

The idea of marking-up a portion of a document as "math" and using LaTeX commands (such as \in for "element of" or \ge for "greater than or equal to") has emerged as a convenient shorthand for taking mathematical notes when at a computer keyboard (as opposed to pen & paper). It's a natural extension of any basic markup language, it's fairly easy to read in its markup form (so long as the concept being expressed isn't too complex: e.g. "f(x) = e^{x^2}\sqrt{\frac{x^4 + \sin(x)}{\log_{10}(x) + \frac{1}{x^{2 + \gamma}}}}"), and one has a publication system ready should one want to publish the markup for display: \(\LaTeX\).

In particular, Org Mode supports this in two ways: embedded LaTeX fragments and LaTeX source blocks.

As usual, I came to the subject while trying to scratch a personal itch. A few years ago, I got interested in Damerau-Levenshtein string distance. I surveyed the relevant literature and posted some example code on Github. Recently, oahrens filed a bug against my sample code, necessitating my re-familiarizing myself with the papers I had used as the source for the code. Since I did the initial work, I've begun using Org Roam to collect my notes, Zettelkasten style. And, of course, in Org Mode.

While working through Esko Ukkonen's "Algorithms for Approximate String Matching" 1, and taking notes in an Org Mode document, I was confronted with the need to replicate the following diagram that appeared in the paper

Ukkonen's diagram

in my Org mode notes. As per usual, I wound up wandering down the rabbit hole. A few late nights (and a few glasses of wine) later, I think I now understand how to use \(\LaTeX\) with Org Mode.

Embedded LaTeX Fragments

Paraphrasing the Org Mode manual, we can freely mix LaTeX math fragments into the document. The following stretches of text will be identified as LaTeX:

  • "Environments of any kind. The only requirement is that the '\begin' statement appears on a new line, preceded by only whitespace"
  • text marked by LaTeX math mode delimiters; '$', '\(' / '\)' & '\[' / '\]' (though they recommend against '$')

The interesting question is: what happens on export? For my particular case, only LaTeX & HTML export are of interest. In the latter case, the LaTeX snippets are passed through as-is… which is dangerous. Between Org Mode's willingness to accept arbitrary LaTeX environments and adding LaTeX packages via #+latex_header, I was able to do more & more in LaTeX while successfully exporting to LaTeX (and from there to PDF). In particular, I was able to reproduce Ukkonen's diagram like so:

#+LATEX_HEADER: \usepackage{tikz}
#+LATEX_HEADER: \usetikzlibrary{tikzmark}
# other headers...

text here...

\begin{table}[htbp]
\caption{minimal cost paths}
\centering
\begin{tabular}{lrrrrrrr}
 &  & p & a & p & l & e & t\\[0pt]
\hline
  & 0\tikzmark{a} & 2\tikzmark{b} & 4 & 6 & 8 & 10 & 12\\[0pt]
a & 2\tikzmark{c} & 3 & 2\tikzmark{d} & 4 & 6 & 8 & 10\\[0pt]
p & 4 & 2\tikzmark{e} & 4\tikzmark{f} & 2\tikzmark{g} & 4 & 6 & 8\\[0pt]
p & 6 & 4 & 5 & 4\tikzmark{h} & 5 & 7 & 9\\[0pt]
l & 8 & 6 & 7 & 6 & 4\tikzmark{i} & 6 & 7\\[0pt]
e & 10 & 8 & 6 & 8 & 6 & 4\tikzmark{j} & 6\tikzmark{k}\\[0pt]
\end{tabular}
\end{table}

\begin{tikzpicture}[remember picture, overlay]
\draw[->] ([xshift=0.5ex, yshift=0.75ex] pic cs:a) -- ([xshift=-1.5ex, yshift=0.75ex] pic cs:b);   % horiz
\draw[->] ([xshift=-0.5ex, yshift=0.0ex] pic cs:a) -- ([xshift=-0.5ex, yshift=1.75ex] pic cs:c);   % vert
... % more arrows here
\end{tikzpicture}

...text continues

tikz is a LaTeX package for diagrams. By importing it in my document's LaTeX headers, and then just writing the LaTeX in my Org Mode, the LaTeX was passed through unchanged when exporting to LaTeX and I got a very nice reproduction of Ukkonen's diagram:

Ukkonen's diagram

Then I tried exporting to HTML:

Ukkonen's diagram

Whoops. So, how does HTML export handle embedded LaTeX? It can do so in two ways: it can use MathJax at render time, or it can process the LaTeX at export time first to DVI, and then to an image file which will be included in the HTML.

MathJax

MathJax is a "JavaScript display engine for mathematics that works in all browsers". By default, Org Mode HTML export will embed the necessary JavaScript in the resulting page and render the LaTeX at page display time. Thing is, MathJax isn't a full-blown LaTeX implementation; it's a purpose-built interpreter for a certain subset of LaTeX. What subset? Well, "the [MathJax] TeX input processor implements only the math-mode macros of TeX and LaTeX, not the text-mode macros. MathJax expects that you will use standard HTML tags to handle formatting the text of your page; MathJax only handles the mathematics." 2 Note that there is a (limited, fixed) set of packages with which you can extend the MathJax interpreter.

So, MathJax is a no-go in terms of my tikz-based diagram solution. Also, I wasn't thrilled at the idea of having to make a network call across the public internet just to render my page.

Images

The other option is to transcode the LaTeX fragments into images. You can select this option by giving the file header #+OPTIONS: the value tex:dvipng (or dvisgm or imagemagick, if you'd prefer an image format other than PNG). This is not only dramatically slower, but the inline math looks… not great:

Ukkonen's diagram

This alone led me to stick with MathJax for LaTeX handling in HTML export.

Where Are We?

At this point, my plan was to use LaTeX fragments to express mathematical symbols only and use MathJax for HTML export. If I wanted to do more than that, such as replicate Ukkonen's diagram, I would drop out of Org Mode entirely, and:

  • pick my diagramming language, whether it be LaTeX, dot, ditaa or PlantUML
  • author the diagram in that language, in a separate file entirely
  • generate an image from the diagram
  • link to the image from the Org document– both PDF & HTML can handle that

LaTeX source blocks

All that said, there's a second way to embed LaTeX into Org Mode diagrams– setup a source code block (see above) containing LaTeX. But that brings up the question: what does it mean to "evaluate" a LaTeX code block? Well, per LaTeX Source Code Blocks in Org Mode: "LaTeX source code blocks can be used to tangle a LaTeX source file, or to create bitmap images or pdf snippets of arbitrary LaTeX code."

"Great!" I thought: I'll prefer LaTeX for my diagraming language & keep the diagram together with the document. Also, the ability to fine-tune the evaluation environment appealed to me.

#+BEGIN_SRC latex :results output file link replace :file ukkonen-minimal-cost-paths.png :buffer no :headers '("\\usepackage{tikz}" "\\usetikzlibrary{tikzmark}")
  \begin{table}[htbp]
  \caption{minimal cost paths}
  \centering
  \begin{tabular}{lrrrrrrr}
   &  & p & a & p & l & e & t\\[0pt]
  \hline
    & 0\tikzmark{a} & 2\tikzmark{b} & 4 & 6 & 8 & 10 & 12\\[0pt]
  a & 2\tikzmark{c} & 3 & 2\tikzmark{d} & 4 & 6 & 8 & 10\\[0pt]
  p & 4 & 2\tikzmark{e} & 4\tikzmark{f} & 2\tikzmark{g} & 4 & 6 & 8\\[0pt]
  p & 6 & 4 & 5 & 4\tikzmark{h} & 5 & 7 & 9\\[0pt]
  l & 8 & 6 & 7 & 6 & 4\tikzmark{i} & 6 & 7\\[0pt]
  e & 10 & 8 & 6 & 8 & 6 & 4\tikzmark{j} & 6\tikzmark{k}\\[0pt]
  \end{tabular}
  \end{table}

  \begin{tikzpicture}[remember picture, overlay]
  \draw[->] ([xshift=0.5ex, yshift=0.75ex] pic cs:a) -- ([xshift=-1.5ex, yshift=0.75ex] pic cs:b);   % horiz
  \draw[->] ([xshift=-0.5ex, yshift=0.0ex] pic cs:a) -- ([xshift=-0.5ex, yshift=1.75ex] pic cs:c);   % vert
  % ... many more
  \end{tikzpicture}
#+END_SRC

Huh:

Ukkonen's diagram

the reader will note that my carefully-drawn lines are nowhere to be found.

This took me some time to run-down, so I want to note it here for anyone else who stumbles upon this through search. It turns out that we often have to run LaTeX more than once. In particular, we need to do so when certain elements of the document require knowledge of the positions of other elements that are only known after a prior pass. This conversation on the Org Mode mail list put me onto the right path: and indeed, if we examine the variable org-latex-pdf-process:

org-latex-pdf-process is a variable defined in ‘ox-latex.el’.

Its value is
("%latex -interaction nonstopmode -output-directory %o %f"
 "%latex -interaction nonstopmode -output-directory %o %f"
 "%latex -interaction nonstopmode -output-directory %o %f")

Its docstring explains: "The reason why this is a list is that it usually takes several runs of ‘pdflatex’, maybe mixed with a call to ‘bibtex’. Org does not have a clever mechanism to detect which of these commands have to be run to get to a stable result, and it also does not do any error checking. Consider a smart LaTeX compiler such as 'texi2dvi' or 'latexmk', which calls the 'correct' combinations of auxiliary programs."

Ah. Alright, so what exactly was happening when I evaluated that source code block? Well, perusing the source turned up org-babel-execute:latex, which is documented as "executing" a LaTeX body. Edebug confirmed I was in the right place. It delegates to org-create-formula-image, which builds the image file in two steps: first by calling the LaTeX compiler, and then calling the image converter on the resulting dvi file. The details of what, exactly, comprises the "LaTeX compiler" are governed by the variable org-preview-latex-process-alist, where we see that by default, for each supported image type, the LaTeX compiler attribute is a list of strings containing a single invocation of LaTeX:

(defcustom org-preview-latex-process-alist
  '((dvipng
     :programs ("latex" "dvipng")
     ;; ...
     :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f"))
    (dvisvgm
     ;; ...
     :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f"))
    (imagemagick
     ;; ...
     :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f"))
    ;; ...
    )

A bit of Emacs Lisp put things right:

(plist-put
 (cdr (assoc 'dvipng org-preview-latex-process-alist))
 :latex-compiler '("latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"))

Given the fact that Org Mode correctly handles this in org-latex-pdf-process, I plan on submitting a patch for this.

Letting LaTeX be LaTeX & HTML be HTML

Still, it seemed a bit of a shame to resort to including an image in the PDF output just because that's what HTML required. And what about an .svg file, to provide better scaling? The Worg page on LaTeX source code blogs contains a tantalizing example of backend-dependent export logic. It didn't come close to working out of the box, but I was intrigued enough to keep digging.

The idea is to compute different export headers for the LaTeX source code block, at export time, for each backend. For export to LaTeX, we setup headers that will simply pass through the LaTeX source "as is", whereas for HTML export we'll produce an .svg file and include a link to that file in the final HTML output.

In order to determine the "current" backend during the export process, we need to consult the variable org-export-current-backend; that's a little prolix, so let's give ourselves a macro that will allow us to express ourselves more succinctly (I placed it at the top of the document, in a comment):

* COMMENT setup

#+BEGIN_SRC emacs-lisp :results silent
  (require 'cl-lib)
  (defmacro by-backend (&rest body)
    `(cl-case org-export-current-backend ,@body))
#+END_SRC

I then updated my source block to this:

#+HEADER: :results (by-backend (latex "latex") (t "output file link replace"))
#+HEADER: :file (by-backend (latex 'nil) (t "ukkonen-minimal-cost-paths.svg"))
#+BEGIN_SRC latex :buffer no  :headers '("\\usepackage{tikz}" "\\usetikzlibrary{tikzmark}")
  \begin{table}[htbp]
  % ...
#+END$_SRC

So when exporting to LaTeX, the LaTeX source will be passed through unchanged. When exporting to any other backend, we'll "evaluate" the source block to produce an .svg & just include the image in the output document. I have no idea if this will work with backends other than HTML; I presume it will depend on the implementation details of the given backend. I selected export to HTML and…

Ukkonen's diagram

Huh. Worse, it turns out that the code path for creating images from LaTeX for HTML export is completely different than that for "evaluating" LaTeX source blocks (with which I was already familiar, see above). I was able to track-down org-latex-compile due to a fortuitous log message & noticed that the LaTeX compilation step was choking on the line \def\pgfsysdriver{pgfsys-tex4ht.def} in the generated LaTeX file. An Org Mode list bug report clued me in to the variable org-babel-latex-preamble– I just updated it to exclude the offending line:

(setq
 org-babel-latex-preamble
  (lambda (_)
    "\\documentclass[preview]{standalone}
"))

et voilà:

org-mode-ukkonen-minimal-cost-paths-fifth-html.png

My Org Mode Configuration for LaTeX

So where are we? \(\LaTeX\) is a great way to express mathematics in Org Mode documents, but since I generally want to preserve the possibility of exporting to HTML, I'll need to limit myself to that which MathJax can handle (which I understand to be math mode macros along with this list of extensions). Org Mode natively handles many things such as emphasis, lists & tables, anyway.

If I need to do something outside of Org Mode and this subset of LaTeX, then I'll move on to a dedicated language for expressing diagrams, such as dot, ditaa or PlanUML. I'll produce an image from that and include it in the exported document. That said, there's a LaTeX package, tikz for exactly this purpose; when using that I can even arrange to just pass the LaTeX through when exporting to LaTeX (while producing an image for HTML output).

As explained in detail above, I did have to make a few minor configuration changes to get this to work, however. I had to update org-preview-latex-process-alist to invoke latex more than once:

(plist-put
 (cdr (assoc 'dvipng org-preview-latex-process-alist))
 :latex-compiler '("latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"))
(plist-put
 (cdr (assoc 'dvisvgm org-preview-latex-process-alist))
 :latex-compiler '("latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"))
(plist-put
 (cdr (assoc 'imagemagick org-preview-latex-process-alist))
 :latex-compiler '("latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"
                   "latex -interaction nonstopmode -output-directory %o %f"))

as well as touch-up org-babel-latex-preamble:

(setq
 org-babel-latex-preamble
  (lambda (_)
    "\\documentclass[preview]{standalone}
"))

Finally, I found a few packages that make entering LaTeX more ergonomic. The first is cdlatex, which is a minor mode which can be turned-on either in Org Mode or your favorite \(\TeX\) mode. However, in particular, on load cdlatex will check for texmathp, which is part of auctex:

(use-package auctex :ensure t :pin gnu)
(use-package cdlatex
  :hook ((LaTeX-mode . turn-on-cdlatex)
         (org-mode   . turn-on-org-cdlatex))
  :ensure t
  :pin nongnu)

cdlatex is fairly comprehensive, so I found it surprising that it offers little in the way of inserting the math mode delimiters themselves. I found the package math-delimiters, but I'm a bit chary of relying on it because:

  • it appears unmaintained
  • it's not on MELPA
  • it has no test suite

So I cloned it, manually installed the library & configured it thusly:

(autoload 'math-delimiters-insert "math-delimiters")

(with-eval-after-load 'org
  (define-key org-mode-map "$" #'math-delimiters-insert))

(with-eval-after-load 'tex              ; for AUCTeX
  (define-key TeX-mode-map "$" #'math-delimiters-insert))

(with-eval-after-load 'tex-mode         ; for the built-in TeX/LaTeX modes
  (define-key tex-mode-map "$" #'math-delimiters-insert))

(with-eval-after-load 'cdlatex
  (define-key cdlatex-mode-map "$" nil))

At this point, including \(\LaTeX\) in Org Mode is as simple as:

org-mode-and-latex.gif

03/19/24 08:28

Footnotes:

1

Ukkonen, E. Algorithms for Approximate String Matching. Information and Control 64 (1985), 100-118.

2

"Differences from Actual TeX — MathJax 3.2 documentation", https://docs.mathjax.org/en/latest/input/tex/differences.html (retrieved March 18, 2024)