Substituting variable for string argument in function call

Viewed 241

I am trying to call a function that expects a string as one of the arguments. However, attempting to substitute a variable containing the string throws an error.

library(jtools)

# Fit linear model
fitiris <- lm(Petal.Length ~ Petal.Width * Species, data = iris)

# Plot interaction effect: works!
interact_plot(fitiris, pred = "Petal.Width", modx = "Species")

# Substitute variable name for string: doesn't work!
predictor <- "Petal.Width"
interact_plot(fitiris, pred = predictor, modx = "Species")

Error in names(modxvals2) <- modx.labels : 
  attempt to set an attribute on NULL
2 Answers

{jtools} uses non-standard evaluation so you can specify unquoted column names, e.g.

library(jtools)

fitiris <- lm(Petal.Length ~ Petal.Width * Species, data = iris)

interact_plot(fitiris, pred = Petal.Width, modx = Species)

...but it's not robustly implemented, so the (common!) case you've run into breaks it. If you really need it to work, you can use bquote to restructure the call (with .(...) around what you want substituted), and then run it with eval:

predictor <- "Petal.Width"
eval(bquote(interact_plot(fitiris, pred = .(predictor), modx = "Species")))

...but this is diving pretty deep into R. A better approach is to make the plot yourself using an ordinary plotting library like {ggplot2}.

I'm the developer of this package.

A short note: this function has just been moved to a new package, called interactions, which is in the process of being added to CRAN. If you want to install it before it gets to CRAN (I expect this to happen within the week), you'll need to use this code to download it from Github:

if (!requireNamespace("remotes") {
  install.packages("remotes")
}
remotes::install_github("jacob-long/interactions")

In this new version, I've changed the non-standard evaluation to follow the tidyeval model. This means it should be more straightforward to write a function that plugs in arguments to pred, modx, and/or mod2.

For example:

library(interactions)

plot_wrapper <- function(my_model, my_pred, my_modx) {
  interact_plot(my_model, pred = !! my_pred, modx = !! my_modx)
}

fiti <- lm(Income ~ Frost + Murder * Illiteracy, data = as.data.frame(state.x77))
plot_wrapper(fiti, my_pred = "Murder", my_modx = "Illiteracy") # Works
pred_var <- "Murder"
modx_var <- "Illiteracy"
plot_wrapper(fiti, my_pred = pred_var, my_modx = modx_var) # Works

Or just to give an example of using variables in a loop...

variables <- c("Murder", "Illiteracy")
for (var in variables) {
  print(interact_plot(fiti, pred = !! var, modx = !! (variables[variables != var])))
}
Related