Passing column name from function to function

I am trying to understand how things are passed from function to function for a project I am working on, but have managed to get myself utterly confused. It is easy enough for data frames, but how can I pass a column name (in either standard or non-standard form) to a function, which then passes it on to another function?

This little example illustrates my problem.

my_function2 <- function(df, y_var) {
  est <- as.formula(paste(substitute(y_var), " ~ disp + hp"))
  lm(est, data = df)
}

my_function1 <- function(df, y_var) {
  # do some stuff on y_var after enquo()
  my_function2(df, y_var)
}

# Works
my_function2(mtcars, "mpg")
#> 
#> Call:
#> lm(formula = est, data = df)
#> 
#> Coefficients:
#> (Intercept)         disp           hp  
#>    30.73590     -0.03035     -0.02484
my_function2(mtcars, mpg)
#> 
#> Call:
#> lm(formula = est, data = df)
#> 
#> Coefficients:
#> (Intercept)         disp           hp  
#>    30.73590     -0.03035     -0.02484

# Does not work
my_function1(mtcars, mpg)
#> Error in eval(predvars, data, env): object 'mpg' not found
my_function1(mtcars, 'mpg')
#> Error in model.frame.default(formula = est, data = df, drop.unused.levels = TRUE): variable lengths differ (found for 'disp')

Created on 2018-10-22 by the reprex package (v0.2.1)

I have tried to use enquo and expr in my_function1, but so far to no avail. Any suggestions would be greatly appreciated.

1 Like

The NSE works for both functions now:

suppressPackageStartupMessages(library(tidyverse))

my_function2 <- function(df, y_var) {
  y_var <- enquo(y_var)
  est <- glue::glue("{rlang::quo_text(y_var)} ~ disp + hp")
  lm(est, data = df)
}

my_function1 <- function(df, y_var) {
  y_var <- enquo(y_var)
  my_function2(df, !!y_var)
}

# Works
my_function2(mtcars, mpg)
#> 
#> Call:
#> lm(formula = est, data = df)
#> 
#> Coefficients:
#> (Intercept)         disp           hp  
#>    30.73590     -0.03035     -0.02484
my_function1(mtcars, mpg)
#> 
#> Call:
#> lm(formula = est, data = df)
#> 
#> Coefficients:
#> (Intercept)         disp           hp  
#>    30.73590     -0.03035     -0.02484

# doesn't work
my_function2(mtcars, "mpg")
#> Error in terms.formula(formula, data = data): invalid term in model formula
my_function1(mtcars, 'mpg')
#> Error in terms.formula(formula, data = data): invalid term in model formula

Created on 2018-10-22 by the reprex package (v0.2.1)

As a tradeoff, both standard functions no longer work :slight_smile:.
Does it help?

1 Like

Perfect! I can live without standard evaluation for this problem!

I ran into a slight problem when I applied this to my original problem in which the second function is predicting the mean based on a Kaplan-Meier survival curve from survreg. In that case, you need as.formula for it to work, which in the linear model case become:

lm(as.formula(est), data = df)

One quick question on coding practices. If I want to turn something into a package later on, is there a preference for NSE or standard evaluation?