1

The only prior question I could find was this one from 2012 but it doesn't seem to help in my case.

I want to plot the means of groups by subgroup using colors. I want to display error bars (confidence intervals) around the means. And I want the error bars to be less wide than the default.

Example code which data from iris (random data used for the fill variable):

library(ggplot2)

#data
df_sum = structure(list(Species = structure(c(1L, 1L, 2L, 2L, 3L, 3L), .Label = c("setosa", 
                                                                         "versicolor", "virginica"), class = "factor"), fillvar = c("A", 
                                                                                                                                    "B", "A", "B", "A", "B"), mean = c(1.43636363636364, 1.48214285714286, 
                                                                                                                                                                       4.16666666666667, 4.34615384615385, 5.49130434782609, 5.6037037037037
                                                                                                                                    ), n = c(22, 28, 24, 26, 23, 27), se = c(0.0429161341346969, 
                                                                                                                                                                             0.0281969506722072, 0.103676382414373, 0.0830626768411882, 0.112273142983994, 
                                                                                                                                                                             0.109320809356896), groupvar = structure(c(1L, 1L, 2L, 2L, 3L, 
                                                                                                                                                                                                                        3L), .Label = c("setosa", "versicolor", "virginica"), class = "factor"), 
               ci_bar = c(2.07961384472768, 2.05183051648029, 2.06865761041905, 
                          2.0595385527533, 2.07387306790403, 2.05552943864287)), .Names = c("Species", 
                                                                                            "fillvar", "mean", "n", "se", "groupvar", "ci_bar"), row.names = c(NA, 
                                                                                                                                                               -6L), class = "data.frame")

ggplot(df_sum, aes(x = groupvar, y = mean, fill = fillvar)) +
  geom_bar(stat="identity", position = "dodge") +
  geom_errorbar(aes(ymin = mean - ci_bar*se, ymax = mean + ci_bar*se), position = position_dodge(), width = .2) +
  xlab("Species") + ylab("Petal.Length")

Which produces: enter image description here

We see the problem. The error bars are dodged, but due to the width setting, they are not dodged far enough.

If we plot without the width setting:

ggplot(df_sum, aes(x = groupvar, y = mean, fill = fillvar)) +
  geom_bar(stat="identity", position = "dodge") +
  geom_errorbar(aes(ymin = mean - ci_bar*se, ymax = mean + ci_bar*se), position = position_dodge()) +
  xlab("Species") + ylab("Petal.Length")

We get: enter image description here

Which is what we expect, but the errors bars are too wide for my taste.

The problem seems to be that position_dodge has a width parameter and so does geom_errorbar. If one puts width=0.2 in the geom_errorbar, it gets forwarded to position_dodge as well which causes the dodge-offset problem. Notice that if one instead sets width inside position_dodge, it does not get forwarded to geom_errorbar (which is outside). This thus only results in the offset being off without the error bars' width changing:

ggplot(df_sum, aes(x = groupvar, y = mean, fill = fillvar)) +
  geom_bar(stat="identity", position = "dodge") +
  geom_errorbar(aes(ymin = mean - ci_bar*se, ymax = mean + ci_bar*se), position = position_dodge(width = .2)) +
  xlab("Species") + ylab("Petal.Length")

enter image description here

This is the reverse of what I want. The question then seems to be how to set width=0.2 inside geom_errorbar without ggplot2 forwarding it automatically to position_dodge.

I only found a slight hacking solution, which is to set the width to the default value (which seems to be 0.9) inside position_dodge to prevent it from getting filled in with the value from geom_errorbar:

ggplot(df_sum, aes(x = groupvar, y = mean, fill = fillvar)) +
  geom_bar(stat="identity", position = "dodge") +
  geom_errorbar(aes(ymin = mean - ci_bar*se, ymax = mean + ci_bar*se), position = position_dodge(width = .9), width = .2) +
  xlab("Species") + ylab("Petal.Length")

Which works as intended: enter image description here

Is there a non-hack solution to this problem?

Community
  • 1
  • 1
CoderGuy123
  • 6,219
  • 5
  • 59
  • 89
  • 1
    By default, the amount of dodging is calculated just so that overlapping is avoided *in the same geom*. You want the same amount of dodging in different geoms and thus you need to specify it manually (which is not a "hack"). See the last example in `help("position_dodge")`. – Roland Jun 03 '16 at 12:08
  • 3
    [A more thorough description of the `width` argument in `position_dodge`](http://stackoverflow.com/questions/34889766/what-is-the-width-argument-in-position-dodge/35102486#35102486). – Henrik Jun 03 '16 at 12:20

0 Answers0