Search code examples
rggplot2colorsaesthetics

Why do 'if' statements including arguments don't work in ggplot geoms?


Why do the following won't work?

ggplot(mtcars,aes(x=wt,y=mpg)) +
  geom_smooth({if (T) ("colour='red'")})

ggplot(mtcars,aes(x=wt,y=mpg)) +
  geom_smooth(ifelse(T,("colour='red'")))

ggplot(mtcars,aes(x=wt,y=mpg)) +
  geom_smooth(switch(T,("colour='red'")))

They all output this:

Error: `mapping` must be created by `aes()`

What would be a workaround?

Edit:

The proposed answers suggested to put the if statement after the named colour argument. The problem is that even if I leave color=NA or NULL or blank, it enters in conflict if aes(colour) is already defined, so it is not equivalent to not having the argument at all. And that is really the problem/workaround I'm trying to get at. For example:

ggplot(mtcars,aes(x=wt,y=mpg,colour=factor(cyl))) + geom_smooth(colour = NA) does not produce three colored lines (as it should if aes() would take over, indicating it's being overwritten)

Setting geom_smooth(color = NULL) gives: Error: Aesthetics must be either length 1 or the same as the data (80): colour

Setting geom_smooth(color = ) gives: Error in geom_smooth(color = ) : argument is missing, with no default

Note: Gregory also suggested duplicating the geom statement, which is a working workaround, but my question was ultimately about 'is there a way to avoid doing precisely this' (duplicating calls to geoms_) and trying to understand why we're not allowed to use if statements including arguments.

Edit 2:

My initial intention with this question was more theoretical as to why ggplot2 is coded in such a way that it does not allow conditional statements to include complete optional arguments in geoms (e.g., would that enter in conflict or create bugs in certain situations?). Yifu Yan originally proposed a promising answer to this question in saying that "color is a named argument, it must have a name", though I would have appreciated more elaboration/explanation on this.

My current understanding is that it might not be possible to do what I want without duplicating calls to geoms. However, an example of a function I would have been looking for (without duplicating calls to geoms) would be:

scatterfun <- function (Data,Predictor,Response,has.Groups,Group.variable) {
  ggplot(Data,aes(x={{Predictor}},y={{Response}})) +
    geom_smooth(switch(has.Groups + 1,("colour='red'"),
                       aes(colour={{Group.variable}})))
}

Works when has.Groups = TRUE

scatterfun(mtcars,wt,mpg,T,factor(cyl))

enter image description here

(As you can see I would like to keep the confidence bands)

But doesn't work when has.Groups = FALSE:

scatterfun(mtcars,wt,mpg,F,factor(cyl))

Error: `mapping` must be created by `aes()`

So with this question, I was attempting to better understand that part when I want to conditionally add a mono-colour to a geom statement (that is why I had isolated this section in the beginning of my question). Hope it's a bit more clear now.


Solution

  • Scenario 1

    If you want either three line or one lines:

    condition <- TRUE
    ggplot(mtcars,aes(x=wt,y=mpg,colour=factor(cyl))) + 
        {
            if ( condition ){
                geom_smooth() 
            } else {
                geom_smooth(color = "black")
            }
        }
    

    enter image description here

    condition <- FALSE
    ggplot(mtcars,aes(x=wt,y=mpg,colour=factor(cyl))) + 
        {
            if ( condition ){
                geom_smooth() 
            } else {
                geom_smooth(color = "black")
            }
        }
    

    enter image description here

    Scenario 2

    To be clear, you always want three separate regression lines for each the groups. But, meanwhile, you also want to create a conditional regression line for data regardless of the groups.

    condition <- TRUE
    ggplot(mtcars,aes(x=wt,y=mpg,colour=factor(cyl))) + 
        geom_smooth(se = FALSE) +
        geom_smooth(colour = if (condition) "black" else NA,se = FALSE)
    

    enter image description here

    library(ggplot2)
    condition <- FALSE
    ggplot(mtcars,aes(x=wt,y=mpg,colour=factor(cyl))) + 
        geom_smooth(se = FALSE) +
        geom_smooth(colour = if (condition) "black" else NA,se = FALSE)
    

    enter image description here