Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geom_errorbar does not work properly with position_dodge in 0.9.0 #431

Closed
michaelhallquist opened this issue Mar 8, 2012 · 6 comments
Closed

Comments

@michaelhallquist
Copy link

A plot I previously created in ggplot2-0.8.9 no longer dodges the error bars despite properly dodging geom_line and geom_point. Here's the command I used. I'm running R 2.14.1 on Mac OS X 10.7. Downgrading to 0.8.9 fixed this problem. The result is a plot where the points and lines are dodged, but the error bars are are overlaid.

limits <- aes(ymax=mean + std.error, ymin=mean - std.error, linetype=NULL)
base_size=11

pos <- position_dodge(width=0.2)

Totalplot <- ggplot(allTotal, aes(x=time, y=mean, linetype=group)) + theme_bw(base_size=base_size) +
geom_line(position=pos, size=1.1) +
geom_errorbar(limits, width=0.2, position=pos) +
geom_point(position=pos, size=2.5) +
facet_wrap(~Disorder) +
ylab(paste("Mean number of total PD symptoms")) + xlab("Time since enrollment (years)") +
opts(legend.key.size=unit(2, "lines"), axis.ticks.margin = unit(0.25, "lines"), plot.margin = unit(c(1, 1, 0.5, 0.5), "lines")) +
opts(panel.margin = unit(0.7, "lines")) +
scale_x_continuous(breaks=c(0,1,2,3)) +
scale_linetype("Latent\ntrajectory") +
opts(axis.title.x = theme_text(size = base_size, vjust = 0.0)) +
opts(axis.title.y = theme_text(size = base_size, hjust = 0.5, vjust=0.3, angle=90)) +
opts(legend.title = theme_text(size = base_size * 0.8, hjust = 0))

@wch
Copy link
Member

wch commented Mar 8, 2012

It's hard to verify your issue without example data...

But this works for me:

dat <- data.frame(x=1:2, y=1:6, g=LETTERS[1:3], e=.5)
pos <- position_dodge(.2)
lim <- aes(ymin=y-e, ymax=y+e)

ggplot(dat, aes(x=x, y=y, colour=g)) + geom_point(position=pos) + 
  geom_errorbar(lim, position=pos, width=.1)

@michaelhallquist
Copy link
Author

Thanks for the follow-up. I should have included a reproducible example... When I tried to create a simple one extending the example you provided, I couldn't get the problem to show-up. But here is a dput of the actual data (which is pretty simple), along with a pared down version of the ggplot call that creates the failure to dodge error bars.

My sense is that it has to do with faceting and the order of the data. Apparently this issue is more complicated than I realized, though. On 0.9.0, the code below does not dodge the error bars. But under 0.8.9, it actually dodges the error bars incorrectly for the right-hand panel. If I sort the data by the faceting factor, then linetype factor, the dodging is correct.

library(ggplot2)
library(grid)
df <- structure(list(mean = c(18.5229357798165, 14.8888888888889, 0.363636363636364,
10.4495412844037, 0.555555555555556, 0.454545454545455, 9.91743119266055,
0, 3.54545454545455, 1.31506849315068, 12, 4.1, 1.12328767123288,
8.1578947368421, 0, 2.78082191780822, 6.97368421052632, 0), std.error = c(1.46441516614787,
3.80585967965643, 0.152120004824377, 1.07669583017945, 0.293972367896066,
0.281671516087812, 1.05135936473872, 0, 1.23850082661283, 0.150944152292836,
0.920757928874163, 0.504424865014052, 0.171111067785861, 1.31493571163454,
0, 0.345798094888679, 1.31491436048081, 0), group = structure(c(1L,
3L, 2L, 1L, 3L, 2L, 1L, 3L, 2L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L,
3L), .Label = c("1", "2", "3"), class = "factor"), Disorder = structure(c(2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L), .Label = c("NPD", "PPD"), class = "factor"), time = c(0,
0, 0, 0.97, 0.97, 0.97, 2.77, 2.77, 2.77, 0, 0, 0, 0.97, 0.97,
0.97, 2.77, 2.77, 2.77)), .Names = c("mean", "std.error", "group",
"Disorder", "time"), class = "data.frame", row.names = c(NA,
18L))

