-
Notifications
You must be signed in to change notification settings - Fork 117
Description
This was originally posted as a rmarkdown issue:
The general problem is that if rmarkdown::render() is called outside the global R environment, the transform function from another cell is not found.
This could happen in several cases
- New custom environment for render
rmarkdown::render(envir = new.env()) - Wrapper function
my_render <- function() rmarkdown::render("input.Rmd")
They will all fail with an error.
Rmarkdown example with ggplot2
---
title: testing
---
```{r}
neglog_trans <- function(base=10){
trans <- \(x) -logb(x,base=base)
inv <- \(x) base^(-x)
scales::trans_new("neglog", transform = trans, inverse = inv)
}
```
```{r}
trans <- scales:::as.transform("neglog")
str(trans)
```
- Fails:
rmarkdown::render("test.Rmd", envir = new.env()) - Works:
rmarkdown::render("test.Rmd")
Trying to minimize, I got down to scales and this example
evaluate::evaluate(function() {
neglog_trans <- function(base=10){
trans <- \(x) -logb(x,base=base)
inv <- \(x) base^(-x)
scales::trans_new("neglog", transform = trans, inverse = inv)
}
trans <- scales:::as.transform("neglog")
str(trans)
}, envir = new.env())
#> <evaluation>
#> Source code:
#> neglog_trans <- function(base = 10) {
#> trans <- function(x) -logb(x, base = base)
#> inv <- function(x) base^(-x)
#> scales::trans_new("neglog", transform = trans, inverse = inv)
#> }
#> Source code:
#> trans <- scales:::as.transform("neglog")
#> Condition:
#> Error in scales:::as.transform("neglog"):
#> Could not find any function named `transform_neglog()` or
#> `neglog_trans()`
#> Source code:
#> str(trans)
#> Condition:
#> Error:
#> object 'trans' not foundWhen using default environment, which will be globalenv(), it works ok
evaluate::evaluate(function() {
neglog_trans <- function(base=10){
trans <- \(x) -logb(x,base=base)
inv <- \(x) base^(-x)
scales::trans_new("neglog", transform = trans, inverse = inv)
}
trans <- scales:::as.transform("neglog")
str(trans)
})
#> <evaluation>
#> Source code:
#> neglog_trans <- function(base = 10) {
#> trans <- function(x) -logb(x, base = base)
#> inv <- function(x) base^(-x)
#> scales::trans_new("neglog", transform = trans, inverse = inv)
#> }
#> Source code:
#> trans <- scales:::as.transform("neglog")
#> Source code:
#> str(trans)
#> Text output:
#> List of 9
#> $ name : chr "neglog"
#> $ transform :function (x)
#> $ inverse :function (x)
#> $ d_transform : NULL
#> $ d_inverse : NULL
#> $ breaks :function (x, n = n_default)
#> $ minor_breaks:function (b, limits, n)
#> $ format :function (x)
#> $ domain : num [1:2] -Inf Inf
#> - attr(*, "class")= chr "transform"neglog_trans will be created in the specific envir, but it seems that when auto resolution happens at
Lines 136 to 145 in 04fc333
| # Single characters are interpreted as function names with the | |
| # `transform_`-prefix | |
| f <- paste0("transform_", x) | |
| fun <- get0(f, mode = "function") | |
| # For backward compatibility we preserve `trans_`-prefixes | |
| if (is.null(fun)) { | |
| f2 <- paste0(x, "_trans") | |
| fun <- get0(f2, mode = "function") | |
| } |
then the environment tree does not have this specific environment. From debug step at scales:::as.transform, I can see these parents where get0() will look into
Browse[1]> rlang::current_env()
<environment: 0x0000029d7e30a978>
Browse[1]> rlang::env_parents(rlang::current_env())
[[1]] $ <env: namespace:scales>
[[2]] $ <env: imports:scales>
[[3]] $ <env: namespace:base>
[[4]] $ <env: global>So this won't be looking in the same environment as where the evaluation takes place.
So using this transform feature in the knitr context won't work, unless rendering and evaluation happen in the globalenv.
I don't know if there is something that knitr or evaluate can do better or differently, or how this 'character' to function resolution can run differently.
The workaround is to use the globalenv for now, or directly use the function in transform.