using .Last.value in rmarkdown/knitr

核能气质少年 提交于 2019-12-11 03:08:08

问题


Having and Rmd file with below content:

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

It renders data.frame but rendering str(.Last.value) produces ## NULL.
Is there any knitr option or a trick I can use to make it works as expected?
Expected output from the second

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

回答1:


Actually, there is a way to make .Last.value to work.

```{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, ...)
})
```

This piece of code defines a custom render function which binds the output to .Last.value.

Though, the above fix is not prefect. The behaviour is a little bit different from the console. For example, in R console

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

The .Last.value returns the last value even if the previous command is nonvisible. On the other hand, the above hack for knitr requires that the result was printed.

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

Update

To fully make .Last.value works as in R console, instead, you could consider the following high-risk hack which overwrites knitr internal function.

```{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"))
```

This overwrites the knitr internal function knit_handlers, so it subjects to break at anytime.




回答2:


Because all code chunks are evaluated via eval() in knitr, the last expression of a code chunk is not a top-level R expression, and .Last.value will not work for knitr.

To make this more clear:

x = 1
x  # a top-level expression if typed in the R console

By comparison, x is no longer a top-level expression in eval():

some_internal_knitr_function() {
  # internal code
  eval(parse(text = c('x = 1', 'x')))
  # more internal code
}


来源:https://stackoverflow.com/questions/31475226/using-last-value-in-rmarkdown-knitr

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!