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?

1
  • 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 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. Commented Jun 21, 2018 at 4:29

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

1 Comment

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...
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.