Reputation: 1488
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
aes
thethics. 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 aes
thetic. Naturally, the first
data frame has the correct lengths, so I figured it should be passing the y
aes
thetic 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
aes
thetic.
Am I missing something here?
Upvotes: 1
Views: 3889
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 geom
s 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