nice selection

I started writing in R before the tidyverse became a thing and I never really had to think about non-standard evaluation when writing functions. Those days are long past and I’ve recently struggled with the challenge when writing functions for the R4EPIs project, which would stick out like ugly little trolls along side tidyverse functions.

One of my biggest struggles was trying to figure out how, excactly to select a varaible from a user as either a character string or a bare variable. I had only known about rlang::enquo() and rlang::sym(), but I thought I had to use one or the other.

I had liked tidyselect::vars_select() because it gave me characters that I could use on my data frame columns, and it worked really will with the dots:

f <- function(.df, ...) {
  tidyselect::vars_select(colnames(.df), ...)
}
f(iris, tidyselect::starts_with("Sepal"))
##   Sepal.Length    Sepal.Width 
## "Sepal.Length"  "Sepal.Width"
f(iris, Sepal.Width)
##   Sepal.Width 
## "Sepal.Width"
f(iris, "Sepal.Width")
##   Sepal.Width 
## "Sepal.Width"

But when I would try it with specific arguments, it would scold me if the data weren’t in character form:

f <- function(.df, var) {
  tidyselect::vars_select(colnames(.df), var)
}
f(iris, Sepal.Width)
## Error in .f(.x[[i]], ...): object 'Sepal.Width' not found
f(iris, "Sepal.Width")
##   Sepal.Width 
## "Sepal.Width"

I recently found that I could use !! enquo(var) to allow the user to input either a character or a bare variable:

library("rlang")
f <- function(.df, var) {
  tidyselect::vars_select(colnames(.df), !! enquo(var))
}
f(iris, Sepal.Width)
##   Sepal.Width 
## "Sepal.Width"
f(iris, "Sepal.Width")
##   Sepal.Width 
## "Sepal.Width"

And now it finally makes sense!

Avatar
Zhian N. Kamvar
Research Software Engineer

I am a population geneticist, data scientist, plant pathologist, and R package developer. I currently work as the Lesson Infrastructure Technology Developer at The Carpentries.

Related

Next
Previous