Setting the Graphics Device in a RMarkdown Document

Published: April 15, 2020

In our recent post about saving R graphics, it became obvious that achieving consistent graphics across platforms or even saving the “correct” graph on a particular OS was challenging. Getting consistent fonts across platforms often failed, and for the default PNG device under Windows, anti-aliasing was also an issue. The conclusion of the post was to use

  • grDevices::cairo_pdf() for saving PDF graphics or
  • grDevices::png(..., type = "cairo_png") for PNGs or alternatively
  • the new {ragg} package.

In many workflows, function calls to graphic devices are not explicit. Instead, the call is made by another package, such as {knitr}.

When kniting an Rmarkdown document, the default graphics device when creating PDF documents is grDevices::pdf() and for HTML documents it’s grDevices::png(). As we demostrated, these are the worst possible choices!

Do you use Professional Posit Products? If so, checkout out our managed Posit services

PDFs and PNGs

If you want to save your graphs as PDFs, then simply set

knitr::opts_chunk$set(dev = "cairo_pdf")

at the top of Rmarkdown file. The PNG variant is slightly different as we need to specify the device dev and also pass the type argument to the device

knitr::opts_chunk$set(dev = "png", dev.args = list(type = "cairo-png"))

These options, i.e. dev = "cairo_pdf", can also be set at individual chunks.

The {ragg} Package

Setting the agg_png() function from the {ragg} package as the graphics device is somewhat more tricky as it doesn’t come pre-defined within {knitr}. The {knitr} docs states that

if none of the 20 built-in devices is appropriate, we can still provide yet another name as long as it is a legal function name which can record plots (it must be of the form function(filename, width, height))

The arguments of agg_png() are

#> $filename
#> [1] "Rplot%03d.png"
#> $width
#> [1] 480
#> $height
#> [1] 480

This suggests we can simply set ragg::agg_png() as the {knitr} dev, as its of the correct form. However, careful reading of the knitr source code highlights that the dpi argument isn’t passed to new devices and that the units should be inches. So after a “little” experimentation, we have

ragg_png = function(..., res = 192) {
  ragg::agg_png(..., res = res, units = "in")
knitr::opts_chunk$set(dev = "ragg_png", fig.ext = "png")

Remember the dpi argument isn’t passed to ragg_png(), so if you want to change the resolution per chunk, then you will need to use

dev.args = list(ragg_png = list(res = 192))

As {ragg} is being developed by RStudio, I’m guessing that at some point in the near future, ragg will become native to {knitr}.

Jumping Rivers Logo