Courvoisier
Courvoisier

Reputation: 993

RStudio 1.1.383 and rmarkdown 1.7 environment enheritance

On Windows 7 64 bits, I have recently updated to RStudio 1.1.383 and rmarkdown 1.7. As I am using render to produce a pdf from an Rmd file I have noticed a new behavior.

  1. There is leakage between the Global Environment and the knitting environment and it goes both ways:
  2. If I define x = 12 in the .Rmd file, I find x in the Global environment after the render is complete.
  3. If I use an undefined variable y in the .Rmd and I set y=1000 in the global environment before using render then y is used in the knitting of the .Rmd
  4. If I do knit from RStudio the leakage does not occur and even if y is defined in the global environment, knitting the .Rmd will give an error (y not found).

Does anyone know why is that? I believe separating the environment is very important to ensure reproducibility even though it is sometimes painful to get right.

Here is my sessionInfo():

> sessionInfo()
R version 3.4.2 (2017-09-28)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                           LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] rmarkdown_1.7

loaded via a namespace (and not attached):
 [1] compiler_3.4.2  backports_1.1.1 magrittr_1.5    rprojroot_1.2   htmltools_0.3.6 tools_3.4.2     yaml_2.1.14     Rcpp_0.12.13   
 [9] stringi_1.1.5   knitr_1.17      stringr_1.2.0   digest_0.6.12   evaluate_0.10.1

Here is the minimal "test render.R" file:

library(rmarkdown)
y=1000
render(input = "test render.Rmd")

and Here is the minimal "test render.Rmd" file:

---
title: "test render"
author: "Courvoisier"
output: pdf_document
---

## R Markdown

```{r cars}
x = 12
print(y)
```

and here is the pdf result:

enter image description here

Upvotes: 1

Views: 283

Answers (1)

Yihui Xie
Yihui Xie

Reputation: 30174

As far as I can tell, this behavior has been there since Day 1. Here is how to prove it. First install the very first version (0.3.3) of rmarkdown from the CRAN archive:

devtools::install_version('rmarkdown', '0.3.3')

And run your example:

library(rmarkdown)
y = 1000
render(input = "test render.Rmd")

You see y is printed (as I'd expect):

rmarkdown 0.3.3

This behavior is by design and I don't know why it is surprising to you. In R, global variables are accessible from anywhere (by definition). You defined y in the global environment, and you should expect it to be accessible in the R Markdown document, too.

The R Markdown document is compiled in the environment parent.frame() of render(), and all variables will be created in this environment. In your case, parent.frame() is the global environment (i.e. globalenv()), and that explains why x was created in the global environment.

When you click the Knit button in RStudio, it is different because the document is compiled in a separate new (clean) R session. The variable y you defined in the current R session will not be available to the new R session. Similarly, x will be created in the new session and not in your current R session. Reproducibility is exactly why we chose to compile R Markdown documents in new R sessions instead of the current R session. If a document works in a new R session, it is more likely to be reproducible. If it works in your current R session (via rmarkdown::render()), it might just work by chance.

If you have to evaluate code chunks in a separate environment, you need to use the argument envir explicitly, e.g.

render(input = "test.Rmd", envir = new.env())

This way, x will not be created in your global environment, but y will be available to the code chunk (again, by definition of global variables).

In all, if you really care about reproducibility (like we do), there is an easy way and a slightly harder way. The easy way is to click the Knit button in RStudio, and the harder way is to render the document in a separate R session by yourself, e.g., via the command line

Rscript -e "rmarkdown::render('test.Rmd')"

Upvotes: 2

Related Questions