24

In ggplot2 you can pass character arguments inside a user defined function using aes_string. How can you do the same for facet grid which takes a formula, not aes?

FUN <- function(data, x, y, fac1, fac2) {
     ggplot(data = data, aes_string(x=x, y=y)) +
     geom_point() + facet_grid(as.formula(substitute(fac1 ~ fac2)))
}


FUN(mtcars, 'hp', 'mpg', 'cyl', 'am')
1
  • 5
    as.formula(paste(fac1,"~", fac2)) Commented Feb 5, 2014 at 20:52

2 Answers 2

40

reformulate() seems to work just fine.

FUN <- function(data, x, y, fac1, fac2) {
      ggplot(data = data, aes_string(x=x, y=y)) +
      geom_point() + facet_grid(reformulate(fac2,fac1))
}

FUN(mtcars, 'hp', 'mpg', 'cyl', 'am')

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

Perfect. Didn't know about reformulate.
If you want to facet only horizontally or vertically, something like reformulate(fac1, ".") also works.
7

With rlang magic and new ggplot2 v3.0.0 features you can do :

FUN <- function(data, x, y, fac1, fac2) {
  ggplot(data = data, aes(x = !!ensym(x), y = !!ensym(y))) +
    geom_point() + 
    facet_grid(eval(expr(!!ensym(fac1) ~ !!ensym(fac2))))
}

FUN(mtcars, 'hp', 'mpg', 'cyl', 'am')

Note that we don't use aes_string, which is soft deprecated.

Personally in these cases I like to use a function I called glue_formula (referencing package glue) :

glue_formula <- function(.formula, .envir = parent.frame(), ...){
  formula_chr <- gsub("\\n\\s*","",as.character(.formula)[c(2,1,3)])
  args <- c(as.list(formula_chr), .sep=" ", .envir = .envir)
  as.formula(do.call(glue::glue, args),env = .envir)
}

FUN2 <- function(data, x, y, fac1, fac2) {
  ggplot(data = data, aes(x = !!ensym(x), y = !!ensym(y))) +
    geom_point() + facet_grid(glue_formula({fac1} ~ {fac2}))
}

FUN2(mtcars, 'hp', 'mpg', 'cyl', 'am')

It's not tidyverse approved (see interesting discussion here) but it has served me well.

2 Comments

Thanks for the update...no knock on your solutions (especially the glue ones) but reformulate(fac2,fac1) seems so much cleaner and easier to reason about than eval(expr(!!ensym(fac1) ~ !!ensym(fac2)))
I agree, it is more flexible though, in case you have a more complex formula (which might not be relevant for facet_grid) , and it comes from lionel. The github issue is not closed so they might come up with something more satisfying.

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.