Search code examples
rggplot2tidyversenon-standard-evaluation

Trouble with an R function for making a ggplot2 graph and optionally facetting with user-specified columns


I'd like to write a function in R for making some graphs and, optionally, facetting those graphs by whatever column the user inputs. I'd prefer to do this using nonstandard evaluation since I don't know what columns the user will have in the data.frame that they input. The code below works, and the user can specify what column they want to color points by:

 library(tidyverse)
 library(rlang)
 data("diamonds")
 
 myplot <- function(DF, colorBy){      
  colorBy <- rlang::enquo(colorBy)      
  ggplot(DF, aes(x = price, y = carat, color = !!colorBy)) +
        geom_point()      
  }
  
  myplot(diamonds, colorBy = cut)

diamonds graph

but this code, where I was trying to allow the user to specify a column to facet by, fails:

myplot_facet <- function(DF, colorBy, facetBy){
  
  colorBy <- rlang::enquo(colorBy)
  facetBy <- rlang::enquo(facetBy)
  ggplot(DF, aes(x = price, y = carat, color = !!colorBy)) +
        geom_point() +
        facet_wrap(. ~ !!facetBy)
 }
 
 myplot_facet(diamonds, colorBy = cut, facetBy = color)

The error I get is

Error: Quosures can only be unquoted within a quasiquotation context.

# Bad: list(!!myquosure)

# Good: dplyr::mutate(data, !!myquosure)

I'm not sure how to use that error message to solve my issue. Does facet_wrap have different input requirements from aes? I thought they were both calling on columns in a data.frame using tidy syntax, so I thought they would work similarly.

As a further complication, I'd like it if the user could set facetBy to NA if they don't want facets.

I've been trying to read up on similar problems (here, here, and here) and I'm trying to decipher the NSE chapter from "Advanced R", but I am struggling. None of the other questions are quite what I'm asking, and the NSE chapter from "Advanced R" is beyond me.


Solution

  • This works:

    myplot_facet <- function(DF, colorBy, facetBy){
      
      facetBy <- enquo(facetBy)
      
      ggplot(DF, aes(x = price, y = carat, color = {{colorBy}} )) +
        geom_point() +
        facet_wrap(vars(!!facetBy))
    }
    
    myplot_facet(diamonds, colorBy = cut, facetBy = color)