0

I'm trying to create a wrapper around the ggplot that allows me to add some aesthetics like the x variable or color but always prefills y, ymin and ymax without having to work with quoted variable names.

Since ggplot2 cannot use tidy evaluation I have to use NSE for this but I'm stuck, the information I could find here and here and inspecting some functions made me try things like unlist(...) and working with match.call(). but they only throw different errors.

In the below function I'd basically like to be able to call ci_plot() or for example ci_plot(color = cyl)

library(dplyr)
library(ggplot2)
library(purrr)
library(tidyr)


ci_plot <- function(data, ...) {
  ggplot(data, aes(..., y = y, ymin = ymin, ymax = ymax))  
}

mpg %>%
  group_by(manufacturer) %>%
  nest() %>%
  mutate(x = map(data, ~mean_se(.x$hwy))) %>%
  unnest(x) %>%
  ci_plot() + 
  geom_pointrange()
Robin Gertenbach
  • 10,316
  • 3
  • 25
  • 37
  • this might help: https://stackoverflow.com/questions/15458526/r-pass-variable-column-indices-to-ggplot2 – Wave Jul 31 '17 at 19:08

2 Answers2

3

You have a couple options, depending on how you want the user to be able to pass the variables to the function.

Using strings and aes_string

You could have the user give variables via strings. In this case, you want that ... in aes_string and then add a separate aes layer for the "fixed" variables.

Your data manipulation code was returning all NA for me, so this example is simpler. I fixed the y variable to be cty.

ci_plot = function(data, ...) {
     ggplot(data, aes_string(...) )  +
          aes( y = cty )
}

ci_plot(data = mpg, x = "displ", color = "class") +
     geom_point()

Using tildes and aes_

An alternative is to have the user use tildes for variables when using the function. In that case, aes_ can be used for both fixed and changeable variables.

ci_plot2 = function(data, ...) {
     ggplot(data, aes_(..., y = ~cty ) ) 
}

ci_plot2(data = mpg, x = ~displ, color = ~class) +
     geom_point()

The resulting plot from both functions: enter image description here

aosmith
  • 34,856
  • 9
  • 84
  • 118
  • Thanks for the thorough reply. However I was looking for ways to keep the syntax the same as for other vanilla ggplot2 functions, without quotes (I probably didn't stress it enough). I managed to sole the issue now and posted an answer if you are interested. – Robin Gertenbach Aug 01 '17 at 10:01
0

After some more digging I found shadow's answer here and figured out how to adapt it for my purpose. I'll try to outline the solution as much as I understand it.

ci_plot <- function(data, ...) {
  # Create a list of unevaluated parameters,
  # removing the first two, which are the function itself and data.
  arglist <- as.list(match.call()[-c(1,2)]) 

  # We can add additional parameters to the list using substitute
  arglist$ymin = substitute(ymin)
  arglist$y    = substitute(y)
  arglist$ymax = substitute(ymax)

  # I suppose this allows ggplot2 to recognize that it needs to quote the arguments
  myaes <- structure(arglist, class="uneval")

  # And this quotes the arguments?
  myaes <- ggplot2:::rename_aes(myaes)

  ggplot(data, myaes)  
}

That function allows me to write the code like this

mpg %>%
  group_by(manufacturer, cyl) %>%
  nest() %>%
  mutate(x = map(data, ~mean_se(.x$hwy))) %>%
  unnest(x) %>%
  ci_plot(x = cyl, color = manufacturer) + 
  geom_pointrange()
Robin Gertenbach
  • 10,316
  • 3
  • 25
  • 37