9

How do I permit errors within \Sexpr?

I have a knitr document. A small part of this document refers to a file that cannot be shared. So whenever \Sexpr{a} is called on for some object a that depends on that file being read, it returns an error. I'd like instead for \Sexpr to print that it encountered an error.

For example,

\documentclass{article}
\usepackage{xcolor}  % for red

\begin{document}

<<>>=
x <- 1
@

The value of $x$ is \Sexpr{x}

<<>>=
a <- scan("secret_file.txt")
@
The value of $a$ is \Sexpr{a}.

\end{document}

will not compile (when secret_file.txt isn't present). I'd like the output to look something like:Sexpr-error-detected

I thought that altering the inline hook would work, but putting the following chunk made no difference.

<<Sexpr-setup>>=
library(knitr)
knit_hooks$set(inline = function(x){
  out <- tryCatch(
    {
      if (is.numeric(x)) 
        x = round(x, getOption("digits"))
      paste(as.character(x), collapse = ", ")
    }, 
    error = function(cond){
      return("\\textcolor{red}{\\textbf{Sexpr error!}}")
      invisible(NULL)
    }, 
    warning = function(cond){
      return("\\textcolor{red}{\\textbf{Sexpr warning!}}")
      invisible(NULL)
    }
  )
  return(out)
})
@

It is not essential to have a custom error message, only that errors are clear from the output and do not prevent compilation. I appreciate that I could do a find replace into something like \Sexpr{XX( and define a function upfront XX() that does the same tryCatch maneouvre, but I thought knitr could do this.


Calling knitr::knit on the above and applying the traceback shows that:

11: eval(expr, envir, enclos)
10: eval(parse_only(code[i]), envir = envir)
9: withVisible(eval(parse_only(code[i]), envir = envir))
8: inline_exec(block)
7: in_dir(opts_knit$get("root.dir") %n% input_dir(), inline_exec(block))
6: call_inline(x)
5: process_group.inline(group)
4: process_group(group)
3: withCallingHandlers(if (tangle) process_tangle(group) else process_group(group), 
       error = function(e) {
           setwd(wd)
           cat(res, sep = "\n", file = output %n% "")
           message("Quitting from lines ", paste(current_lines(i), 
               collapse = "-"), " (", knit_concord$get("infile"), 
               ") ")
       })
2: process_file(text, output)
1: knitr::knit("knitr-prevent-errors.Rnw", quiet = TRUE)

From following the functions, it appears that the error is low down at

eval(parse_only(code[i]), envir = envir)

Where code[i] is a. Am I right in thinking that the only way to resolve this is to change the line starting v = with a tryCatch?

Community
  • 1
  • 1
Hugh
  • 15,521
  • 12
  • 57
  • 100
  • Not sure whether the answer [here](https://stackoverflow.com/questions/24978427/suppressing-error-messages-in-knitr) could be adapted to your problem. The answer by Josh O'Brien changes the error hook function. The knitr documentation [here](http://yihui.name/knitr/hooks/) suggest that this hook handles the errors for both chunks and inline code. `error: errors from stop() (applies to errors in both code chunks and inline R code)`. I had a quick play with adding `knit_hooks$set(error=myErrorFunction)` with your code but I still couldn't get it to compile with `\Sexpr{a}`. – Graeme Apr 19 '16 at 12:58
  • Thanks. Yes that will only work for in-chunk options – Hugh Apr 19 '16 at 13:48

1 Answers1

5

With the option include=FALSE in the setup chunk,the following worked for me with output as below. If it does not work for you I will delete the post

enter image description here

\documentclass{article}
\usepackage{xcolor}  % for red


<<setup, include=FALSE>>= 
knit_hooks$set(inline = function(x) {

out <- tryCatch(
    {
      if (is.numeric(x)) 
        x = round(x, getOption("digits"))
      paste(as.character(x), collapse = ", ")
    }, 
    error = function(cond){
      return("\\textcolor{red}{\\textbf{Sexpr error!}}")
      invisible(NULL)
    }, 
    warning = function(cond){
      return("\\textcolor{red}{\\textbf{Sexpr warning!}}")
      invisible(NULL)
    }
  )

return(out)

})
@ 



\begin{document}

<<>>=
x <- 1
@

The value of $x$ is \Sexpr{x}

<<>>=
a <- scan("secret_file.txt")
@
The value of $a$ is \Sexpr{a}.

\end{document}

Knitr Output:

>knitr::knit("test.Rnw")


processing file: test.Rnw
  |.........                                                        |  14%
  ordinary text without R code

  |...................                                              |  29%
label: setup (with options) 
List of 2
 $ include: logi FALSE
 $ indent : chr "    "

  |............................                                     |  43%
  ordinary text without R code

  |.....................................                            |  57%
label: unnamed-chunk-1 (with options) 
List of 1
 $ indent: chr "    "

  |..............................................                   |  71%
   inline R code fragments

  |........................................................         |  86%
label: unnamed-chunk-2 (with options) 
List of 1
 $ indent: chr "    "

  |.................................................................| 100%
   inline R code fragments


output file: test.tex

[1] "test.tex"

Tex Output:

>texi2pdf("test.tex")
>

I am using MikTex 2.9,knitr 1.9, R 3.0.2 on Windows , can you please attach your log files then we can compare the differences if any

Silence Dogood
  • 3,587
  • 1
  • 13
  • 17
  • So I didn't get it to compile, but I'd like to explore this a bit more. What do you get when you `knitr::knit` your file? – Hugh Apr 19 '16 at 22:59
  • How are you getting this to work without `library(knitr)` in `test.Rnw`? – Hugh Apr 22 '16 at 03:04
  • Sorry I did not mention. In RStudio 0.95.551, I do `library(knitr)` first and then `knit("test.Rnw")`. Are you trying to compile the file from commandline – Silence Dogood Apr 22 '16 at 11:00