New R/exams Version: TinyTeX, Fixing Parameters and Random Seeds, and More
R/exams on CRAN screenshot (CC-BY).

New R/exams Version: TinyTeX, Fixing Parameters and Random Seeds, and More

New minor releases of the R/exams package to CRAN with many enhancements including TinyTeX support and extended control over the random variation in dynamic exercises through fixed parameters or custom random seeds.

New versions of the R/exams package (2.3-5 and 2.3-6) have been released on the Comprehensive R Archive Network at The second update was necessitated by more thorough checks for pandoc availability on Solaris and OS X. In the next days binary Windows and OS X packages should also become available. The development version of the package is now version 2.4-0 on R-Forge at

TinyTeX support

R/exams users that want to produce PDF output, e.g., via exams2pdf() or exams2nops(), need to install LaTeX for rendering the exercises. Especially for users that do not write LaTeX documents themselves (but only Markdown instead) it is now much easier to install a lightweight LaTeX distribution thanks to the wonderful TinyTeX package by Yihui Xie. All that needs to be done is:


The latter installs the TinyTeX distribution and the former makes the R interface available. After that it is recommended to run exams2nops() once:

exams2nops(c("swisscapital.Rmd", "deriv2.Rmd"))

This takes a while because some additional LaTeX packages will be downloaded and installed automatically. Running the same command a second time will be much faster because then all required LaTeX packages will already be available.

If the tinytex R package is installed, the default is to compile PDF exams with tinytex::latexmk(); otherwise tools::texi2dvi() is used (which does not offer automatic LaTeX package installation). If the latter should be used even when requireNamespace("tinytex") is true, then options(exams_tex = "tools") can be set (instead of exams_tex = "tinytex")

Fixing parameters and seeds

One frequent feature request for R/exams was to reduce the amount of random variation in exams even if the underlying exercise templates offer more flexibility. Application cases are where teachers want to control each randomly selected exercise in a quiz or exam manually. To address this, two mechanisms are provided now:

  1. Some of the parameters that would usually be sampled randomly can be temporarily fixed (on the fly) by using the new function expar().
  2. Several exams2xyz() interfaces gained a seed argument with which dedicated random seeds can be selected per exercise.

Fixing parameters

The first feature is of interest, for example, if computing the solution becomes harder when a certain parameter increases or takes a particular value. The new function expar() allows to fix such parameters on the fly if they are defined in the first code chunk of the exercise. For example

expar("deriv.Rmd", a = 1, c = 0)

generates a temporary file where the parameters a and c of the deriv exercise are fixed to the values 1 and 0, respectively. The result can then be processed by all exams2xyz() interfaces “as usual”, e.g.:

  expar("deriv.Rmd", a = 1, c = 0),

A potential caveat is that expar() either needs the exercise file to be available locally in the current working directoy or with the full path. It does not work with the edir argument of subsequent exams2xyz() calls.

Fixing seeds

Some exams2xyz() interfaces now support setting seeds for each individual exercise in an exam to enable custom exercise selection (e.g., when only putting together a single exam). Currently, this is only supported in xexams(), exams2pdf(), exams2html(), exams2nops(), and exams2blackboard(). Other interfaces will follow, though.

Thus, using this feature, teachers can try a few random seeds for a given exercise until they get a variant they like. Then they do the same with the next exercise etc. At the end all exercises and all seeds are collected and passed on in this form: exams2xyz(c(exercise1, exercise2, ...), seed = c(seed1, seed2, ...)).

Moreover, in the exams2xyz() interfaces that support setting seeds, the file argument can now also be a matrix (rather than a vector or list). This enables customization of the exact selection of exercises in each exam. In the example below we use exactly the same random replication of the deriv and tstat exercises, respectively, but permute their order. The final exercise is ttest in both cases but with different seeds.

f <- rbind(
  c("deriv.Rmd", "tstat.Rmd", "ttest.Rmd"),
  c("tstat.Rmd", "deriv.Rmd", "ttest.Rmd")
s <- rbind(
  c(123, 321, 111),
  c(321, 123, 222)
exams2html(f, seed = s)

Written exams (NOPS)

The tools for written NOPS exams that can be automatically scanned and evaluated have been enhanced.

  • Several users were kind enough to provide new language support: Korean (ko, 정세원), Japanese (ja, Kohei Watanabe), Norwegian (Bokmål, no, Tormod Bøe), Slovenian (sl, Matjaž Jeran), Vietnamese (vi, Trần Thị Hoàng Hà).
  • Improvements in nops_eval(): Show exam ID in HTML report and round points to four digits. The language= file paths do not have to be absolute anymore. For interactive checking/fixing of registration IDs the width of scanned subimage is now adapted according to the reglength.
  • The actual writing of nops_eval() results has been modularized (with contributions from Kenji Sato). Different nops_eval_write_<flavor> functions can be plugged in. At the moment there is only the default writer (optimized for OpenOlat) but further flavors are planned (including a standalone workflow and one for Moodle).
  • Function nops_language() is now exported as part of the user interface (only internal previously). Based on a language specification in a DCF file this sets up a list with language texts (possibly converted to HTML).

Improvements and bug fixes

  • New exercise capitals that illustrates how a certain number of true/false items can be chosen randomly from a longer list. The exercise can also be switched from mchoice to schoice without any further necessary modifications. Finally, the exercise illustrates that UTF-8 encoding is needed for the Rmd version while in the Rnw version the few special characters can be coded in ASCII using LaTeX commands.
  • All LaTeX templates that use \fontfamily{phv} now also gained a \usepackage{helvet} to ensure that the corresponding LaTeX packages are installed. When using tinytex (see above) the corresponding LaTeX packages will be installed if not yet available upon first usage.
  • In R/Markdown exercises the question/solution answerlist can now use not only * but also - as the symbol for bullet points (suggested by Ben Kasel).
  • Fixed a bug in exams2pdf() where the case of multiple duplicated supplement names was not handled correctly (reported by TwelveFifths on StackOverflow).
  • Improved xexams() so that full file paths to exercise files also work on Windows.
  • read_metainfo() now assures a non-NULL exname. The default is to use “R/exams exercise”.
  • Fixed a bug in extract_items() which incorrectly dropped the last element in an answerlist if it was completely empty (even without a trailing space). This was a problem for cloze exercises with ##ANSWER## patterns, leading to a questionlist that was too short (reported by Julia Guggenberger).
  • Various fixes and improvements in exams2qti21() (and thus inherited by exams2openolat()): Support of cloze and essay type exercises has been much improved, fixing bugs in the XML and meta-information handling. String exercises work again. The internally-generated XML labels are more robust now avoiding spaces and leading integers.
  • The package depends on R >= 3.4.0 now, which enables plugging a custom svg device into Sweave(). In previous versions of the package a workaround was included that works for R < 3.4.0 (but required writing into the global environment which is avoided now).