Tidy evaluation in R, or “tidyeval” for short, is a pretty robust topic.
But in this episode of Do More With R, I’ll focus on one specific – and useful – task.
Hi, I’m Sharon Machlis with IDG Communications.
And I’m going to demonstrate how to use tidyeval so you can incorporate functions
from packages like dplyr and ggplot2 inside your own custom functions.
If you’ve tried to do this before, you may have run into problems using standard R code.
Tidyeval solves one important one.
Even though the computer-science theory behind it is somewhat advanced – and I definitely
don’t understand all of it; using tidy evaluation for this specific purpose isn’t really that
hard.
Let’s look at an example with the ever-popular mtcars sample data set.
Here’s how I might do a scatterplot of miles per gallon by weight, using dplyr to filter
for higher-mpg cars only.
And I’ve added a few style tweaks to the default ggplot graph:
Now I’d like to create a function with this code, so I can easily re-use my customizations
to plot other data, not just mtcars.
Here’s my first try at a function.
I’m just wrapping that graph code in a new function.
To use my new function, it’s pretty straightforward to add the graph title, the data frame, and
a default minimum value as arguments.
But what about the column names?
If I use wt and mpg unquoted as arguments in my function, like ggplot does, I get an
error.
That’s because in this code, my function is looking for objects called wt and mpg even
though ggplot isn’t.
If I try wt and mpg as quoted arguments I get a graph, but not at all the graph I
want.
My function now thinks these are character strings, not representations of something
else.
If I try using the full columns for mtcars$wt and mtcars$mpg, I get another error.
The problem here is that tidyverse functions use tidy evaluation.
They don’t evaluate the value of a variable right away.
But my regular R function does evaluate the value of an argument right away, because it
uses standard evaluation of variables.
I somehow need my function to do the same thing as the tidyverse functions do, and use
tidy evaluation.
So how do I do that?
I need what I sometimes think of as a meta variable – a special kind of variable that
refers to another variable instead of containing one or more values.
That’s something the rlang package calls a “quosure”.
Hadley Wickham much more accurately describes a quosure as capturing both an R expression
and that expression’s environment.
One thing that’s special about a quosure, as opposed to a regular variable, is that
if you use a quosure in your code, R won’t try to get the value of what’s in there
until you tell it to.
In conventional R programming – and most programming – I can create a variable x
that refers to 3.
Any time I want to use the value 3 in my code, I can use actual 3 or, if I’ve assigned
3 to the variable x, I can use x to represent that value.
R has immediately evaluated the value of x.
Using a variable like x makes code more re-usable.
Quosure behavior is different.
You can create a quosure by using the rlang package’s enquo() function.
Here I just created a quosure called x2 that refers to my “regular” variable x.
Look what happens in my console with that: It’s no longer giving the simple value inside;
it’s showing a structure that looks more like a function.
To access the value of what that quosure contains, you have to tell R when and how to do that.
I sometimes think of the quosure having a timing element, so your code doesn’t try
to get what’s inside it until you say so.
Interactively in the console, you can use the quo_get_expr() operator to see a quosure’s
stored value
But inside a function you’re writing, you want the quosure’s value and its environment.
You access both with what’s called the “bang bang” operator: 2 exclamation marks.
Any time you need the full variable (really, the full expression) that’s stored inside
a quosure, just refer to the quosure object with those 2 exclamation marks in front.
And finally, when you’re writing an R function that needs quosures, make sure to create those
quosures before you need those variables in your code.
Here’s part of my updated function code I’ve created the quosures, but don’t yet
have the code to use them.
Here’s the complete revised function.
See the bang-bangs to use my quosures? If I use
this new function with unquoted variables, it should work.
And, there’s the graph.
This is a very simple case.
I hope that Lionel Henry and Hadley Wickham, authors of the rlang package, aren’t cringing
in horror at this explanation if they’re watching.
But it works for me for this basic use case, and I hope it works for you, too.
There’s a lot more to know about tidy eval, and more operators in the rlang package.
You can read more from RStudio at tidyeval.tidyverse.org.
That’s it for this episode, thanks for watching!
For more R tips, head to the Do More With R page at infoworld: https://go.infoworld.com/morewithR,
all lower case except for the R. Or, look for the Do More With R playlist on YouTube
in the IDG Tech Talk Channel.
Hope to see you next episode!