Search code examples
rargumentsnon-standard-evaluation

Using non-standard evaluation to call an argument in a nested function


I am trying to take an argument from a simple function "adder" and then use a loop to look at the effect of incrementing that argument.

I know there must be better approaches, such as building a single function that makes a longer data frame or maybe a nested loop without the second function... so I welcome those!

But what I'm more specifically interested is how to quote(?) and then parse(?) the argument, here called either "a" or "b" (but the function would declare them "arg_to_change") inside the new function, here called "change_of_adder_arguments".

adder <- function(a=1,b=2){
  data.frame(t=1:100) %>% mutate(x=a*t, y=b*2)
  
}

change_of_adder_arguments <- function(arg_to_change) {
  output <- list()
  arg_to_change_enquo <- enquo(arg_to_change)
  for (i in 1:5) {
    output[[i]] <- ggplot(adder(!!arg_to_change_enquo := i), aes(x, y)) + geom_point()
  
  }
  return(output)
}

change_of_adder_arguments(a)
change_of_adder_arguments(b)

Error: Problem with mutate() input x. x could not find function ":=" i Input x is a * t.

The nail in the coffin seems to be using the arg_to_change_enquo on the LHS of the assignment operator. I know there are many articles here about non-standard evaluation, but I have tried quote, enquo, bquote, parse/eval, sym, substitute, !!, {{}}, =, :=, assign and combinations of all these with no luck. My instinct is that the answer is in specifying which environment? If anybody knows of any good references that "ELI5" about enviroments, I would greatly appreciate it. Thanks!


Solution

  • You can use do.call and pass the arguments to change as a list.

    library(ggplot2)
    
    change_of_adder_arguments <- function(arg_to_change) {
      output <- vector('list', 5)
      arg_to_change_string <- deparse(substitute(arg_to_change))
      for (i in 1:5) {
        output[[i]] <- ggplot(do.call(adder, setNames(as.list(i), 
                       arg_to_change_string)), aes(x, y)) + geom_point()
      }
      return(output)
    }
    
    plot <- change_of_adder_arguments(b)