LaTeX exam templates with R & Rmarkdown
LaTeX: The final fontier
Happy New Year! 2022’s holiday blog post is brought to you by the letters LaTeX. I do not use LaTeX outside the rmarkdown
environment so I wanted to familiarize myself with its more advanced typesetting features.
If you’re thinking of typesetting a manuscript, then this is not the post for you. I used an exam as the example (pun not intended) to play with.
tl;dr I made an
rmarkdown
template for an exam paper using LaTeX {exam}. It supports R code chunks and shows or hides the answers.
Accessing the template
You need to be able to create PDFs with rmarkdown
(pandoc and LaTeX). rmarkdown
templates need to be housed within a package.
- If you don’t want to create your own R package, the template can be downloaded ready to use via the package
biostats.tutorials
on my GitHub - You can get the files to add to your own package from the Gist
When you have the templates installed, you should be able to see them listed when you create a an R markdown document from template.
LaTeX {exam}
LaTeX has a document type called {exam} that contains helper functions for typesetting an exam. For example, defining questions, solutions, or showing mark allocations. It’s pretty straightforward to get a basic template set up by following the documentation.
This option is fine if you are working purely in LaTeX and a TeX editor. But it doesn’t work with R. R would be pretty important if for example you wanted to integrate R output. Of course, you could typeset an exam in rmarkdown
with a more generic document class but you miss out on the more specific functions.
Rmarkdown & LaTeX
There’s a lot of technical information to gloss over but there are three general ways to use LaTeX with rmarkdown
. Each way has its advantages and disadvantages to achieve our desired outcome: a nicely formatted exam template with R code that’s able to also show the answers.
1. Rnw
An Rnw (Sweave) file is a LaTeX file that supports R code. Meaning rather than a document written in markdown with code chunks and some LaTeX, you have a document written in LaTeX with code chunks and no markdown. Knitting proceeds as normal - be sure to change your setting from Sweave to knitr for Rnw files in your global settings.
I found this to be the second best option and a decent alternative to my best option. It produces the desired outcome using {exam} provided the R code is relatively simple. However, your document will be very TeX heavy so avoid it if TeX is not your strong suit.
2. TeX template
Another one for advanced TeX users. This way you make your own template that Pandoc uses to generate the PDF. However, this template seems to override the Pandoc template so you need a complete template with all the bells and whistles. This is probably the better option in terms of customisation and using LaTeX to the best of its ability. But involving Pandoc makes the behind-the-scenes workflow more complex, such as specifying to LaTeX how Pandoc creates bulleted lists. And I don’t know anything about TeX templates.
The bookdown handbook recommends to start from the original Pandoc LaTeX template but I could not get the template to work out of the box from GitHub. Something about not knowing what to do with plots.
There are lots of templates out there that don’t necessarily use {exam} that you could use. Once you have the template you can call it in the YAML like:
output:
pdf_document:
template: template.tex
3. Preambles
In the end I found using preambles was the best compromise. You can include TeX files in YAML like:
output:
pdf_document:
includes:
before_body: cover.tex
in_header: preamble.tex
This method allowed most of the functions and aesthetics of {exam}, like a cover page and a header and footer. These TeX snippets don’t override the template but they are not dynamic and cannot be linked to YAML variables. For example, you cannot use the title of your document as set in the YAML in the header. You could via $ operators in a TeX template.
The benefits are that you can package your files as an rmarkdown
template and you can write in markdown, which is easier for me. The main drawback is that you cannot use code highlighting because there is an issue with a LaTeX package called framed
. I couldn’t find a workaround that worked for me (See this StackExchange). If you want to use echo = TRUE
as a chunk option then you need to set highlight: NULL
in YAML:
output:
pdf_document:
highlight: NULL
includes:
before_body: cover.tex
in_header: preamble.tex
Workflow
The template involves three files. See the gist.
1. skeleton.Rmd
This is the main template. usethis::use_rmarkdown_template()
will generate the correct folder structure and empty files for you. The template contains two example questions for how a question could be laid out but the heavy lifting is done automatically by document class {exam}, as called in the YAML. Remove classoption: answers
to hide the answers when knitting.
2. cover.tex
This creates a cover page containing generic instructions, the class and exam name as set in the YAML, and space for students to write their name and student number. This is like TeX that goes before \begin{document}
. This file is all aesthetics. The document works without it.
3. preamble.tex
This is the more important TeX file because there are some pecularities with how Pandoc and LaTeX talk to each other. First, we can avoid using \begin{}
or \end{}
commands by redefining them (See this StackOverflow). The three main ones used in {exam} are for questions, questions with multiple parts, and solutions. Second, Pandoc does not know how to deal with all {exam} functions so you need to help it a little (See this GitHub issue). We need to tell it how to understand we want a question with multiple parts like a) and b).
End notes
After all that I still know nothing about how Pandoc or LaTeX works.