rggplot2tidyeval

R ggplot2: Replacing aes_string() with aes() and .data[[varname]] when varname may be NULL


I am working on updating some older R code to make it use ggplot2's aes() now that aes_string() is deprecated. I admit I don't understand all of the details of tidy evaluation, but from what I do understand it seems like the replacement for aes_string(shape=shapevar) would be aes(shape=.data[[shapevar]]), or possibly aes(shape=!!sym(shapevar)).

The problem with these replacements is that they do not work when shapevar is NULL, as shown in the example below:

library('ggplot2')

set.seed(1)
dat <- data.frame(x=rnorm(25),y=rnorm(25),othervar=factor(sample(1:3,25,replace=T)))

make_scatter_string <- function(plotdat,outfile,xvar='x',yvar='y',colorvar=NULL,shapevar=NULL) {
  plt <- ggplot(plotdat,aes_string(x=xvar,y=yvar,color=colorvar,shape=shapevar)) + geom_point()
  ggsave(outfile,plt)
}

make_scatter_data <- function(plotdat,outfile,xvar='x',yvar='y',colorvar=NULL,shapevar=NULL) {
  plt <- ggplot(plotdat,aes(x=.data[[xvar]],y=.data[[yvar]],color=.data[[colorvar]],shape=.data[[shapevar]])) + geom_point()
  ggsave(outfile,plt)
}

make_scatter_sym <- function(plotdat,outfile,xvar='x',yvar='y',colorvar=NULL,shapevar=NULL) {
  plt <- ggplot(plotdat,aes(x=!!sym(xvar),y=!!sym(yvar),color=!!sym(colorvar),shape=!!sym(shapevar))) + geom_point()
  ggsave(outfile,plt)
}

make_scatter_string(dat,'test1.png',colorvar='othervar') # Works, aes_string can handle shapevar being NULL
make_scatter_data(dat,'test2.png',colorvar='othervar') # Gives error message "Error in `.data[[NULL]]`: ! Must subset the data pronoun with a string, not NULL."
make_scatter_sym(dat,'test3.png',colorvar='othervar') # Gives error message "Error in `sym()`: ! Can't convert NULL to a symbol."

What is the correct way to give aes() a variable like shapevar that may contain the name of a variable in the data or may be NULL? Or is there some other value that should be used to say "don't use this aesthetic" instead of NULL?


Solution

  • Adapting my answer on How to replace the deprecated ggplot2 function aes_string: accepting an arbitrary number of named strings to specify aesthetic mappings?, a flexible and generalized approach of the one by @r2evans may look like so.

    Basically I renamed the functions arguments to the names of the aesthetics and used ... to allow to pass additional aesthetics and which also works with NULL:

    library(ggplot2)
    
    make_scatter_sym <- function(plotdat, outfile, x = "x", y = "y", ...) {
      args <- lapply(list(x = x, y = y, ...), function(x) if (!is.null(x)) sym(x))
    
      plt <- ggplot(plotdat, aes(!!!args)) +
        geom_point()
    
      ggsave(outfile, plt)
    
      plt
    }
    
    make_scatter_sym(dat, "test1.png", color = "othervar")
    #> Saving 7 x 5 in image
    

    
    make_scatter_sym(dat, "test1.png", color = NULL, shape = NULL)
    #> Saving 7 x 5 in image