I'm attempting to plot a stacked barplot with ggplot2 with this code:

ggplot(CC, aes(x = Condition, y = Percent, fill = Cell_Cycle))+
  geom_bar(stat = "identity")+
  geom_text(aes(label = paste(round(Percent,2),"%")), position = position_stack(vjust =  0.5))

stacked bar graph

Question: How do I go about adding error bars to the graph?

I tried this code:

ggplot(DF, aes(x = Condition, y = Percent, fill = Cell_Type))+
     geom_bar(stat = "identity")+
     geom_text(aes(label = paste(round(Percent,2),"%")), position = position_stack(vjust =  0.5) + geom_errorbar(aes(ymin=Condition, ymax=Condition), width = .2))

But got this error:

Error: Cannot add ggproto objects together.

output of dput(DF)

structure(list(Cell_Type = structure(c(1L, 2L, 3L, 4L, 5L, 6L, 
7L, 1L, 2L, 3L, 4L, 5L, 6L, 7L), .Label = c("Fibroblast", "T cell", 
"Macrophage", "Tumor", "Islets of Langerhans", "Endothelial", 
"B cell"), class = "factor"), Condition = structure(c(1L, 1L, 
1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("treated", 
"untreated"), class = "factor"), Freq = c(6051L, 1892L, 1133L, 
657L, 116L, 868L, 832L, 5331L, 3757L, 1802L, 835L, 287L, 704L, 
256L), Percent = c(52.3941466793662, 16.3823707680319, 9.8103731924842, 
5.68880422547407, 1.00441596675037, 7.51580223395965, 7.20408693393367, 
41.0962072155412, 28.9623805118717, 13.8914585260561, 6.43694110391613, 
2.21245760098674, 5.42707369719396, 1.97348134443417)), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -14L), groups = structure(list(
    Condition = structure(1:2, .Label = c("treated", "untreated"
    ), class = "factor"), .rows = list(1:7, 8:14)), row.names = c(NA, 
-2L), class = c("tbl_df", "tbl", "data.frame"), .drop = TRUE))
  • $\begingroup$ What are len and sd ? can you add a reproducible example of DF, len,sd ? By curiosity, does your question is related to this one bioinformatics.stackexchange.com/questions/11197/…? $\endgroup$
    – dc37
    Jan 23, 2020 at 16:44
  • $\begingroup$ I didn't change len and sd when I pasted it. I have updated it to Condition and added the output of DF. And yes, it is related to that question. Wasn't sure whether to ask it on the same question. $\endgroup$
    – user6810
    Jan 23, 2020 at 16:51
  • $\begingroup$ In your exemple, there is no mention of len and sd, so it is not clear what are these values and how you want to calculate them. Also, does the related question is yours ? because you don't have the same username ? $\endgroup$
    – dc37
    Jan 23, 2020 at 17:02
  • $\begingroup$ len and sd are not part of my example. When I pasted the code to the question, I didn't change it. Yes, it is my question, as for the username, I just created a new account as I couldn't log into the other. $\endgroup$
    – user6810
    Jan 23, 2020 at 17:05
  • $\begingroup$ Ok, so your question is about to calculate len and sd ? because you don't have these values, right ? For your account, you can see this link: bioinformatics.stackexchange.com/help/merging-accounts. Also, when you are registered on one site of StackExchange, you can directly create a new account on another StackExchange website by clicking on topright join Community button, it will automatically link your account on all sites you are registered of. $\endgroup$
    – dc37
    Jan 23, 2020 at 17:13

1 Answer 1


If you want to indicate the error or the uncertainty for each cell type, you need to replicate your experiments, ccount each cell type in each replicate, calculate the average percentage of each cell type in each condition and the associated standard deviation.

To answer your question about how to plot a stacked bargraph with error bar, first this option is not integrated into ggplot2 (see this discussion from the creator of ggplot2: https://github.com/tidyverse/ggplot2/issues/1079)

So, you need to calculate the position of each error bar by hand. You can do that by using dplyr. Here, I set the same error bar for everyone as you don't know what is the standard deviation in your data but at least you can observe the structure of the dataframe:

DF %>% mutate(SD = 2) %>%
  mutate(Cell_Type = factor(Cell_Type, levels = c("B cell","Endothelial","Islets of Langerhans","Tumor","Macrophage","T cell","Fibroblast"))) %>%
  group_by(Condition) %>%
  mutate(SDPos = cumsum(Percent)) %>%
  ggplot(aes(x = Condition, y = Percent, fill = Cell_Type))+
  geom_bar(stat = "identity")+
  geom_text(aes(label = paste(round(Percent,2),"%")), position = position_stack(vjust =  0.5))+
  geom_errorbar(aes(ymin = SDPos-SD, ymax = SDPos+SD), width = 0.3, position = "identity")

enter image description here

As you can see, it's pretty ugly... so, if you need to add error bar, I will rather advised you to do a dodged barchart as the following:

DF %>% mutate(SD = 2) %>%
  ggplot(aes(x = Cell_Type, y = Percent, fill = Condition))+
  geom_bar(stat = "identity", position = position_dodge())+
  geom_text(aes(label = paste(round(Percent,2),"%")), position = position_dodge(0.9), vjust =-2, size = 3)+
  geom_errorbar(aes(ymin = Percent-SD, ymax = Percent+SD), width = 0.3, position = position_dodge(0.9))+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  scale_y_continuous(limits = c(-2,60))

enter image description here

To my opinion, it makes easier the comparison of the distribution of each cell type between conditions.

Hope that it answers your question.

  • $\begingroup$ For this scenario, I would advise against a barchart and would use a violin plot or a boxplot instead. The latter two would enable to assess the number of replicates within a group as well as the spread of the replicates. $\endgroup$
    – haci
    Jan 23, 2020 at 20:31
  • $\begingroup$ I agree if you are able to have more than 3 replicates. Otherwise, the spread observed with boxplot or violin plot won't mean a lot. But as it seems that individual values are the count of different cell types from single cell RNA seq, I doubt you can have a lot of replicates. That's why I advised for barchart. But it is also possible to plot individual values and the mean using geom_pointrange. $\endgroup$
    – dc37
    Jan 23, 2020 at 20:57
  • $\begingroup$ These numbers and graphs will not mean anything anyway if one does not have many replicates, especially if the data are from human samples and not from a model organism with a rather "clean" genetic background. Moreover, it is even more important to use box/violin plots when the number of replicates are small so that the reader is not mislead about the lack of power in the analyses. I guess, at least hope, that we will not see these plots in the future anyway: twitter.com/rafalab/status/1098973538260840449?lang=en $\endgroup$
    – haci
    Jan 23, 2020 at 21:47
  • $\begingroup$ Totally agree ;) and personally, I won't publish those kind of results (at least in this format). But it's well beyond the scope of the question :D $\endgroup$
    – dc37
    Jan 23, 2020 at 22:01
  • $\begingroup$ These samples are derived from human samples, and I have replicates for each sample. A total of 32 samples, 16 from each condition. What do you all propose I should use to plot? I'm new at bioinformatics, and assumed a bargraph would be ideal. From reading the comments and answer, I don't have SD for each. I will add that. $\endgroup$
    – user6810
    Jan 24, 2020 at 13:17

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.