Force Error Bars to Be in the Middle of Bar

Center error bars (geom_errorbar) horizontally on bars (geom_bar)

As data for error bars are located in the same data frame where data for the bars you don't need to provide argument data= in geom_errorbar() and also there is no need to call geom_errorbar() twice.

You should provide in geom_errorbar() ymin and ymax values in aes(), also color=supp in aes() will ensure that error bars are colored according to supp values. To get the same colors as for bars, add scale_color_manual() with the same color names. With argument position=position_dodge(0.9) you can get errorbars in center of bars.

ggplot(df1, aes(x=dose, y=len, fill=supp)) +      
geom_bar(stat="identity", position=position_dodge()) +
scale_fill_manual(name = "", values = c("deepskyblue1", "green")) +
geom_errorbar(aes(ymin=len-se, ymax=len+se,color=supp), width=.4,
position=position_dodge(.9))+
scale_color_manual(name = "", values = c("deepskyblue1", "green"))

Sample Image

Error bars in ggplot in middle of bin

When you add the group parameter to the aes, you will get the desired result:

ggplot(data=df, aes(x=Gene, y=FC, fill=expt, group=expt)) +
geom_bar(colour="black", stat="identity", position = position_dodge(width = 0.9)) +
geom_errorbar(aes(ymax = FC + se, ymin = FC, group=expt),
position = position_dodge(width = 0.9), width = 0.25)

this gives:

Sample Image

Generating a bar plot in R with error bars

Edit

Changed the labels as requested in the comment.

You can change a little the structure of your data.frame to get tha data in a shape that can be used for ggplot():

library(ggplot2)
dat <- data.frame(a=0.9685, b=0.0150831, c=0.9253333, d=0.03018388, e=0.9856667, f=0.01330664, g=0.9268333, h=0.05894885, i=0.9686667,j=0.01478738, k=0.9313333, l=0.07123389)
data <- data.frame(mean=unlist(dat[, 1:ncol(dat) %% 2 == 1]), sd=unlist(dat[, 1:ncol(dat) %% 2 == 0]))
data$x <- rownames(data)
data$category <- as.factor(sort(rep(1:3, 2)))
data$Method <- as.factor(rep(c('k-NN', 'Decision trees'), 3))
gg <- ggplot(aes(x=category, y=mean, fill=Method, group=Method), data=data)
gg <- gg + geom_bar(stat='identity', position = position_dodge(), width=.5)
gg <- gg + geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), position = position_dodge(width=.5), width=.2)
gg

Sample Image

ggplot Error bars does not fit on its bars

I think everything they told you in the comments above does work. See below.

#Turn Write.Ratio into a factor
data$Write.Ratio <- as.factor(data$Write.Ratio)

data <- transform(data,Systems = reorder(Systems, order(Latency, decreasing = F)))
plot1 <- ggplot(data, aes(Write.Ratio, Latency, fill = Systems))

#Add position=position_dodge(.9) to geom_errorbar
plot1 <- plot1 + geom_bar(stat = "identity", position="dodge") +
geom_errorbar(aes(ymin=Latency-ErrorBar, ymax=Latency+ErrorBar), width = .2, position=position_dodge(.9))

plot1 <- plot1+scale_y_continuous(breaks= seq(0,60,10))+labs(x = "Write Ratio")+
scale_x_discrete(labels = seq(25,100,25))+ labs(y="Latency (ms)")

plot1 <- plot1+scale_fill_manual(values=c("#2980b9", "#F5BF00", "#66CC99", "#6c3483"))

plot1 <- plot1+theme(panel.grid.major = element_blank())

plot1 <- plot1+theme_bw()+theme(legend.position="bottom")+labs(fill="")+
theme(text = element_text(size=18))

plot1

Sample Image

ggplot2 - Bars non-aligned to error bars

You should add group = variable inside the aes() of ggplot() to make position_dodge() work.

ggplot(data=df, aes(x=Period, y=value, group = variable)) +
geom_bar(aes(fill=variable), position='dodge', stat="identity", width=0.75) +
geom_errorbar(aes(ymin=ymin, ymax=ymax), position = position_dodge(0.75),width = 0.2) +
facet_wrap(~scenario) +
theme_bw(base_size=16)

