cimentadaj
cimentadaj

Reputation: 1488

ggplot2 asking for a non-existent aesthetic in geom_errorbar

I actually found the answer to be my problem but I was wondering whether this is a bug or not.

Suppose I have this:

library(ggplot2)
library(dplyr)
first <-
mtcars %>%
  group_by(vs) %>%
  summarise(mean = mean(mpg),
            lower_ci = mean(mpg) - 2 * sd(mpg),
            upper_ci = mean(mpg) + 2 * sd(mpg))

I can make a layered plot like this:

ggplot(data = mtcars, aes(x = as.factor(vs))) +
  geom_point(aes(y = mpg), alpha = 0.2) +
  geom_point(data = first, aes(y = mean), colour = "red") +
  geom_errorbar(data = first, aes(ymin = lower_ci, ymax = upper_ci))

Great, no problem. Let's recreate the plot step by step.

graph <- ggplot()
graph <- graph + geom_point(alpha = 0.2)
graph <- graph %+% mtcars + aes(x = as.factor(vs), y = mpg)
graph <- graph + geom_point(data = first, aes(x = as.factor(vs), y = mean, colour = "red"))

At this point I only have to overlay the error bars which need the x, ymin and ymax aesthethics. However, the graph object has a predefined y in the structure of the object. For some reason, if I add this:

graph + geom_errorbar(data = first,
                               aes(x = as.factor(vs), ymin = lower_ci, ymax = upper_ci))

which I would think is the right way, it throws an error about the length of the aesthetic. Naturally, the first data frame has the correct lengths, so I figured it should be passing the y aesthetic from the global options.

If I add this:

graph + geom_errorbar(data = first,
                               aes(x = as.factor(vs), y = NULL, ymin = lower_ci, ymax = upper_ci))

It fixes it and as expected throws the Warning: Ignoring unknown aesthetics: y.

I would assume that the global options of the object would recognize that geom_errorbar doesn't require a y aesthetic.

Am I missing something here?

Upvotes: 1

Views: 3889

Answers (1)

Gregor Thomas
Gregor Thomas

Reputation: 145965

Am I missing something here?

No. You identified the issue correctly; you are just assuming there is something else. It's a small bug that probably isn't worth fixing.

I would assume that the global options of the object would recognize that geom_errorbar doesn't require a y aesthetic.

Aesthetics are inherited by default (you can avoid the error by setting inherit.aes = FALSE)), and they are immediately checked against the available data. If an inherited mapped column isn't available because it isn't in the data frame for the layer, an error is thrown.

Here's another example. It's not really different from the one in your question, but it uses more common geoms and is a little simpler:

df1 = data.frame(x1 = 1:2, y1 = 3:4, ty = 'a')
df2 = data.frame(x2 = 1, y2 = 5)

ggplot(df1, aes(x1, y1, linetype = ty)) +
    geom_line() + 
    geom_point(data = df2, aes(x = x2, y = y2))
# Error in eval(expr, envir, enclos) : object 'ty' not found

Even though geom_point doesn't take a linetype aesthetic, because there isn't a data column in df2 named ty, we get an error. As below, the easy fix is to set inherit.aes = FALSE:

ggplot(df1, aes(x1, y1, lintype = ty)) +
    geom_line() + 
    geom_point(data = df2, aes(x = x2, y = y2), inherit.aes = FALSE)
## works

Upvotes: 2

Related Questions