Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

knitr inherits variables from a user's environment, even with envir = new.env()

Tags:

r

knitr

I've found that a knitr document inherits variables from the user's environment, even if the argument envir = new.env() is provided. How can I prevent it from inheriting these variables?

For instance, suppose I wrote a simple .Rmd file using a variable that doesn't exist (y), knitted it, and showed the resulting file:

library(knitr)
writeLines(c("```{r}", "y + 1", "```"), "test.Rmd")
knit("test.Rmd", quiet = TRUE, envir = new.env())
# [1] "test.md"
cat(readLines("test.md"), sep = "\n")
# 
# ```r
# y + 1
# #> Error in eval(expr, envir, enclos): object 'y' not found
# ```

Of course, I get an error that the y variable doesn't exist, just as I should.

However, if I then define y in my own environment, I find I can now refer to y in the .Rmd file, even though I give the envir = new.env() argument.

y <- 3
knit("test.Rmd", quiet = TRUE, envir = new.env())
# [1] "test.md"
cat(readLines("test.md"), sep = "\n")
#
# ```r
# y + 1
# # [1] 4
# ```

My understanding was that envir = new.env() should have caused the knitr document to be evaluated in a new environment without the y variable. This is a problem because it allows knitr documents to be non-reproducible, referring to variables I don't define within the document.

Note that the rmarkdown render documentation (which is a wrapper around knit) specifically says you can use envir = new.env():

The environment in which the code chunks are to be evaluated during knitting (can use new.env() to guarantee an empty new environment).

However, render shows the same behavior as above, for the same reason. Are my expectations (and the rmarkdown docs) incorrect about envir = new.env(), or am I using it incorrectly? And is there another way to guarantee a new environment in a document being knitted?

like image 233
David Robinson Avatar asked Aug 27 '15 19:08

David Robinson


People also ask

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.

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.

How do you use the knitr in RStudio?

If you are using RStudio, then the “Knit” button (Ctrl+Shift+K) will render the document and display a preview of it.


1 Answers

new.env has a parent argument whose default is parent.frame() — i.e. the caller. In other words, your new environment inherits all the stuff from your current environment.

You can avoid this by specifying parent:

new.env(parent = baseenv())

Or, if you want to inherit loaded packages:

new.env(parent = as.environment(2))

And, yes, the render documentation is somewhat misleading: while new.env() provides a new, empty environment, it’s not entirely decoupled from the caller, and the caller probably almost never wants to use just new.env().

In order to be able to use packages inside a clean environment inherited from baseenv(), you need to manually implement the package attachment mechanism because R packages do not support environment isolation by themselves (grrr!). Or you use the ‘box’ package, which supports locally attached packages:

```{r}
box::use(ggplot2[...])
qplot(rnorm(10))
```

The [...] declaration causes the package to be attached locally (in the current scope), unlike with library.

like image 65
Konrad Rudolph Avatar answered Sep 25 '22 11:09

Konrad Rudolph