Andrew
Andrew

Reputation: 38709

knitr generating errors in document but generates figures correctly regardless

I'm knitting an R Markdown file on macOS and I'm using knitr::opts_chunk$set(dev = c("png", "cairo_pdf")) to save the output of plots as PNG and PDF files simultaneously. I'm also using the Cairo PDF library since it can embed fonts correctly by default (see here)

When I knit and create a plot that uses a custom font, knitr correctly saves both the PNG and PDF files using Cairo:

figure output

However, in the actual knitted R Markdown document, R complains about missing fonts and provides dozens of warnings. This is odd, since it is working just fine behind the scenes.

Here's a MWE:

---
title: "So many warnings?"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(fig.path = "fig/",  # Save images to a subdirectory
                      echo = FALSE,  # Hide code for now
                      dpi = 300,  # High resolution PNGs
                      # Save all figures as Cairo PDFs and PNGs
                      dev = c("png", "cairo_pdf"),
                      dev.args = list(png = list(type = "cairo")))
```

```{r load-libraries}
library(ggplot2)
```

```{r warningless-plot}
# This will save two files in the fig/ folder, both saved using Cairo:
# - fig/warningless-plot-1.png
# - fig/warningless-plot-1.pdf

ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()
```

```{r warningful-plot}
# This will save two files in the fig/ folder, both saved *correctly* using Cairo:
# - fig/warningful-plot-1.png
# - fig/warningful-plot-1.pdf

# However, rmarkdown or knitr or something in the pipeline gets mad and throws 
# a ton of warnings.

ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  theme_grey(base_family = "Comic Sans MS")
```

The figures themselves are saved correctly, but the HTML output is full of these warnings:

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
## font family 'Comic Sans MS' not found in PostScript font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :    
## font family 'Comic Sans MS' not found in PostScript font database

Right now my solution is to add warning=FALSE to the chunk options for warningful-plot and all other chunks that generate plots with custom fonts. I'd like to know why these extra warnings are happening, though, and if there's a way to avoid getting warnings in the first place.

Upvotes: 5

Views: 593

Answers (1)

Andrew
Andrew

Reputation: 38709

Answering my own question here…

According to a couple issues on GitHub (at knitr and hrbrthemes), this happens because knitr invisibly uses a null PDF device (pdf(NULL)) in the background when actually knitting. The default pdf() graphics device in R can't handle custom fonts, though, hence the warnings. Even though none of the visible graphics ever go through the base pdf() device, they still go through it invisibly I guess.

When knitting using dev = 'png', knitr will use an invisible png() device and no warnings will be thrown. It seems that using a cairo_pdf device at the same time breaks this and forces knitr to go back to an invisible, custom-font-less pdf() device.

We can fix this by forcing knitr to use an invisible png() device instead, based on this comment here:

# Use invisible NULL png() device
options(device = function(file, width, height) {
  png(tempfile(), width = width, height = height)
})

# knit options, including `dev = c("png", "cairo_pdf")`
knitr::opts_chunk$set(fig.path = "fig/",  # Save images to a subdirectory
                      echo = FALSE,  # Hide code for now
                      dpi = 300,  # High resolution PNGs
                      # Save all figures as Cairo PDFs and PNGs
                      dev = c("png", "cairo_pdf"),
                      dev.args = list(png = list(type = "cairo")))

That options(device = ...) incantation makes the warnings go away.

Upvotes: 5

Related Questions