ggplot2 density histogram with width=.5, vline and centered bar positions - r
I want a nice density (that sums to 1) histogram for some discrete data. I have tried a couple of ways to do this, but none were entirely satisfactory.
Generate some data:
#data
set.seed(-999)
d.test = data.frame(score = round(rnorm(100,1)))
mean.score = mean(d.test[,1])
d1 = as.data.frame(prop.table(table(d.test)))
The first gives the right placement of bars -- centered on top of the number -- but the wrong placement of vline(). This is because the x-axis is discrete (factor) and so the mean is plotted using the number of levels, not the values. The mean value is .89.
ggplot(data=d1, aes(x=d.test, y=Freq)) +
geom_bar(stat="identity", width=.5) +
geom_vline(xintercept=mean.score, color="blue", linetype="dashed")
The second gives the correct vline() placement (because the x-axis is continuous), but wrong placement of bars and the width parameter does not appear to be modifiable when x-axis is continuous (see here). I also tried the size parameter which also has no effect. Ditto for hjust.
ggplot(d.test, aes(x=score)) +
geom_histogram(aes(y=..count../sum(..count..)), width=.5) +
geom_vline(xintercept=mean.score, color="blue", linetype="dashed")
Any ideas? My bad idea is to rescale the mean so that it fits with the factor levels and use the first solution. This won't work well in case some of the factor levels are 'missing', e.g. 1, 2, 4 with no factor for 3 because no datapoint had that value. If the mean is 3.5, rescaling this is odd (x-axis is no longer an interval scale).
Another idea is this:
ggplot(d.test, aes(x=score)) +
stat_bin(binwidth=.5, aes(y= ..density../sum(..density..)), hjust=-.5) +
scale_x_continuous(breaks = -2:5) + #add ticks back
geom_vline(xintercept=mean.score, color="blue", linetype="dashed")
But this requires adjusting the breaks, and the bars are still in the wrong positions (not centered). Unfortunately, hjust does not appear to work.
How do I get everything I want?
density sums to 1
bars centered above values
vline() at the correct number
width=.5
With base graphics, one could perhaps solve this problem by plotting twice on the x-axis. Is there some similar way here?
It sounds like you just want to make sure that your x-axis values are numeric rather than factors
ggplot(data=d1, aes(x=as.numeric(as.character(d.test)), y=Freq)) +
geom_bar(stat="identity", width=.5) +
geom_vline(xintercept=mean.score, color="blue", linetype="dashed") +
scale_x_continuous(breaks=-2:3)
which gives
Related
How to set background color for each panel in grouped boxplot?
I plotted a grouped boxplot and trying to change the background color for each panel. I can use panel.background function to change whole plot background. But how this can be done for individual panel? I found a similar question here. But I failed to adopt the code to my plot. Top few lines of my input data look like Code p<-ggplot(df, aes(x=Genotype, y=Length, fill=Treatment)) + scale_fill_manual(values=c("#69b3a2", "#CF7737"))+ geom_boxplot(width=2.5)+ theme(text = element_text(size=20),panel.spacing.x=unit(0.4, "lines"), axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank(),axis.text.y = element_text(angle=90, hjust=1,colour="black")) + labs(x = "Genotype", y = "Petal length (cm)")+ facet_grid(~divide,scales = "free", space = "free") p+theme(panel.background = element_rect(fill = "#F6F8F9", colour = "#E7ECF1"))
Unfortunately, like the other theme elements, the fill aesthetic of element_rect() cannot be mapped to data. You cannot just send a vector of colors to fill either (create your own mapping of sorts). In the end, the simplest solution probably is going to be very similar to the answer you linked to in your question... with a bit of a twist here. I'll use mtcars as an example. Note that I'm converting some of the continuous variables in the dataset to factors so that we can create some more discrete values. It's important to note, the rect geom is drawn before the boxplot geom, to ensure the boxplot appears on top of the rect. ggplot(mtcars, aes(factor(carb), disp)) + geom_rect( aes(fill=factor(carb)), alpha=0.5, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + geom_boxplot() + facet_grid(~factor(carb), scales='free_x') + theme_bw() All done... but not quite. Something is wrong and you might notice this if you pay attention to the boxes on the legend and the gridlines in the plot panels. It looks like the alpha value is incorrect for some facets and okay for others. What's going on here? Well, this has to do with how geom_rect works. It's drawing a box on each plot panel, but just like the other geoms, it's mapped to the data. Even though the x and y aesthetics for the geom_rect are actually not used to draw the rectangle, they are used to indicate how many of each rectangle are drawn. This means that the number of rectangles drawn in each facet corresponds to the number of lines in the dataset which exist for that facet. If 3 observations exist, 3 rectangles are drawn. If 20 observations exist for one facet, 20 rectangles are drawn, etc. So, the fix is to supply a dataframe that contains one observation each for every facet. We have to then make sure that we supply any and all other aesthetics (x and y here) that are included in the ggplot call, or we will get an error indicating ggplot cannot "find" that particular column. Remember, even if geom_rect doesn't use these for drawing, they are used to determine how many observations exist (and therefore how many to draw). rect_df <- data.frame(carb=unique(mtcars$carb)) # supply one of each type of carb # have to give something to disp rect_df$disp <- 0 ggplot(mtcars, aes(factor(carb), disp)) + geom_rect( data=rect_df, aes(fill=factor(carb)), alpha=0.5, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + geom_boxplot() + facet_grid(~factor(carb), scales='free_x') + theme_bw() That's better.
Ggplot2 Boxplot width setting changes x-axis
I have produced a boxplot with a continuous x-axis unsing geom_boxplot() in ggplot2. However, as there are many boxes they appear as skinny lines. Another stackoverflow chain (see here) suggested using the width= argument to make all the boxes the same width. However, when I use this argument it changes the x-axis and some of the boxes just disappear! For example, take this example dataframe. I apologise for the number of observations this has but I think the quantity has to do with the problem as I couldn't reproduce it with a more simple boxplot: Lat<- c(50.70228,50.70228,50.70228,51.82067,51.82067,51.82067,52.45893,52.45893,52.45893,52.76478,52.76478,52.76478,52.78354,52.78354,52.78354,53.56102,53.56102,53.56102,53.65364,53.65364,53.65364,53.63130,53.63130,53.63130,54.19035,54.19035,54.19035,54.25751,54.25751,54.25751,54.23526,54.23526,54.23526,54.62469,54.62469,54.62469,54.67831,54.67831,54.67831,54.67900,54.67900,54.67900,54.94908,54.94908,54.94908,55.19456,55.19456,55.19456,54.79198,54.79198,54.79198,55.34981,55.34981,55.34981,55.85655,55.85655,55.85655,56.06078,56.06078,56.06078,55.84553,55.84553,55.84553,56.00197,56.00197,56.00197,56.71842,56.71842,56.71842,57.00116,57.00116,57.00116,57.06942,57.06942,57.06942,57.26815,57.26815,57.26815,57.45532,57.45532,57.45532,57.88596,57.88596,57.88596,51.07711,51.07711,51.07711,51.07801,51.07621,51.11159,51.11159,51.11159,52.02484,52.02484,52.02484,52.02581,52.02581,52.02581,52.02685,52.02685,52.02685,52.05353,52.05353,52.05626,52.05353,52.05353,52.05353,52.05353,52.05353,52.05353,51.93541,51.93541,51.93541,51.93541,51.93541,51.93541,51.93541,51.93541,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.90810,52.90810,52.90810,52.90810,52.90810,52.90810,52.78968,52.78778,52.78968,52.78968,52.78881,52.78883,52.78883,52.78883,52.78970,52.78970,52.79506,52.79506,52.79506,53.77270,53.77276,53.77109,53.77109,53.77276,53.76845,53.76845,53.77109,53.76845,53.77109,53.87020,53.87020,53.87020,53.87103,53.88205,53.88205,53.88205,53.88205,53.87701,53.87701,53.87098,53.87098,53.87098,53.86932,53.86932,53.86932,56.51869,56.51869,56.51869,56.55870,56.55870,56.55870,56.55964,56.55964,56.55964,57.51056,57.49542,57.49542,57.50878,57.50878,57.50878,57.45201,57.45477,57.45192,57.45192,57.45192) y <- c(33.45407,21.40954,27.73487,20.38318,26.65483,31.68201,23.95467,20.77363,32.94192,22.71228,25.78824,28.39449,35.60615,24.29325,22.95047,25.65343,30.23262,22.05534,37.20565,35.53812,38.20211,39.38034,35.16619,38.82336,29.72370,38.25754,26.51339,39.38283,29.57483,31.80111,24.52967,34.83037,21.75038,35.50868,39.41830,21.96971,22.82504,32.69746,35.10747,27.75669,34.96690,37.61921,37.17226,20.50448,39.26582,22.08668,28.41502,36.69530,23.69404,23.18052,33.27420,23.04157,33.17285,32.00579,21.83845,22.97143,32.27190,21.53771,38.65481,20.14341,33.62718,39.86755,39.77881,30.59810,27.65909,24.11646,34.56981,29.30249,34.99361,32.39553,28.90443,34.88775,22.77049,36.44468,30.64496,35.81501,31.77673,24.19058,39.36298,21.47219,23.02268,31.37647,27.28457,33.14749,23.20842,39.73427,39.81399,35.51515,24.55080,39.41190,29.59987,38.46791,20.94479,37.22109,26.36060,30.91641,39.25975,39.88288,22.59061,30.24439,21.66110,30.36878,28.76901,38.75561,33.80408,31.05842,26.18921,21.30804,35.02966,33.85981,30.84373,31.67341,35.07605,37.93820,31.30481,21.45117,37.13626,25.70964,25.64736,38.58381,31.24448,26.55902,23.90817,33.70300,26.48909,37.73200,32.52413,22.44440,28.19878,32.46415,25.13711,26.66075,28.16254,20.40673,39.89327,30.83327,32.40196,39.81218,39.80391,21.87316,34.95792,33.38958,38.18441,22.03114,35.64410,34.90643,24.23056,36.66581,29.35813,20.86880,30.02044,36.13727,24.65558,39.43175,29.00154,29.78185,22.89196,37.15204,35.88188,28.73920,28.04934,37.50701,30.36306,28.39842,35.20973,26.54260,29.57763,26.03163,26.90440,27.60110,25.80086,39.98019,21.59970,28.83825,32.01711,20.50812,38.43331,32.41898,27.68722,32.59905,24.18150,29.05701,22.38512,32.93342,37.66694,37.65391,34.19613,23.89985,36.90012,20.74244,27.08511,29.21433,35.83771,35.59557,33.74533,27.08854,38.38994) V3 <-c(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2) df <- as.data.frame(cbind(Lat, y, as.factor(V3))) head(df) I plot it on a continuous x-axis as so: df_plot <- ggplot(df, aes(x=Lat, y=y, group=Lat))+ geom_boxplot(aes(colour=as.factor(V3)))+ theme_classic() df_plot Which produces: As you can see the boxes are represented as skinny lines. Therefore I tried to use the width= argument as so: df_plot2 <- ggplot(df, aes(x=Lat, y=y, group=Lat))+ geom_boxplot(aes(colour=as.factor(V3)), width=1)+ theme_classic() df_plot2 The output is: The main thing to notice here is that the x-axis range has suddenly changed! Some of the boxes are no longer plotted whilst others seem to be placed at different values of the x-axis. The range of the x-axis should be: range(df$Lat) [1] 50.70228 57.88596 I am completley perplexed as to why the x-axis would change by simply adding the width= argument in geom_boxplot(). I therefore tried to force the limits of the x-axis scale as so: df_plot3 <- ggplot(df, aes(x=Lat, y=y, group=Lat))+ geom_boxplot(aes(colour=as.factor(V3)), width=1)+ xlim(50,58)+ theme_classic() df_plot3 ouput: Please send help!
I think the strange behaviour comes from ggplot trying to automatically dodge your boxplots apart. By setting position = position_dodge(width = 0) the plot seems to be created as expected without changing the placement of boxes along the x-axis. (But gives a warning about overlapping x intervals) Lat<- c(50.70228,50.70228,50.70228,51.82067,51.82067,51.82067,52.45893,52.45893,52.45893,52.76478,52.76478,52.76478,52.78354,52.78354,52.78354,53.56102,53.56102,53.56102,53.65364,53.65364,53.65364,53.63130,53.63130,53.63130,54.19035,54.19035,54.19035,54.25751,54.25751,54.25751,54.23526,54.23526,54.23526,54.62469,54.62469,54.62469,54.67831,54.67831,54.67831,54.67900,54.67900,54.67900,54.94908,54.94908,54.94908,55.19456,55.19456,55.19456,54.79198,54.79198,54.79198,55.34981,55.34981,55.34981,55.85655,55.85655,55.85655,56.06078,56.06078,56.06078,55.84553,55.84553,55.84553,56.00197,56.00197,56.00197,56.71842,56.71842,56.71842,57.00116,57.00116,57.00116,57.06942,57.06942,57.06942,57.26815,57.26815,57.26815,57.45532,57.45532,57.45532,57.88596,57.88596,57.88596,51.07711,51.07711,51.07711,51.07801,51.07621,51.11159,51.11159,51.11159,52.02484,52.02484,52.02484,52.02581,52.02581,52.02581,52.02685,52.02685,52.02685,52.05353,52.05353,52.05626,52.05353,52.05353,52.05353,52.05353,52.05353,52.05353,51.93541,51.93541,51.93541,51.93541,51.93541,51.93541,51.93541,51.93541,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.92425,52.90810,52.90810,52.90810,52.90810,52.90810,52.90810,52.78968,52.78778,52.78968,52.78968,52.78881,52.78883,52.78883,52.78883,52.78970,52.78970,52.79506,52.79506,52.79506,53.77270,53.77276,53.77109,53.77109,53.77276,53.76845,53.76845,53.77109,53.76845,53.77109,53.87020,53.87020,53.87020,53.87103,53.88205,53.88205,53.88205,53.88205,53.87701,53.87701,53.87098,53.87098,53.87098,53.86932,53.86932,53.86932,56.51869,56.51869,56.51869,56.55870,56.55870,56.55870,56.55964,56.55964,56.55964,57.51056,57.49542,57.49542,57.50878,57.50878,57.50878,57.45201,57.45477,57.45192,57.45192,57.45192) y <- c(33.45407,21.40954,27.73487,20.38318,26.65483,31.68201,23.95467,20.77363,32.94192,22.71228,25.78824,28.39449,35.60615,24.29325,22.95047,25.65343,30.23262,22.05534,37.20565,35.53812,38.20211,39.38034,35.16619,38.82336,29.72370,38.25754,26.51339,39.38283,29.57483,31.80111,24.52967,34.83037,21.75038,35.50868,39.41830,21.96971,22.82504,32.69746,35.10747,27.75669,34.96690,37.61921,37.17226,20.50448,39.26582,22.08668,28.41502,36.69530,23.69404,23.18052,33.27420,23.04157,33.17285,32.00579,21.83845,22.97143,32.27190,21.53771,38.65481,20.14341,33.62718,39.86755,39.77881,30.59810,27.65909,24.11646,34.56981,29.30249,34.99361,32.39553,28.90443,34.88775,22.77049,36.44468,30.64496,35.81501,31.77673,24.19058,39.36298,21.47219,23.02268,31.37647,27.28457,33.14749,23.20842,39.73427,39.81399,35.51515,24.55080,39.41190,29.59987,38.46791,20.94479,37.22109,26.36060,30.91641,39.25975,39.88288,22.59061,30.24439,21.66110,30.36878,28.76901,38.75561,33.80408,31.05842,26.18921,21.30804,35.02966,33.85981,30.84373,31.67341,35.07605,37.93820,31.30481,21.45117,37.13626,25.70964,25.64736,38.58381,31.24448,26.55902,23.90817,33.70300,26.48909,37.73200,32.52413,22.44440,28.19878,32.46415,25.13711,26.66075,28.16254,20.40673,39.89327,30.83327,32.40196,39.81218,39.80391,21.87316,34.95792,33.38958,38.18441,22.03114,35.64410,34.90643,24.23056,36.66581,29.35813,20.86880,30.02044,36.13727,24.65558,39.43175,29.00154,29.78185,22.89196,37.15204,35.88188,28.73920,28.04934,37.50701,30.36306,28.39842,35.20973,26.54260,29.57763,26.03163,26.90440,27.60110,25.80086,39.98019,21.59970,28.83825,32.01711,20.50812,38.43331,32.41898,27.68722,32.59905,24.18150,29.05701,22.38512,32.93342,37.66694,37.65391,34.19613,23.89985,36.90012,20.74244,27.08511,29.21433,35.83771,35.59557,33.74533,27.08854,38.38994) V3 <-c(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2) library(ggplot2) df <- as.data.frame(cbind(Lat, y, as.factor(V3))) df_plot <- ggplot(df) + geom_boxplot(aes(colour=as.factor(V3), x=Lat, y=y, group=as.factor(Lat)), position=position_dodge(width = 0), width=1) + theme_classic()
Boxplot overlaid on dot plot + means, means in wrong position
Using advice given in Overdraw mean points in grouped boxplot with ggplot2 I tried FEV <- expand.grid(sex=c('female', 'male'), smoke=c('no', 'yes'), reps=1:5) set.seed(1) FEV$fev <- runif(nrow(FEV), 1, 4) ggplot(FEV, aes(x=smoke, y=fev, color=sex)) + geom_boxplot(alpha=.5, width=.2) + # remove width to overlay boxes on pts stat_summary(fun.y=mean, geom="point", shape=5, size=2, position=position_dodge(width=.2)) + geom_dotplot(binaxis='y', stackdir='center', position='dodge') + xlab('') + ylab(expression(FEV[1])) + coord_flip() The means are not placed quite correctly in the vertical sense. Guidance welcomed. Note: I like having the box plots between the two sets of dots; that's not the problem.
The help for ?position_dodge just says that dodging things with different widths is tricky - I usually tweak this manually. Trying a few values, it looks like you want the points to take a dodge width that is 3/4 of the boxplot width but I don't know why or if that holds for other geoms. I would try changing the width for the stat_summary call to 0.15
ggplot2 histogram of factors showing the probability mass instead of count
I am trying to use the excellent ggplot2 using the bar geom to plot the probability mass rather than the count. However, using aes(y=..density..) the distribution does not sum to one (but is close). I think the problem might be due to the default binwidth for factors. Here is an example of the problem, age <- c(rep(0,4), rep(1,4)) mppf <- c(1,1,1,0,1,1,0,0) data.test <- as.data.frame(cbind(age,mppf)) data.test$age <- as.factor(data.test$age) data.test$mppf <- as.factor(data.test$mppf) p.test.density <- ggplot(data.test, aes(mppf, group=age, fill=age)) + geom_bar(aes(y=..density..), position='dodge') + scale_y_continuous(limits=c(0,1)) dev.new() print(p.test.density) I can get around this problem by keeping the x-variable as continuous and setting binwidth=1, but it doesn't seem very elegant. data.test$mppf.numeric <- as.numeric(data.test$mppf) p.test.density.numeric <- ggplot(data.test, aes(mppf.numeric, group=age, fill=age)) + geom_histogram(aes(y=..density..), position='dodge', binwidth=1)+ scale_y_continuous(limits=c(0,1)) dev.new() print(p.test.density.numeric)
I think you almost have it figured out, and would have once you realized you needed a bar plot and not a histogram. The default width for bars with categorical data is .9 (See ?stat_bin. The help page for geom_bar doesn't give the default bar width but does send you to stat_bin for further reading.). Given that, your plots show the correct density for a bar width of .9. Simply change to a width of 1 and you will see the density values you expected to see. ggplot(data.test, aes(x = mppf, group = age, fill = age)) + geom_bar(aes(y=..density..), position = "dodge", width = 1) + scale_y_continuous(limits=c(0,1))
How to make dodge in geom_bar agree with dodge in geom_errorbar, geom_point
I have a dataset where measurements are made for different groups at different days. I want to have side by side bars representing the measurements at the different days for the different groups with the groups of bars spaced according to day of measurement with errorbars overlaid to them. I'm having trouble with making the dodging in geom_bar agree with the dodge on geom_errorbar. Here is a simple piece of code: days = data.frame(day=c(0,1,8,15)); groups = data.frame(group=c("A","B","C","D", "E"), means=seq(0,1,length=5)); my_data = merge(days, groups); my_data$mid = exp(my_data$means+rnorm(nrow(my_data), sd=0.25)); my_data$sigma = 0.1; png(file="bar_and_errors_example.png", height=900, width=1200); plot(ggplot(my_data, aes(x=day, weight=mid, ymin=mid-sigma, ymax=mid+sigma, fill=group)) + geom_bar (position=position_dodge(width=0.5)) + geom_errorbar (position=position_dodge(width=0.5), colour="black") + geom_point (position=position_dodge(width=0.5), aes(y=mid, colour=group))); dev.off(); In the plot, the errorsegments appears with a fixed offset from its bar (sorry, no plots allowed for newbies even if ggplot2 is the subject). When binwidth is adjusted in geom_bar, the offset is not fixed and changes from day to day. Notice, that geom_errorbar and geom_point dodge in tandem. How do I get geom_bar to agree with the other two? Any help appreciated.
The alignment problems are due, in part, to your bars not representing the data you intend. The following lines up correctly: ggplot(my_data, aes(x=day, weight=mid, ymin=mid-sigma, ymax=mid+sigma, fill=group)) + geom_bar (position=position_dodge(), aes(y=mid), stat="identity") + geom_errorbar (position=position_dodge(width=0.9), colour="black") + geom_point (position=position_dodge(width=0.9), aes(y=mid, colour=group))
This is an old question, but since i ran into the problem today, i want to add the following: In geom_bar(position = position_dodge(width=0.9), stat = "identity") + geom_errorbar( position = position_dodge(width=0.9), colour="black") the width-argument within position_dodge controls the dodging width of the things to dodge from each other. However, this produces whiskers as wide as the bars, which is possibly undesired. An additional width-argument outside the position_dodge controls the width of the whiskers (and bars): geom_bar(position = position_dodge(width=0.9), stat = "identity", width=0.7) + geom_errorbar( position = position_dodge(width=0.9), colour="black", width=0.3)
The first change I reformatted the code according to the advanced R style guide. days <- data.frame(day=c(0,1,8,15)) groups <- data.frame( group=c("A","B","C","D", "E"), means=seq(0,1,length=5) ) my_data <- merge(days, groups) my_data$mid <- exp(my_data$means+rnorm(nrow(my_data), sd=0.25)) my_data$sigma <- 0.1 Now when we look at the data we see that day is a factor and everything else is the same. str(my_data) To remove blank space from the plot I converted the day column to factors. CHECK that the levels are in the proper order before proceeding. my_data$day <- as.factor(my_data$day) levels(my_data$day) The next change I made was defining y in your aes arguments. As I'm sure you are aware, this lets ggplot know where to look for y values. Then I changed the position argument to "dodge" and added the stat="identity" argument. The "identity" argument tells ggplot to plot y at x. geom_errorbar inherits the dodge position from geom_bar so you can leave it unspecified, but geom_point does not so you must specify that value. The default dodge is position_dodge(.9). ggplot(data = my_data, aes(x=day, y= mid, ymin=mid-sigma, ymax=mid+sigma, fill=group)) + geom_bar(position="dodge", stat = "identity") + geom_errorbar( position = position_dodge(), colour="black") + geom_point(position=position_dodge(.9), aes(y=mid, colour=group))
sometimes you put aes(x=tasks,y=val,fill=group) in geom_bar rather than ggplot. This causes the problem since ggplot looks forward x and you specify it by the location of each group.