Reputation: 4659
I am trying to make "new expressions" based off quosures within a function from its arguments, but am unsure of how exactly to make this new expression.
Here is an example where I pass a numerator and denominator and would ideally do mutations on both but also would like to do a mutation where I divide them:
df <- tibble(
g1 = c(1, 1, 2, 2, 2),
g2 = c(1, 2, 1, 2, 1),
a = sample(5),
b = sample(5)
)
my_divide <- function(df, numerator, denominator) {
numerator <- enquo(numerator)
denominator <- enquo(denominator)
df %>%
mutate(p = !!numerator / !!denominator)
}
my_divide(df, g1 , g2)
This fails with the following error:
Error in !denominator : invalid argument type
I could easily pass the expression as its own argument and enquo() it, but this doesn't scale for more expressions. I could also create temporary columns in the dataframe from the base quosures and then calculate the expression directly, but this seems too verbose. I imagine there's a simpler way to do this
Upvotes: 0
Views: 113
Reputation: 269694
1) /
has higher precedence than !
but we want !
to bind more tightly since we want !! to be applied prior to the division, not afterwards. Put parentheses around !!numerator
and then it will work. See ?Syntax
for documentation of the precedence rules used by the R language.
2) Another possibility but without rlang/tidyeval is:
my_divide <- function(df, numerator, denominator = 1) {
eval.parent(substitute(
df %>% mutate(p = numerator / denominator)
))
}
my_divide(df, g1 / g2)
my_divide(df, g1, g2)
Upvotes: 2
Reputation: 919
Use backticks to call the divide function.
my_divide <- function(df, numerator, denominator) {
n <- enquo(numerator)
d <- enquo(denominator)
df %>%
mutate(p = `/`(!!n, !!d))
}
my_divide(df, g1 , g2)
Upvotes: 1
Reputation: 887213
An option would be to pass it as an quoted expression for later evaluation
my_divide <- function(df, exprs) {
df %>%
mutate(p = !! exprs)
}
my_divide(df, quote(g1/ g2))
# A tibble: 5 x 5
# g1 g2 a b p
# <dbl> <dbl> <int> <int> <dbl>
#1 1.00 1.00 5 2 1.00
#2 1.00 2.00 2 4 0.500
#3 2.00 1.00 3 1 2.00
#4 2.00 2.00 4 5 1.00
#5 2.00 1.00 1 3 2.00
Upvotes: 0