Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to request an early exit when knitting an Rmd document?

Tags:

markdown

r

knitr

Let's say you have an R markdown document that will not render cleanly.

I know you can set the knitr chunk option error to TRUE to request that evaluation continue, even in the presence of errors. You can do this for an individual chunk via error = TRUE or in a more global way via knitr::opts_chunk$set(error = TRUE).

But sometimes there are errors that are still fatal to the knitting process. Two examples I've recently encountered: trying to unlink() the current working directory (oops!) and calling rstudioapi::getVersion() from inline R code when RStudio is not available. Is there a general description of these sorts of errors, i.e. the ones beyond the reach of error = TRUE? Is there a way to tolerate errors in inline R code vs in chunks?

Also, are there more official ways to halt knitting early or to automate debugging in this situation?

like image 981
jennybryan Avatar asked Nov 14 '15 06:11

jennybryan


People also ask

How do you knit RMD without running?

If you don't want any code chunks to run you can add eval = FALSE in your setup chunk with knitr::opts_chunk$set() . If you want only some chunks to run you can add eval = FALSE to only the chunk headers of those you don't want to run.

How do you RMD in R in knitting?

To transform your markdown file into an HTML, PDF, or Word document, click the “Knit” icon that appears above your file in the scripts editor. A drop down menu will let you select the type of output that you want. When you click the button, rmarkdown will duplicate your text in the new file format.

How do you comment out an RMD?

After drag the lines you want to make comment, press SHIFT + CMD + C (macOS), SHIFT + CTRL + C (Windows). This is the shortcut of R Markdown editor (R Studio) to comment out. For me it was Ctrl+ Shift + C.

How do I hide a chunk in my RMD?

Chunk options You use results="hide" to hide the results/output (but here the code would still be displayed). You use include=FALSE to have the chunk evaluated, but neither the code nor its output displayed.


2 Answers

To exit early from the knitting process, you may use the function knitr::knit_exit() anywhere in the source document (in a code chunk or inline expression). Once knit_exit() is called, knitr will ignore all the rest of the document and write out the results it has collected so far.

There is no way to tolerate errors in inline R code at the moment. You need to make sure inline R code always runs without errors1. If errors do occur, you should see the range of lines that produced the error from the knitr log in the console, of the form Quitting from lines x1-x2 (filename.Rmd). Then you can go to the file filename.Rmd and see what is wrong with the lines from x1 to x2. Same thing applies to code chunks with the chunk option error = FALSE.

Beyond the types of errors mentioned above, it may be tricky to find the source of the problem. For example, when you unintentionally unlink() the current directory, it should not stop the knitting process, because unlink() succeeded anyway. You may run into problems after the knitting process, e.g., LaTeX/HTML cannot find the output figure files. In this case, you can try to apply knit_exit() to all code chunks in the document one by one. One way to achieve this is to set up a chunk hook to run knit_exit() after a certain chunk. Below is an example of using linear search (you can improve it by using bisection instead):

#' Render an input document chunk by chunk until an error occurs #'  #' @param input the input filename (an Rmd file in this example) #' @param compile a function to compile the input file, e.g. knitr::knit, or #'   rmarkdown::render knit_debug = function(input, compile = knitr::knit) {   library(knitr)   lines = readLines(input)   chunk = grep(all_patterns$md$chunk.begin, lines)  # line number of chunk headers    knit_hooks$set(debug = function(before) {     if (!before) {       chunk_current <<- chunk_current + 1       if (chunk_current >= chunk_num) knit_exit()     }   })    opts_chunk$set(debug = TRUE)    # try to exit after the i-th chunk and see which chunk introduced the error   for (chunk_num in seq_along(chunk)) {     chunk_current = 0  # a chunk counter, incremented after each chunk     res = try(compile(input))     if (inherits(res, 'try-error')) {       message('The first error came from line ', chunk[chunk_num])       break     }   } } 

  1. This is by design. I think it is a good idea to have error = TRUE for code chunks, since sometimes we want to show errors, for example, for teaching purposes. However, if I allow errors for inline code as well, authors may fail to recognize fatal errors in the inline code. Inline code is normally used to embed values inline, and I don't think it makes much sense if an inline value is an error. Imagine a sentence in a report like The P-value of my test is ERROR, and if knitr didn't signal the error, it will require the authors to read the report output very carefully to spot this issue. I think it is a bad idea to have to rely on human eyes to find such mistakes.
like image 92
Yihui Xie Avatar answered Sep 22 '22 19:09

Yihui Xie


IMHO, difficulty debugging an Rmd document is a warning that something is wrong. I have a rule of thumb: Do the heavy lifting outside the Rmd. Do rendering inside the Rmd, and only rendering. That keeps the Rmd code simple.

My large R programs look like this.

data <- loadData() analytics <- doAnalytics(data) rmarkdown::render("theDoc.Rmd", envir=analytics) 

(Here, doAnalytics returns a list or environment. That list or environment gets passed to the Rmd document via the envir parameter, making the results of the analytics computations available inside the document.)

The doAnalytics function does the complicated calculations. I can debug it using the regular tools, and I can easily check its output. By the time I call rmarkdown::render, I know the hard stuff is working correctly. The Rmd code is just "print this" and "format that", easy to debug.

This division of responsibility has served me well, and I can recommend it. Especially compared to the mind-bending task of debugging complicated calculations buried inside a dynamically rendered document.

like image 27
pteetor Avatar answered Sep 24 '22 19:09

pteetor