Search code examples
rdplyrrlangtidyeval

Are there limits to tidy evaluation scope?


I'm trying to use tidy evaluation, as defined in dplyr 0.7.0.

However, during a function call within mutate() I am getting an error. It seems that the variables are not being evaluated as I expect.

library(dplyr)
library(tibble)
library(tidyr)

myCor <- function(col1, col2) {
  col1 <- enquo(col1)
  col2 <- enquo(col2)

  mtcars %>%
    rownames_to_column("vehicle") %>%
    select(vehicle, !!col1, !!col2) %>%
    mutate(correlation=cor(!!col1, !!col2))
}

myCor("mpg", "disp")
# Error in mutate_impl(.data, dots) : 
#   Evaluation error: 'x' must be numeric.

Instead, I have to use this non-tidy eval syntax to get the desired output.

myCor <- function(col1, col2) {
  col1_tidy <- enquo(col1)
  col2_tidy <- enquo(col2)

  mtcars %>%
    rownames_to_column("vehicle") %>%
    select(vehicle, !!col1_tidy, !!col2_tidy) %>%
    mutate(correlation=cor(eval(parse(text=col1)), eval(parse(text=col2))))
}

myCor("mpg", "disp")
# vehicle  mpg  disp correlation
# 1            Mazda RX4 21.0 160.0  -0.8475514
# 2        Mazda RX4 Wag 21.0 160.0  -0.8475514
# 3           Datsun 710 22.8 108.0  -0.8475514
# 4       Hornet 4 Drive 21.4 258.0  -0.8475514
# ...

Is there a way to use tidy evaluation throughout this example?


Solution

  • Use ensym instead of enquo if you want to pass strings as your arguments...

    library(dplyr)
    library(rlang)
    library(tibble)
    
    myCor <- function(col1, col2) {
      col1 <- ensym(col1)
      col2 <- ensym(col2)
    
      mtcars %>%
        rownames_to_column("vehicle") %>%
        select(vehicle, !!col1, !!col2) %>%
        mutate(correlation=cor(!!col1, !!col2))
    }
    
    # both of these will work now
    myCor("mpg", "disp")
    myCor(mpg, disp)