Search code examples
rdplyrtidyeval

dplyr / tidyevaluation: How to pass an expression in mutate as a string?


I want to write a function that has two inputs: The name of a new variable and a mathematical expression. Both arguments come as strings.

This function should take a data.frame and add the specified new variable which should be the result of the given mathematical expression.

This is a minimal working example of what I tried:

df <- tibble(A = 1:10, B = 1:10)
new_var <- "C"
expression <- "A + B"


example_fun <- function(new_var, expression) {
  new_var_sym <- sym(new_var)
  expression_sym <-  sym(expression)

  mutate(df, !! new_var_sym := !! expression_sym)
}

example_fun(new_var, expression)

This yields the following error:

Error in mutate_impl(.data, dots) : Binding not found: A + B.

When I wrap the mutate line within the function with expr(), I get

mutate(df, `:=`(C, `A + B`))

It seems as if the ticks around A + B should not be there, but I could not figure out how to get rid of them. At least, enquo() and quo_name() did not help.


Solution

  • We can have a quosure/quote as expression and then do the evaluation (!!). Also, the lhs of := can take string, so we don't need to convert the 'new_var' to symbol

    library(tidyverse)
    library(rlang)
    
    expression <- quo(A + B)
    example_fun <- function(new_var, expression) {
    
    
      df %>% 
          mutate(!! new_var := !! expression)
    }
    
    example_fun(new_var, expression)
    # A tibble: 10 x 3
    #       A     B     C
    #   <int> <int> <int>
    # 1     1     1     2
    # 2     2     2     4
    # 3     3     3     6
    # 4     4     4     8
    # 5     5     5    10
    # 6     6     6    12
    # 7     7     7    14
    # 8     8     8    16
    # 9     9     9    18
    #10    10    10    20
    

    If we really wanted to pass as character strings, then use parse_expr

    expression <- "A + B"
    example_fun <- function(new_var, expression) {
    
    
      df %>%
         mutate(!! new_var := !! parse_expr(expression))
    }
    
    example_fun(new_var, expression)
    # A tibble: 10 x 3
    #       A     B     C
    #   <int> <int> <int>
    # 1     1     1     2
    # 2     2     2     4
    # 3     3     3     6
    # 4     4     4     8
    # 5     5     5    10
    # 6     6     6    12
    # 7     7     7    14
    # 8     8     8    16
    # 9     9     9    18
    #10    10    10    20