1

Suppose I have a function f(...) which internally calls different functions which both happen to take arguments with the name color. In some cases I want to send my ... argument to one, and sometimes the other. Is there some way to specify which one I mean when calling f()?

Here's a simple example.

library(ggplot2)

f <- function(...) {
  ggplot(mtcars, aes(disp, mpg)) +
    geom_point(aes(...), ...)
}

# in this case I want it OUTSIDE aes()
f(color = "blue") # should be geom_point(color = blue)


# here I want it INSIDE aes()
f(color = cyl) # should be geom_point(aes(color = cyl))
#> Error in list2(na.rm = na.rm, ...): object 'cyl' not found

Created on 2022-11-04 with reprex v2.0.2

Dan Adams
  • 4,971
  • 9
  • 28
  • 5
    It doesn't truly work in your first example It only works because `aes(col = 'abc')` itself doesn't return an error, but rather creates a single level factor, which then gets overwritten by `color = 'abc'` in the outer level by default behaviour in `geom_point`. How would you distinguish between the 2 yourself? There's no naming difference between the 2, so you'd have to capture the input, test whether `color` or `colour` is included, and whether it is a name contained in `.data` or not, and pass it to the correct layer respectively. – Oliver Nov 04 '22 at 12:44
  • 2
    Possible duplicate: https://stackoverflow.com/questions/4124900/is-there-a-way-to-use-two-statements-in-a-function-in-r. The `...` all goes in one bucket. If you have a list of different arguments name they you can manually split them up in a messy way, but if they both have the same parameter names, then `...` probably isn't the best way to pass parameters. – MrFlick Nov 04 '22 at 14:00
  • Thanks @Oliver for explaining what was happening here. As both comments make clear, it sounds like this is fundamentally the wrong way to approach this. I will tweak my question and add an answer just to provide closure. – Dan Adams Nov 05 '22 at 00:05

1 Answers1

1

First of all, it is necessarily ambiguous to provide two different function arguments with the same name in the same function. Therefore using ... is probably not the best way to do this. Possible solutions can be found in this thread.

In the example, the argument color is getting passed from ... to BOTH aes() and geom_point() because they both take a color argument. The reason the first example works is because supplying color = "blue" in both places doesn't throw an error.

library(ggplot2)

ggplot(mtcars, aes(disp, mpg)) +
  geom_point(aes(color = "blue"), color = "blue")

Created on 2022-11-04 with reprex v2.0.2

Finally, with a small tweak to the original function, it would be possible to make it flexible to provide color to either part of the function, but the approach probably wouldn't extend past this narrow use case much so probably not much help.

library(ggplot2)

f <- function(...) {
  ggplot(mtcars, aes(disp, mpg)) +
    geom_point(...)
}

f(color = "blue")

f(aes(color = factor(cyl)))

Created on 2022-11-04 with reprex v2.0.2

Dan Adams
  • 4,971
  • 9
  • 28