Search code examples
rdplyrrlangnse

understanding rlang: mutate with variable col name and variable column


I'd like to define a function that takes a data.frame and a column name and returns the data.frame in with that column transformed (e.g. to lowercase). When the column name is known in advance, this is simple:

diamonds %>% mutate(cut = tolower(cut))

How do I define a function foo, such that:

col <- "cut"
foo(diamonds, col) 

does this same behavior? (Not looking for a base R or data.table answer since I want to preserve dplyr's ability to translate this into a lazily-evaluated SQL call).

If I just wanted my function to work using: foo(diamonds, cut), I just need enquo and !!

foo <- function(df, col){
    x <- enquo(col)
    mutate(df, !!x := tolower(!!x))
}

If I want to take the column name in quotes, foo(diamonds, "cut"), adding ensym is sufficient:

foo <- function(df, col){
    col <- ensym(col)
    x <- enquo(col)
    mutate(df, !!x := tolower(!!x))
}

but this fails when given a variable for an argument:

col <- "cut"
foo(diamonds, col) 

Error in ~col : object 'col' not found

What am I missing that can evaluate the variable?


Solution

  • You can also avoid tidy eval entirely here by using mutate_at().

    library(tidyverse)
    
    (x <- tibble(
      num = 1:3,
      month = month.abb[num]
    ))
    #> # A tibble: 3 x 2
    #>     num month
    #>   <int> <chr>
    #> 1     1 Jan  
    #> 2     2 Feb  
    #> 3     3 Mar
    
    x %>%
      mutate(month = tolower(month))
    #> # A tibble: 3 x 2
    #>     num month
    #>   <int> <chr>
    #> 1     1 jan  
    #> 2     2 feb  
    #> 3     3 mar
    
    foo <- function(df, col) {
      mutate_at(df, .vars = col, .funs = tolower)
    }
    
    foo(x, "month")
    #> # A tibble: 3 x 2
    #>     num month
    #>   <int> <chr>
    #> 1     1 jan  
    #> 2     2 feb  
    #> 3     3 mar
    
    this <- "month"
    foo(x, this)
    #> # A tibble: 3 x 2
    #>     num month
    #>   <int> <chr>
    #> 1     1 jan  
    #> 2     2 feb  
    #> 3     3 mar
    

    Created on 2019-03-09 by the reprex package (v0.2.1.9000)