9

I want to create a plotting function where I specify the data set, and specify the plotting arguments as function arguments in similar fashion as I can within ggplot2, i.e. where we specify the variable name without the dataset, e.g. hp instead of mtcars$hp.

For example:

ggfun <- function(dat, x.var, y.var){

  ggp <- ggplot(data = dat,
                aes(x = x.var,
                    y = y.var)) +
    geom_point()

  return(ggp)
}


ggfun(dat = mtcars, x.var = drat, y.var = hp)

Would return: wonderful plot

However it returns:

> ggfun(dat = mtcars, x.var = drat, y.var = hp)
Error in eval(expr, envir, enclos) : object 'drat' not found
In addition: Warning message:
In eval(expr, envir, enclos) : restarting interrupted promise evaluation

I know using aes_string instead of aes works, e.g.:

ggfun <- function(dat, x.var, y.var){

  ggp <- ggplot(data = dat,
                aes_string(x = x.var,
                    y = y.var)) +
    geom_point()

  return(ggp)
}

ggfun(dat = mtcars, x.var = "drat", y.var = "hp")

But I'd prefer to avoid using string form.

Other attempts include ggfun(dat = mtcars, x.var = mtcars$drat, y.var = mtcars$hp), which returns the right graph but partially defeats the purpose of the exercise, and produces lables "x.var" and "y.var" instead of "drat" and "hp".

Any known and reasonably simple way around this?

Scransom
  • 3,175
  • 3
  • 31
  • 51
  • 2
    I would also suggest @akrun's solution below. I would like to add that a great resource on understand how to work with unquoted variables is https://dplyr.tidyverse.org/articles/programming.html `ggplot2` was originally developed before this the `rlang` package became an integral part of tidyverse, and so it's being rewritten (has been?) to support quosures - hence you will need to download ggplot2 from github to make it work. – Melissa Key Jun 21 '18 at 04:29

2 Answers2

24

With the devel version of ggplot2, we can pass unquoted arguments, convert it to quosure (with enquo) and evaluate it (!!)

ggfun <- function(dat, x.var, y.var){
  x.var <- enquo(x.var)
  y.var <- enquo(y.var)
  ggp <- ggplot(data = dat,
                aes(x = !! x.var,
                    y = !! y.var)) +
    geom_point()

  return(ggp)
}

ggfun(dat = mtcars, x.var = drat, y.var = hp)

For quoted strings, convert it to symbol with sym (from rlang) and do the evaluation

ggfun <- function(dat, x.var, y.var){
  x.var <- rlang::sym(x.var)
  y.var <- rlang::sym(y.var)
  ggp <- ggplot(data = dat,
                aes(x = !! x.var,
                    y = !! y.var)) +
    geom_point()

  return(ggp)
}

ggfun(dat = mtcars, x.var = "drat", y.var = "hp")

enter image description here


If we want to pass either quoted or unquoted, the quosure is changed to character (quo_name), then to symbol (sym) and evaluate (!!)

ggfun <- function(dat, x.var, y.var){
  x.var <- rlang::sym(quo_name(enquo(x.var)))
  y.var <- rlang::sym(quo_name(enquo(y.var)))
  ggp <- ggplot(data = dat,
                aes(x = !! x.var,
                    y = !! y.var)) +
    geom_point()

  return(ggp)
}

p1 <- ggfun(dat = mtcars, x.var = drat, y.var = hp)
p2 <- ggfun(dat = mtcars, x.var = "drat", y.var = "hp")

all.equal(p1, p2)
#[1] TRUE
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Are the calls to `rlang` required for any ggplot() functions we might build? I'm writing a function to contain a lot of `annotate` arguments... – Ben Aug 26 '21 at 14:56
3

As of rlang 0.4.0 (2019-06-25) there is now the embrace operator {{}}. With the embrace operator:

library(ggplot2)
data("mtcars")

The operator works with both column names and labels in function arguments.

scatter_plot <- function(data, x, y, title) {
  ggplot(data, aes({{x}}, {{y}})) +
    geom_point()+
    labs(title= {{title}})
}
scatter_plot(mtcars, drat, hp, "Drat by HP")

Plots can be further customized with + just as normal.

scatter_plot(mtcars, drat, hp, "Drat by HP with trend") +
  geom_smooth()

Other resources

  • This post is where I encountered the method.
  • This SO answer provides some additional very similar examples of using tidy evaluation with dplyr and tables.
ncraig
  • 783
  • 1
  • 10
  • 23