在rmarkdown / knitr中使用.Last.value

时间:2015-07-17 11:52:26

标签: r knitr r-markdown

拥有以下内容的Rmd文件:

```{r}
data.frame(a=1)
str(.Last.value)
```

它呈现data.frame但呈现str(.Last.value)会产生## NULL 是否有任何针织选项或技巧可以使其按预期工作? 第二次预期输出

## 'data.frame':    1 obs. of  1 variable:
##  $ a: num 1

2 个答案:

答案 0 :(得分:5)

因为所有代码块都是通过 knitr 中的eval()进行评估的,所以代码块的最后一个表达式不是顶级 R表达式,{ {1}}不适用于 knitr

为了更清楚地说明这一点:

.Last.value

相比之下,x = 1 x # a top-level expression if typed in the R console 不再是x中的顶级表达式:

eval()

答案 1 :(得分:4)

实际上,有一种方法可以使.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控制台

> x <- 2
> .Last.value
[1] 2

即使上一个命令不可见,.Last.value也会返回最后一个值。另一方面,knitr的上述hack要求打印结果。

```{r}
x <- 2
x
.Last.value
```

更新

要完全使.Last.value像在R控制台中一样工作,您可以考虑以下高风险黑客,它会覆盖knitr内部函数。

```{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,因此可以随时中断。