I need to create a barplot with error bars, my data consists of 2 groups called "Genot", with 3 sub-groups "Suberin" for each, associated with a value "Percent".

summary_data <- FY %>%
  group_by(Genot, Suberin) %>%
    Mean_Percent = mean(Percent),
    SD_Percent = sd(Percent))

# plot
ggplot(summary_data, aes(x = Genot, y = Mean_Percent, fill=Suberin)) +
  geom_bar(stat = 'identity', aes(fill = Suberin)) +
  geom_errorbar(data = summary_data,
                aes(x = Genot, ymax = Mean_Percent + SD_Percent, ymin = Mean_Percent - SD_Percent), 
                , position = "identity",width = 0.2)

enter image description here

My main problem is that the error bars are placed from 0, but I have to order my data as the following to get the graph in the order I want.

FY$Suberin <- ordered(FY$Suberin,
                    levels = c("Con", "Patchy","Non" ))

I can't figure out a way to describe the positions

  • $\begingroup$ I understand why you're trying to do this, but I think that the plot will be kind of hard to look at regardless. I'd suggest making your life simpler and using grouped bars instead. $\endgroup$ Commented Nov 27, 2023 at 14:20
  • 2
    $\begingroup$ wait, in your second code block, you are overwriting only that column. You're not actually reordering the rest of the data. Is that intentional? $\endgroup$ Commented Nov 27, 2023 at 14:22
  • $\begingroup$ In my field and for these particular data stacked barplots are what we have to use $\endgroup$
    – user18598
    Commented Nov 29, 2023 at 8:22
  • $\begingroup$ In the second code block, I am reordering the full dataset based on the argument "Suberin", this is to obtain my plot with "Non", "Patchy" and "Con" (starting from 0) $\endgroup$
    – user18598
    Commented Nov 29, 2023 at 8:29

1 Answer 1


(Following from comments)

I am 99% sure that, in the second code block, you are reordering only that one column and the rest of the columns are remaining unordered. That means that that column will be permuted with respect to the rest of the data, which I doubt is what you intend. I'd suggest instead running this, which will reorder the whole dataframe:

# not actually run cause I don't have the data, check it!
FY <- FY[
               levels = c("Con", "Patchy","Non" )

Consider this analogous example:

> test = data.frame(
  "three"=c("this", "that", "which")
> test
  one two three
1   1   6  this
2   2   5  that
3   3   4 which
> test$three = ordered(test$three, levels=c("that", "this", "which"))
# only column "three" is reordered!!!
> test
  one two three
1   1   6  this
2   2   5  that
3   3   4 which

# THIS reorders the whole dataframe
> test[order(test$three),]
  one two three
2   2   5  that
1   1   6  this
3   3   4 which

# impose a specific ordering by making it a factor, maybe there's a better way
> test[order(factor(test$three, levels=c("that", "which", "this"))),]
  one two three
2   2   5  that
3   3   4 which
1   1   6  this

I don't know that that impacts your error bar issue. But the underlying data will certainly be affected and possibly made inaccurate by permuting only one column.

Another thing that's a little weird is that you're computing Mean_Percent in two places: first, in your summarise expression, and then again when you actually make the plot with geom_bar(stat="identity"..., which will fill the axes you've set up with newly estimated values based on the relative frequencies of the Suberin column. So you aren't plotting the Mean_Percent values that you are getting from summarise, as far as I can tell.

I'm a little scared of the way that you are computing mean/sd percentages and stacking them, especially not knowing what the data look like. I'd recommend confirming that your Mean_Percent that you compute with summarise adds up to 100%; for the actual bars in the barplot you are letting geom_bar recompute the proportions directly from the data, so I don't think the fact that it apparently adds up to 100% in the plot is trustworthy. To summarize: it'd make sense to confirm that what's in your dataframe matches what's in the plot since they are separately computed.

I don't know exactly that either of these issues is leading to your error bars having the wrong central tendencies, but investigating a couple of these lines may lead you to discover something.

I'm not a ggplot person so I can't diagnose just by looking at your code, and obviously I don't have your data so I can't tinker with it. Someone with more experience there might be a good idea. However, there are some related questions on SO that may be worth reading over.

Note again that none other than Hadley Wickham finds this kind of plot confusing.

  • $\begingroup$ Cool answer, @user185980 please consider marking it as accepted. ggplot is a hassle and there's no-one here who'd really do this ... I know it, its just fiddly. $\endgroup$
    – M__
    Commented Dec 1, 2023 at 4:07
  • 1
    $\begingroup$ @M__ appreciate the callout, but I'm not sure that my answer really addresses their concern- I didn't solve the problem! I merely have worries about the approach. $\endgroup$ Commented Dec 1, 2023 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.