Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 396
Andrew Avatar asked Mar 08 '19 23:03

Andrew


People also ask

What is the function of knitr in creating markdown document?

knitr is an engine for dynamic report generation with R. It is a package in the programming language R that enables integration of R code into LaTeX, LyX, HTML, Markdown, AsciiDoc, and reStructuredText documents. The purpose of knitr is to allow reproducible research in R through the means of literate programming.

What does knitr :: Opts_chunk set echo true mean?

The first code chunk: ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) ``` is used to specify any global settings to be applied to the R Markdown script. The example sets all code chunks as “echo=TRUE”, meaning they will be included in the final rendered version.

How does R knitr work?

When you run render , R Markdown feeds the . Rmd file to knitr, which executes all of the code chunks and creates a new markdown (. md) document which includes the code and its output. The markdown file generated by knitr is then processed by pandoc which is responsible for creating the finished format.


1 Answers

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.

like image 69
Andrew Avatar answered Sep 22 '22 22:09

Andrew