The same can be atchieved if you move the fill = variable to the aes() of ggplot() from geom_bar().

ggplot(data=df, aes(x=Period, y=value, fill = variable)) +
geom_bar(position='dodge', stat="identity", width=0.75) +
geom_errorbar(aes(ymin=ymin, ymax=ymax), position = position_dodge(0.75),width = 0.2) +
facet_wrap(~scenario) +
theme_bw(base_size=16)

Position problem with geom_bar when using both width and dodge

TL;DR: From the start, position = "dodge" (or position = position_dodge(<some width value>)) wasn't doing what you thought it was doing.

Underlying intuition

position_dodge is one of the position-adjusting functions available in the ggplot2 package. If there are multiple elements belonging to different groups occupying the same location, position_identity would do nothing at all, position_dodge would place the elements side by side horizontally, position_stack would place them on top of one another vertically, position_fill would place them on top of one another vertically & stretch proportionally to fit the whole plot area, etc.

Here's a summary of different position-adjusting functions' behaviours, from RStudio's ggplot2 cheat sheet:

cheatsheet

Note that the elements to be dodged / etc. must belong to different groups. If group = <some variable> is specified explicitly in a plot, that would be used as the grouping variable for determining which elements should be dodged / etc. from one another. If there's no explicit group mapping in aes(), but there's one or more of color = <some variable> / fill = <some variable> / linetype = <some variable> / and so on, the interaction of all discrete variables would be used. From ?aes_group_order:

By default, the group is set to the interaction of all discrete
variables in the plot. This often partitions the data correctly, but
when it does not, or when no discrete variable is used in the plot,
you will need to explicitly define the grouping structure, by mapping
group to a variable that has a different value for each group.

Plot by plot breakdown

Let's start with your original plot. As there was no grouping variable of any kind in the plot's aesthetic mappings, position = "dodge" did absolutely nothing.

We can replace that with position = "identity" for both geom layers (in fact, position = "identity" is the default position for geom_errorbar, so there's no need to spell it out), and the resulting plot would be the same.

Increasing the transparency makes it obvious that the two bars are occupying the same spot, one "behind" another.

I guess this original plot isn't what you actually intended? There are really very few scenarios where it would make sense for one bar to be behind another like this...

ggplot(data = df, aes(x=group1, y = mean))+
geom_col(position = 'dodge') +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd),
position = 'dodge') +
ggtitle("original plot")

ggplot(data = df, aes(x=group1, y = mean))+
geom_col(position = "identity") +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd)) +
ggtitle("remove position dodge")

ggplot(data = df, aes(x=group1, y = mean))+
geom_col(position = "identity", alpha = 0.5) +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd)) +
ggtitle("increase transparency")

illustration 1

I'll skip over the second plot, since adding width = 0.2 didn't change anything fundamental.

In the third plot, we finally put position = "dodge" to use, because there's a group variable now. The bars & errorbars move accordingly, based on their respective widths. This is the expected behaviour if position = "dodge" is used instead of position = position_dodge(width = <some value>, ...), where the distance dodged follows the geom layer's width by default, unless it's overridden by a specific value in position_dodge(width = ...).

If the geom_errorbar layer kept to its default width (which is the same as the default width for geom_col), both layers' elements would have been dodged by the same amount.

ggplot(data = df, aes(x=group1, y = mean, fill = group2))+
geom_col(position = 'dodge') +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.2,
position = 'dodge') +
ggtitle("third plot")

ggplot(data = df, aes(x=group1, y = mean, fill = group2))+
geom_col(position = 'dodge') +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd),
position = 'dodge') +
ggtitle("with default width")

illustration 2

Side note: We know both geom_errorbar & geom_col have the same default width, because they set up their data in the same way. The following line of code can be found in both GeomErrorbar$setup_data / GeomCol$setup_data:

data$width <- data$width %||% params$width %||% (resolution(data$x, FALSE) * 0.9)
# i.e. if width is specified as one of the aesthetic mappings, use that;
# else if width is specified in the geom layer's parameters, use that;
# else, use 90% of the dataset's x-axis variable's resolution. <- default value of 0.9

In conclusion, when you have different aesthetic groups, specifying the width in position_dodge determines the distance moved by each element, while specifying the width in each geom layer's determines each element's... well, width. As long as different geom layers dodge by the same amount, they will be in alignment with one another.

