在 rmarkdown/knitr 中使用 .Last.value
using .Last.value in rmarkdown/knitr
具有以下内容的 Rmd 文件:
```{r}
data.frame(a=1)
str(.Last.value)
```
它渲染 data.frame 但渲染 str(.Last.value)
产生 ## NULL
.
是否有任何 knitr 选项或技巧可以使它按预期工作?
第二个的预期输出
## 'data.frame': 1 obs. of 1 variable:
## $ a: num 1
因为所有代码块都是通过 eval()
在 knitr 中计算的,所以代码块的最后一个表达式不是 top-level R 表达式,并且 .Last.value
不适用于 knitr.
为了更清楚地说明这一点:
x = 1
x # a top-level expression if typed in the R console
相比之下,x
不再是 eval()
中的顶级表达式:
some_internal_knitr_function() {
# internal code
eval(parse(text = c('x = 1', 'x')))
# more internal code
}
实际上,有一种方法可以使 .Last.value
起作用。
```{r setup, include=FALSE}
knitr::opts_chunk$set(render = function(x, ...){
unlockBinding(".Last.value", .BaseNamespaceEnv)
assign(".Last.value", x, .BaseNamespaceEnv)
lockBinding(".Last.value", .BaseNamespaceEnv)
knitr::knit_print(x, ...)
})
```
这段代码定义了一个自定义渲染函数,它将输出绑定到 .Last.value
。
不过,上述修复并不完美。该行为与控制台略有不同。例如,在 R console
> x <- 2
> .Last.value
[1] 2
.Last.value returns 最后一个值,即使上一个命令是不可见的。另一方面,上述针对 knitr
的 hack 要求打印结果。
```{r}
x <- 2
x
.Last.value
```
更新
要完全使 .Last.value
像在 R 控制台中一样工作,您可以考虑以下覆盖 knitr
内部函数的高风险 hack。
```{r setup, include=FALSE}
unlockBinding("knit_handlers", getNamespace("knitr"))
evalq(
assign(
"knit_handlers",
function(fun, options) {
if (!is.function(fun)) fun = knit_print
if (length(formals(fun)) < 2)
stop("the chunk option 'render' must be a function of the form ",
"function(x, options) or function(x, ...)")
merge_list(default_handlers, list(value = function(x, visible) {
unlockBinding(".Last.value", .BaseNamespaceEnv)
assign(".Last.value", x, .BaseNamespaceEnv)
lockBinding(".Last.value", .BaseNamespaceEnv)
if (visible) fun(x, options = options)
}))
}
),
getNamespace("knitr")
)
lockBinding("knit_handlers", getNamespace("knitr"))
```
这会覆盖 knitr
内部函数 knit_handlers
,因此它随时可能中断。
具有以下内容的 Rmd 文件:
```{r}
data.frame(a=1)
str(.Last.value)
```
它渲染 data.frame 但渲染 str(.Last.value)
产生 ## NULL
.
是否有任何 knitr 选项或技巧可以使它按预期工作?
第二个的预期输出
## 'data.frame': 1 obs. of 1 variable:
## $ a: num 1
因为所有代码块都是通过 eval()
在 knitr 中计算的,所以代码块的最后一个表达式不是 top-level R 表达式,并且 .Last.value
不适用于 knitr.
为了更清楚地说明这一点:
x = 1
x # a top-level expression if typed in the R console
相比之下,x
不再是 eval()
中的顶级表达式:
some_internal_knitr_function() {
# internal code
eval(parse(text = c('x = 1', 'x')))
# more internal code
}
实际上,有一种方法可以使 .Last.value
起作用。
```{r setup, include=FALSE}
knitr::opts_chunk$set(render = function(x, ...){
unlockBinding(".Last.value", .BaseNamespaceEnv)
assign(".Last.value", x, .BaseNamespaceEnv)
lockBinding(".Last.value", .BaseNamespaceEnv)
knitr::knit_print(x, ...)
})
```
这段代码定义了一个自定义渲染函数,它将输出绑定到 .Last.value
。
不过,上述修复并不完美。该行为与控制台略有不同。例如,在 R console
> x <- 2
> .Last.value
[1] 2
.Last.value returns 最后一个值,即使上一个命令是不可见的。另一方面,上述针对 knitr
的 hack 要求打印结果。
```{r}
x <- 2
x
.Last.value
```
更新
要完全使 .Last.value
像在 R 控制台中一样工作,您可以考虑以下覆盖 knitr
内部函数的高风险 hack。
```{r setup, include=FALSE}
unlockBinding("knit_handlers", getNamespace("knitr"))
evalq(
assign(
"knit_handlers",
function(fun, options) {
if (!is.function(fun)) fun = knit_print
if (length(formals(fun)) < 2)
stop("the chunk option 'render' must be a function of the form ",
"function(x, options) or function(x, ...)")
merge_list(default_handlers, list(value = function(x, visible) {
unlockBinding(".Last.value", .BaseNamespaceEnv)
assign(".Last.value", x, .BaseNamespaceEnv)
lockBinding(".Last.value", .BaseNamespaceEnv)
if (visible) fun(x, options = options)
}))
}
),
getNamespace("knitr")
)
lockBinding("knit_handlers", getNamespace("knitr"))
```
这会覆盖 knitr
内部函数 knit_handlers
,因此它随时可能中断。