user1771185
user1771185

Reputation: 341

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.

Upvotes: 34

Views: 52909

Answers (4)

Brian Diggs
Brian Diggs

Reputation: 58875

The alignment problems are due, in part, to your bars not representing the data you intend. The following lines up correctly:

library(ggplot2)
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
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))

Created on 2024-05-23 with reprex v2.1.0

Upvotes: 28

Javid Dadashkarimi
Javid Dadashkarimi

Reputation: 51

Sometimes you put aes(x=tasks,y=val,fill=group) in geom_bar rather than ggplot. This causes the problem since ggplot is trying to find x and while you have specified it by the location of each group.

Upvotes: 5

nouse
nouse

Reputation: 3471

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) 

Upvotes: 15

Collin
Collin

Reputation: 460

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))

enter image description here

Upvotes: 4

Related Questions