Below is a random example for illustration, which uses different width values for each layer (0.5 for geom_col, 0.9 for geom_errorbar), but the same dodge width (0.6):

ggplot(data = df, aes(x=group1, y = mean, fill = group2))+
geom_col(position = position_dodge(0.6), width = 0.5) +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.9,
position = position_dodge(0.6)) +
ggtitle("another example")

example

Error Bar change upper, lower and center errors independently of each other

Figured it out. Apparently, you need to Series.Points.AddXY(xValue, CenterMarkerInErrorBar, LowerBoundsInErrorBar, UpperBoundsInErrorBar) .. But that wasn't documented anywhere that I could find from Microsoft.

Also, if you see the above information, you can't use the first two lines, as they'll break the error bars .. somehow. The last two lines and the code in this post will work fine, though.

Special thanks to MSChart C# Error Bar Graph With Dynamic Upper and Lower Bounds for the answer!

specify error bars with ggplot and facet_grid

The first and easiest solution would be to make your bar plot side-by-side instead of stacked. Then the only thing you need to change in your code is to add position="dodge" to your geom_bar() and run the rest of your code as you have it. This has the added benefit of being able to compare the heights of the different bars directly and avoids placing error bars in the middle of a bar.

ms.chl<- ggplot(mus3, aes(x=group, y=litium, fill=treatment)) +
geom_bar(stat="identity", colour="black",position="dodge") +
facet_grid(~day) + theme_bw()
ms.chl + geom_errorbar(aes(ymin=litium-se, ymax=litium+se), size=0.5,
width=.25,position=position_dodge(.9)) +
facet_grid(~day)

Sample Image

To add error bars on a stacked bar plot, you have to have make sure the bars are centered on the cumulative sum of litium. For this, you can use cumsum() within ave():

mus3 <- within(mus3,lit2 <- ave(litium,group,day,FUN=cumsum))

Then use lit2 instead of litium when you call geom_errorbar() and don't dodge.

ms.chl<- ggplot(mus3, aes(x=group, y=litium, fill=treatment)) +
geom_bar(stat="identity", colour="black") + facet_grid(~day) + theme_bw()

ms.chl + geom_errorbar(aes(ymin=lit2-se, ymax=lit2+se), size=0.5,
width=.25) + facet_grid(~day)

Sample Image

And if you just want the error bars for the group, then you have to get the errors for the whole group and not the group within treatment, but you can't just add that straight to the means based on the whole group, because those are means and the stacked bar plot has the sum of the means, so you have to sum the means from mus3.

musgroup <- summarySE(mus, measurevar="litium", 
groupvars=c("group", "day"), na.rm = TRUE)

musgroupsum <- ddply(mus3,.(group,day),summarize,lit2 = sum(litium))

mus4 <- merge(musgroup,musgroupsum)

ms.chl<- ggplot() +
geom_bar(data=mus3, aes(x=group, y=litium, fill=treatment),
stat="identity", colour="black") + facet_grid(~day) + theme_bw()

ms.chl + geom_errorbar(data=mus4,aes(x=group,ymin=lit2-se, ymax=lit2+se),
size=0.5, width=.25)

Sample Image

At this point, though, it starts getting a little nonsensical. The stacked means are not the group means--they are the sum of the group means, but the error is for the group mean. When you look at the figure the error bars will seem smaller in relation to the mean they represent because they are centered much higher than they ought to be. It seems like what you are looking for is a representation of the group mean that allows you to see the contribution of each of the treatments to that group mean. One way to show this is to scale the bar plot size so that the cumulative sum is centered on the proper mean for each of the groups.

mus3 <- within(mus3,lit3 <- ave(litium,group,day,FUN=function(x) x/length(x)))

ms.chl<- ggplot() +
geom_bar(data=mus3, aes(x=group, y=lit3, fill=treatment),
stat="identity", colour="black") + facet_grid(~day) +
theme_bw() + ylab("litium")

ms.chl + geom_errorbar(data=mus4,aes(x=group,ymin=litium-se, ymax=litium+se),
size=0.5,width=.25)

Sample Image



Related Topics



Leave a reply



Submit