Search code examples
rggplot2facet-wraptidyeval

Tidy evaluation in making multiple panel plots using ggplot2


I have a function to make multi-panel plots using ggplot2:

plot_facet <- function(df, var.x, var.y, var.facet) {
  p <- df %>% 
    ggplot(aes(x = {{var.x}}, y = {{var.y}})) +
    geom_point()    
  
   if(!is_missing(var.facet)) p <- p + facet_grid({{var.facet}} ~ .)
  
  return(p)
}

The following call works as expected:

plot_facet(mtcars, mpg, hp) + facet_grid(cyl ~ .)

But this doesn't:

plot_facet(mtcars, mpg, hp, cyl)

and I got the error message:

Error in is_reference(x, quote(expr = )) : object 'cyl' not found

I have tried this and it doesn't work either:

facet_grid(rows = vars({{var.facet}}))

How can I fix it? Thanks for your help.


Solution

  • The problem seems to be that is_missing evaluates too much (to be honest, I don't make too much sense out of its help page). If you just use missing (which only operates on the symbol), you can use your facet_grid(rows = vars({{var.facet}})) approach:

    library(ggplot2)
    library(magrittr)
    library(rlang)
    
    plot_facet <- function(df, var.x, var.y, var.facet) {
      p <- df %>% 
        ggplot(aes(x = {{var.x}}, y = {{var.y}})) +
        geom_point()    
      
      if(!missing(var.facet)) p <- p + facet_grid(rows = vars({{var.facet}}))
      
      return(p)
    }
    
    plot_facet(mtcars, mpg, hp, cyl)
    

    Alternatively, you can convert var.facet to a symbol at the beginning of your function and use this together with is_missing and the rows argument:

    plot_facet <- function(df, var.x, var.y, var.facet) {
      var.facet <- ensym(var.facet)
      p <- df %>% 
        ggplot(aes(x = {{var.x}}, y = {{var.y}})) +
        geom_point()    
      
      if(!is_missing(var.facet)) p <- p + facet_grid(rows = vars({{var.facet}}))
      
      return(p)
    }
    
    plot_facet(mtcars, mpg, hp, cyl)