Search code examples
rggplot2nullaesthetics

How to write a function that passes NULL to ggplot without getting aesthetics error


I am trying to write a function that creates plots and ran into an error that I don't understand. Here is a simplified example.

Reproducible example:

library (ggplot2)
# Sample data
xdata = 0:20
ydata = 20:40
dat <- data.frame(xdata, ydata)

# This works
line_p <- ggplot(dat, aes(x = xdata, y = ydata, group = NULL, color = NULL)) + geom_line()
line_p

I expected the following to work, but get an aesthetics error, but in this case the x and y variables are the same length. The issues seems to be having a default value of NULL for group and color. I tried explicitly passing NULL as well with aes_group and aes_color as function variables but this also did not work.

# Using a function doesn't work:

# create function
line_function <- function(mydata     = dat,
                          xinput     = x,
                          yinput     = y,
                          aes_group  = NULL,
                          aes_color  = NULL,
                          ...) {

  lineplot <- ggplot(dat, aes(x = xinput, y = yinput, group = aes_group, color = aes_color)) + geom_line()
}


# test the function
line_test_p <- line_function(
  mydata = dat,
  xinput = xdata,
  yinput = ydata
)

line_test_p

Testing with explicit inputs

# test the function again with explicit NULL inputs

line_test2_p <- line_function(
  mydata    = dat,
  xinput    = xdata,
  yinput    = ydata,
  aes_group = NULL,
  aes_color = NULL
)

line_test2_p

Is it not possible to write a generic function where ggplot will interpret the NULL values as in the example that works without a function, or am I missing something else?

Thanks!


Solution

  • In short, you should check out aes_string for creating aesthetic mappings programmatically. It allows you to create aesthetic mappings using the names of variables stored strings. That way, it's easy to pass column names as arguments to a function and create the corresponding plot.

    The following version of your function works for me:

    # create function
    line_function <- function(mydata     = dat,
                              xinput     = "x", # note the defaults are
                              yinput     = "y", # strings here
                              aes_group  = NULL,
                              aes_color  = NULL,
                              ...) {
    
      ggplot(mydata, # this should be the argument, not the global variable dat
             # now we create the aes binding with aes_string
             aes_string(x = xinput,
                        y = yinput,
                        group = aes_group,
                        color = aes_color)) +
        geom_line()
    }
    

    And now you can use the function to create your examples:

    # test the function
    line_test_p <- line_function(
      mydata = dat,
      xinput = "xdata", # note the strings
      yinput = "ydata"
    )
    
    # test the function again with explicit NULL inputs
    line_test2_p <- line_function(mydata    = dat,
                                  xinput    = "xdata", # and strings here
                                  yinput    = "ydata",
                                  aes_group = NULL,
                                  aes_color = NULL)
    

    And things should work out for you. Again, do check out the documentation, because there are different ways you can accomplish this, and you may prefer different ways for different purposes or preferences.