问题
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