7

What I am trying to do is create a "dodged" bar chart using gglot from two different dataframes

Unfortunately geom_bar doesn't see the previous data added so it plots it right over top, I've tried playing with position and width but it doesn't seem to change anything probably due to the fact that it is one bar per category.

The code below creates the data plots the data incorrectly (bars are on top of one another) and then plots it correctly using a workaround of binding the dataframes together.

library("ggplot2")

x<-data.frame(dat=rep(seq(1,4),3),let=rep("X"))
y<-data.frame(dat=rep(seq(1,4),4),let=rep("y"))

xy<-rbind(x,y)

#what I would like to use with two different data frames
ggplot(NULL,aes(dat))+
  geom_bar(data=y,fill="red",width=0.1,position = "dodge")+
  geom_bar(data=x,fill="blue",width=0.1,position = "dodge")

#what I would like to see only without binding dfs
ggplot(xy,aes(dat,fill=let))+geom_bar(position="dodge")

I'm using ggplot to be constant with other plots that use only a single dataframe.

tonytonov
  • 25,060
  • 16
  • 82
  • 98
gtwebb
  • 2,981
  • 3
  • 13
  • 22
  • 5
    Are you trying to avoid using `rbind` to create a combined `data.frame` at all costs, or do you just want to avoid creating a new object? For example, you could use `ggplot(data=rbind(x,y),aes(x=dat,fill=let))+geom_bar(binwidth=0.1,position="dodge")` so that `xy` isn't in the global environment. – nrussell Jul 16 '14 at 01:09
  • 2
    Will something like this work for you? `library(plyr); offset <- 0.05; ggplot(NULL,aes(dat)) + geom_bar(data=mutate(y, dat=dat-offset),fill="red") + geom_bar(data=mutate(x, dat=dat+offset),fill="blue")` – tonytonov Jul 16 '14 at 06:51
  • 2
    @tonytonov: You can do this without mutate, for example, `ggplot() + geom_bar(data=y, aes(dat-0.05), fill="red", width=0.2) + geom_bar(data=x, aes(dat+0.05), fill="blue", width=0.2)`. However, either way, notice that the red and blue bars are not lined up symmetrically on either side of the major tick marks (you can see this more easily if you increase the size of the offset). I expected the offset approach to work, and would be interested in the explanation for why it fails to place the bars in symmetric positions relative to the major tick marks. – eipi10 Jul 16 '14 at 12:15
  • @eipi10 Nice comment. I am also unable to explain why the alignment fails, not sure if that's a bug or we are missing something. – tonytonov Jul 16 '14 at 13:53
  • IIRC, `position` belongs `layer`, so there is no way to do this. – kohske Jul 16 '14 at 15:46
  • Thanks for the answers guys. All three of them work. I did want to avoid rbind since in the actual data I don't have a flag such as let (that was created just so I could bind them, which I could also do if needed). If anyone wanted to post them as an answer I would give you a vote. – gtwebb Jul 16 '14 at 15:58
  • An interesting thing with the alignment, not only is it not symmetrical around the major axis but the 4 different sets of bars are different from one another. If you add +xlim(0,5) it fixes the symmetry. – gtwebb Jul 16 '14 at 15:59
  • Strangely, other values of `xlim` can behave differently. For example, `xlim(-1,5)` results in the first two pairs of bars overlapping and the other two dodged, but not symmetrically about the tick mark. `xlim(0.5,4.5)` results in the first and third pairs of bars overlapping, while the second and fourth pairs are dodged symmetrically about the tick mark. – eipi10 Jul 16 '14 at 17:26

1 Answers1

7
ggplot(mapping=aes(x=dat))+
  geom_bar(data=y, aes(x=dat-0.1), fill="red", binwidth=0.1)+
  geom_bar(data=x, fill="blue", binwidth=0.1)

The key here is that you are shifting the data by the same amount as one binwidth and that binwidth is less than the spacing between groups. The binning is done on the data after shifting, so that affects which bin the data appears in. Also, without setting the binwidth explicitly, how wide the bins are depend on the range of the plot (which is why it varies when xlim was varied and worked "nicely" for round values).

enter image description here

Brian Diggs
  • 57,757
  • 13
  • 166
  • 188