Reputation: 483
I was trying to generate an expression in a separate function. To prevent repetitive code. The expression is then passed onto ggplot.
This works fine (a simple expression)
ggplot(mpg, aes(x = model, y = displ)) + geom_boxplot()
This works fine too (an expression with formula and string)
x = "displ"
xVar = expr(!!ensym(x) * 2)
ggplot(mpg, aes(x = model, y = !!xVar)) + geom_boxplot()
This doesn't work (an expression generated in a formula)
makeExpression = function(varName){
return(expr(!!ensym(varName) * 2))
}
xVar = makeExpression(x)
ggplot(mpg, aes(x = model, y = !!xVar)) + geom_boxplot()
This works (an expression generated in a formula with a dirty hack)
makeExpression = function(varName){
a = varName
return(expr(!!ensym(varName) * 2))
}
xVar = makeExpression(x)
ggplot(mpg, aes(x = model, y = !!xVar)) + geom_boxplot()
The third example gives the following error: *Error in x * 2 : non-numeric argument to binary operator*
This means that "x", which was supplied to the function is not evaluated. x holds a string of a column name. The expression should have been: displ * 2
Funnily 4th example also works after accessing varName once within the function. Note that a is never used.
I don't understand why this is the case. It looks like a dirty hack to me but it probably has something to do with the scoping. Is there any cleaner way of doing this?
Upvotes: 0
Views: 67
Reputation: 206167
If you want to pass a variable that contains a name as a character value, then you want to use sym
rather than ensym
. sym
will evaluate the parameter to pass to it to get the value. ensym
is meant only to be used in function to capture expressions passed to function. Note that this magic only works when the parameter is still in the "promise" state and hasn't been evaluated by any previous code in the function. This is why the 4th example "works" because that extra code forces the promise to be evaluated.
Upvotes: 1