#if this command is not run in 0.8.9, the error bar dodging below is out of order in the right panel
#in 0.9.0, ordering has no effect (error bars are not dodged at all)
#df <- df[order(df$Disorder, df$group),]

limits <- aes(ymax=mean + std.error, ymin=mean - std.error, linetype=NULL)
pos <- position_dodge(width=0.2)
badplot <- ggplot(df, aes(x=time, y=mean, linetype=group)) +
geom_line(position=pos, size=1.1) +
geom_errorbar(limits, width=0.2, position=pos, show_guide=FALSE) +
geom_point(position=pos, size=2.0) +
facet_wrap(~Disorder)
print(badplot)

@BrianDiggs
Copy link
Contributor

It seems that the faceting variable is not being picked up as a grouping variable for the error bars where it is for the others. By explicitly setting the group to include it, you get consistent positioning (Using values defined in the previous comment):

ggplot(df, aes(x=time, y=mean, linetype=group, group=interaction(Disorder,group))) +
geom_line(position=pos, size=1.1) +
geom_errorbar(limits, width=0.2, position=pos, show_guide=FALSE) +
geom_point(position=pos, size=2.0) +
facet_wrap(~Disorder)

I haven't looked further, but hopefully this can help the next person.

@wch
Copy link
Member

wch commented Mar 12, 2012

I'm pretty sure this isn't a bug -- the reason it stopped working for you is because a bug in 0.8.9 was fixed! That bug is also the reason why you had to order the data frame in a particular way. I recently wrote about this same bug on the mailing list: http://groups.google.com/group/ggplot2/browse_thread/thread/e8e44bd0aa4c3074

Commit ac91fe4 is the one that changed the behavior.

In your default aesthetic mapping, you make group a grouping variable, by mapping it to linetype. But in this line of code, you unset the linetype=group mapping, so group is not a grouping variable for the error bars:

limits <- aes(ymax=mean + std.error, ymin=mean - std.error, linetype=NULL)

Since the error bars aren't grouped on the group variable, they won't be dodged.

If you re-run the same code without setting linetype=NULL, it works in 0.9.0:

# Dodging works, but with dashed and dotted error bars
limits <- aes(ymax=mean + std.error, ymin=mean - std.error)
pos <- position_dodge(width=0.2)
badplot <- ggplot(df, aes(x=time, y=mean, linetype=group)) + 
  geom_line(position=pos, size=1.1) + 
  geom_errorbar(limits, width=0.2, position=pos, show_guide=FALSE) + 
  geom_point(position=pos, size=2.0) +
  facet_wrap(~Disorder)
print(badplot)

Of course, you probably don't want the linetype of the error bars to be dotted and dashed like this. To make them all solid, but still use group as a grouping var, you can map aes(..., linetype=NULL, group=group):

# Dodging works, solid error bars
limits <- aes(ymax=mean + std.error, ymin=mean - std.error, linetype=NULL, group=group)
pos <- position_dodge(width=0.2)
badplot <- ggplot(df, aes(x=time, y=mean, linetype=group)) + 
  geom_line(position=pos, size=1.1) + 
  geom_errorbar(limits, width=0.2, position=pos, show_guide=FALSE) + 
  geom_point(position=pos, size=2.0) +
  facet_wrap(~Disorder)
print(badplot)

Or in the default mapping you can map group=group, then set linetype="solid" for the error bars.

# Dodging works, solid error bars
limits <- aes(ymax=mean + std.error, ymin=mean - std.error)
pos <- position_dodge(width=0.2)
badplot <- ggplot(df, aes(x=time, y=mean, linetype=group, group=group)) + 
  geom_line(position=pos, size=1.1) + 
  geom_errorbar(limits, width=0.2, position=pos, show_guide=FALSE, linetype="solid") + 
  geom_point(position=pos, size=2.0) +
  facet_wrap(~Disorder)
print(badplot)

@BrianDiggs
Copy link
Contributor

Sorry for misdiagnosing the problem. I didn't notice the linetype=NULL in limits.

@michaelhallquist
Copy link
Author

Thanks, Winston, and Brian for the suggestions. I see what you mean that unsetting linetype for the error bars should turn off the dodge positioning, so the undodged plot is quite sensible. Setting group and unsetting linetype in the mapping for the error bars works perfectly. I'll stick with this approach in the future.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 20, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants