Moo*_*per 12 r knitr r-markdown r-environment
我有以下Rmd文件test.Rmd:
---
title: "test"
output: html_document
---
```{r}
print(y)
```
```{r}
x <- "don't you ignore me!"
print(x)
```
Run Code Online (Sandbox Code Playgroud)
我想以下面的方式调用render:
render('test.Rmd', output_format = "html_document",
output_file = 'test.html',
envir = list(y="hello"))
Run Code Online (Sandbox Code Playgroud)
但它失败了:
processing file: test.Rmd
|................ | 25%
ordinary text without R code
|................................ | 50%
label: unnamed-chunk-1
|................................................. | 75%
ordinary text without R code
|.................................................................| 100%
label: unnamed-chunk-2
Quitting from lines 11-13 (test.Rmd)
Error in print(x) : object 'x' not found
Run Code Online (Sandbox Code Playgroud)
第一块块很好,所以有些东西有效.如果我y在我的全局环境中定义我可以在没有envir参数的情况下运行它并且它可以正常工作.
我想也许render不喜欢列表,所以让我们给它一个合适的环境:
y_env <- as.environment(list(y="hello"))
ls(envir = y_env)
# [1] "y"
render('test.Rmd', output_format = "html_document",
output_file = 'test.html',
envir = y_env)
Run Code Online (Sandbox Code Playgroud)
但更糟糕的是,它没有找到print!
processing file: test.Rmd
|................ | 25%
ordinary text without R code
|................................ | 50%
label: unnamed-chunk-1
Quitting from lines 7-8 (test.Rmd)
Error in eval(expr, envir, enclos) : could not find function "print"
Run Code Online (Sandbox Code Playgroud)
现在文档提到使用函数,new.env因此绝望我试试这个:
y_env <- new.env()
y_env$y <- "hello"
render('test.Rmd', output_format = "html_document",
output_file = 'test.html',
envir = y_env)
Run Code Online (Sandbox Code Playgroud)
现在它有效!
processing file: test.Rmd
|................ | 25%
ordinary text without R code
|................................ | 50%
label: unnamed-chunk-1
|................................................. | 75%
ordinary text without R code
|.................................................................| 100%
label: unnamed-chunk-2
output file: test.knit.md
"C:/Program Files/RStudio/bin/pandoc/pandoc" +RTS -K512m -RTS test.utf8.md --to html --from markdown+autolink_bare_uris+ascii_identifiers+tex_math_single_backslash --output test.html --smart --email-obfuscation none --self-contained --standalone --section-divs --template "**redacted**\RMARKD~1\rmd\h\DEFAUL~1.HTM" --no-highlight --variable highlightjs=1 --variable "theme:bootstrap" --include-in-header "**redacted**\AppData\Local\Temp\RtmpGm9aXz\rmarkdown-str3f6c5101cb3.html" --mathjax --variable "mathjax-url:https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
Output created: test.html
Run Code Online (Sandbox Code Playgroud)
所以我对几件事感到困惑,回顾一下:
render识别列表(第一个块没有失败)但忽略了块中的常规分配您的两个第一个示例因不同原因而失败.要了解这两个失败,首先要了解一下knitr和rmarkdown如何评估代码块.
当您调用rmarkdown::render()文件时,每个代码块最终都会通过调用来评估evaluate::evaluate().就其评估行为和范围规则而言,其evaluate()行为几乎与基本R函数完全相同eval().
(evaluate::evaluate()最大的不同之处在于eval()它如何处理每个计算表达式的输出.如上所述?evaluate,除了评估作为第一个参数传递的表达式之外,它还"捕获重新创建输出所需的所有信息,就像复制了一样并将代码粘贴到R终端".该信息包括图表和警告以及错误消息,这就是为什么它在像knitr这样的包中非常方便!)
在任何情况下,evaluate()函数内的最终调用knitr:::block_exec()看起来都是这样的
evaluate::evaluate(code, envir = env, ...)
Run Code Online (Sandbox Code Playgroud)
其中:
code 是一个字符串向量,给出构成当前块的(可能是多个)表达式.
env是您envir在原始调用中提供正式参数的值rmarkdown::render().
在您的第一个示例中,envir是列表,而不是环境.在这种情况下,评估是在函数调用创建的本地环境中执行的.未解决的符号(如记录在这两个?eval和?evaluate)的寻找列表中的第一个传递envir的环境链,然后与由给定的开始enclos参数.至关重要的是,分配是临时评估环境的本地分配,一旦函数调用完成,它就不存在了.
因为evaluate()在表达式的字符向量上一次一个地操作,所以当envir列表时,在其中一个表达式中创建的变量将不可用于后续表达式.
当envir参数to rmarkdown::render()是一个列表时,你的代码块最终会被这样的调用评估:
library(evaluate)
code <- c('x <- "don\'t you ignore me!"',
'print(x)')
env <- list(y = 1:10)
evaluate(code, envir = env)
## Or, for prettier printing:
replay(evaluate(code, envir = env))
## > x <- "don't you ignore me!"
## > print(x)
## Error in print(x): object 'x' not found
Run Code Online (Sandbox Code Playgroud)
效果与使用以下内容完全相同eval():
env <- list(y =1 :10)
eval(quote(x <- "don't you ignore me"), envir = env)
eval(quote(x), envir = env)
## Error in eval(quote(x), envir = env) : object 'x' not found
Run Code Online (Sandbox Code Playgroud)
何时envir=返回环境as.environment(list()),您会因其他原因而出错.在这种情况下,您的代码块最终会通过以下调用进行评估:
library(evaluate)
code <- c('x <- "don\'t you ignore me!"',
'print(x)')
env <- as.environment(list(y = 1:10))
evaluate(code, envir = env)
## Or, for prettier printing:
replay(evaluate(code, envir = env))
## > x <- "don't you ignore me!"
## Error in x <- "don't you ignore me!": could not find function "<-"
## > print(x)
## Error in print(x): could not find function "print"
Run Code Online (Sandbox Code Playgroud)
正如您所指出的那样,这会失败,因为as.environment()返回一个环境,其封闭环境是空的环境(即返回的环境emptyenv()).evaluate()(就像eval()那样)寻找符号<-,env并且当它在那里找不到它时,启动封闭环境链,这里不包含任何匹配.(回想一下,当envir环境而不是列表时,enclos不使用该参数.)
要做你想做的事,你需要创建一个环境:(1)包含你列表中的所有对象; (2)具有作为其封闭环境的呼叫的父环境render()(即render()通常评估呼叫的环境).最简洁的方法是使用漂亮的list2env()函数,如下所示:
env <- list2env(list(y="hello"), parent.frame())
render('test.Rmd', output_format = "html_document",
output_file = 'test.html',
envir = env)
Run Code Online (Sandbox Code Playgroud)
这样做会导致您的代码块被代码评估,如下所示,这是您想要的:
library(evaluate)
code <- c('x <- "don\'t you ignore me!"',
'print(x)')
env <- list2env(list(y = 1:10), envir = parent.frame())
evaluate(code, envir = env)
replay(evaluate(code, envir = env))
## > x <- "don't you ignore me!"
## > print(x)
## [1] "don't you ignore me!"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
652 次 |
| 最近记录: |