Home > Software engineering >  How to pass variables from lm object to aes(x =, y = )?
How to pass variables from lm object to aes(x =, y = )?

Time:03-24

Context: I have a function that takes an object created with stats::lm() as its main argument. The goal of this function is to make ggplots with only this lm object. Warning: variables used in the model are NOT arguments of the function i.e. if the model is lmobj <- lm(y ~ x, data = df) then the function only takes lmobj as an argument. Indeed it is different from question like this one. Moreover, I am not looking for "ggplot only" solutions that take the raw data and compute regression line and scatterplot (e.g. ggplot2::geom_smooth(method = "lm")).

Problem: ggplot() geom functions have a x and y argument that require unquoted variables (see reference manual); how can I recover these from lmobj?

Expected output:

library(ggplot2)
lmobj <- lm(Petal.Width ~ Petal.Length, data = iris)
myfun <- function(.lm) {
  # make a scatterplot with .lm using ggplot
  ggplot(data = .lm[["model"]], aes(x = Petal.Width, y = Petal.Length))  
    geom_point()
}
myfun(lmobj)

Trials and errors

I tried to grab an unquoted variable name from lmobject using cat():

> cat(names(lmobj[["model"]][2]))
Petal.Length

But it creates an error:

> myfuntest <- function(.lm) {
    # make a scatterplot with .lm using ggplot
    ggplot(data = .lm[["model"]], aes(x = cat(names(.lm[["model"]][2])), 
                                      y = cat(names(.lm[["model"]][1]))))  
      geom_point()
  }
> myfuntest(lmobj)
Petal.LengthPetal.WidthPetal.LengthPetal.WidthError: geom_point requires the following missing aesthetics: x and y

CodePudding user response:

The following works:

myfun <- function(model) {
  coefs <- names(model$model)
  ggplot(data = model$model)  
    aes(x = !! rlang::sym(coefs[1L]), y = !! rlang::sym(coefs[2L])))  
    geom_point()
}

The relevant point here is that aes uses ‘rlang’s tidy evaluation and as such requires the arguments to be injected via !! as names.

CodePudding user response:

One way to do it is to evaluate first the arguments of aes as symbols and then call aes by wrapping it into a do.call

myfun <- function(.lm) {
  ggplot(data = .lm[["model"]],
         do.call(aes, list(x = sym(names(.lm[["model"]])[2]),
                           y = sym(names(.lm[["model"]])[1]))))  
    geom_point()
}

  • Related