I stumbled over an issue when using NSE in a custom function inside dplyr::mutate
. Consider the following code:
require(tidyverse)
f <- function(var) {
varname <- deparse(substitute(var))
v1 <- as.name(sprintf("%s.Width", varname))
v2 <- as.name(sprintf("%s.Length", varname))
return(substitute(v1 + v2))
}
iris %>%
mutate(
test = f(Sepal) %>% eval()
)
ff <- function(var) {
varname <- deparse(substitute(var))
v1 <- as.name(sprintf("%s.Width", varname))
v2 <- as.name(sprintf("%s.Length", varname))
substitute(v1 + v2) %>% eval.parent(n = 1)
}
iris %>%
mutate(
test = ff(Sepal)
)
Here f
works fine but requires an external call to eval()
to execute the code inside the mutate()
environment.
This is of course a bit ugly and leads to a lot of boilerplate code. My best guess at making this work was ff
which tries to evaluate the constructed expression in its calling environment - which I expected to be the mutate()
environment. However, this throws a variable-not-found error.
Any thoughts on how to make this work and what the underlying issue is? Essentially I want allow custom 'macros' in dplyr verbs.
Using the !!
tidy eval "unquote" operator:
ff <- function(var) {
varname <- deparse(substitute(var))
v1 <- as.name(sprintf("%s.Width", varname))
v2 <- as.name(sprintf("%s.Length", varname))
substitute(v1 + v2)
}
iris %>%
head() %>%
mutate(
test = !! ff(Sepal)
)