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"))
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:
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
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
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:
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")
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")
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")
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)
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)
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)
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)
Related Topics
Grouping & Visualizing Cumulative Features in R
Reorder Rows Using Custom Order
How to Have Conditional Markdown Chunk Execution in Rmarkdown
Mgcv: How to Set Number And/Or Locations of Knots for Splines
Aesthetics Must Either Be Length One, or the Same Length as the Dataproblems
How to Pass Strings Denoting Expressions to Dplyr 0.7 Verbs
Create Sections Through a Loop with Knitr
Read CSV File Hosted on Google Drive
Mutating Column in 'Dplyr' Using 'Rowsums'
How to Create Base R Plot 'Type = B' Equivalent in Ggplot2
Use Fortran Subroutine in R? Undefined Symbol
Avoid Wasting Space When Placing Multiple Aligned Plots Onto One Page
Figure Captions, References Using Knitr and Markdown to HTML
Multiple Colour Scales in One Stacked Bar Plot Using Ggplot
How to Put the Labels Outside of Piechart
How to Automate Multiple Requests to a Web Search Form Using R