geom_bar with multiple values for a category

1,432 views
Skip to first unread message

yoda230

unread,
Jan 20, 2011, 6:38:53 AM1/20/11
to ggplot2
Hello,

I have come across a situation where I want to do a bar plot grouped
by particular categories but some categories have more than one
value. In this situation I would like two bars by each other.

test <- data.frame(Name=c("yoda","yoda","luke"),Value=c(1:3))
ggplot(test,aes(Name,Value,fill=Name)) + geom_bar(position="dodge")

So here I would like 3 bars under two labels. Can this be done?

Thanks

Brandon Hurr

unread,
Jan 20, 2011, 6:54:01 AM1/20/11
to yoda230, ggplot2
How about...

test$fac<-c("a","b","a")
ggplot(test,aes(fac,Value)) + geom_bar(position="dodge")+ facet_grid(~Name, scales="free_x", space="free")

It's probably closer, but not really what you're asking for. 

B


--
You received this message because you are subscribed to the ggplot2 mailing list.
Please provide a reproducible example: http://gist.github.com/270442

To post: email ggp...@googlegroups.com
To unsubscribe: email ggplot2+u...@googlegroups.com
More options: http://groups.google.com/group/ggplot2

Dennis Murphy

unread,
Jan 20, 2011, 7:25:26 PM1/20/11
to yoda230, ggplot2
Hi:

The only way it seems to me you could do something like that is to create unique values/levels for the names to render the plot and then change the labels of the bars on the x-axis and legend. Here are a couple of stabs at it, although I don't think either of these are what you really wanted. More on that below.

# (1): Create a new variable with unique names in each row.
#        In particular, I created a 'yoda' and a 'Yoda'. This will get
#        you three bars with individual counts represented, and
#        the labels can be adjusted with scale_* calls.


test <- data.frame(Name=c("yoda","yoda","luke"),Value=c(1:3))
test$Name2 <- as.character(test$Name)
test$Name2[2] <- 'Yoda'
> test
  Name Value Name2
1 yoda     1  yoda
2 yoda     2  Yoda
3 luke     3  luke

g <- ggplot(test, aes(x = Name2, fill = Name2))
g + geom_bar(aes(weight = Value)) + labs(fill = 'Name', x = 'Name') +
     scale_x_discrete(breaks = unique(test$Name2), labels = test$Name) +
     scale_fill_discrete(breaks = unique(test$Name2), labels = test$Name)

#--------
This gets you a chart with three bars, two names and three colors. Closer, but not what you wanted.
#--------

# (2) Use the original factor Name to supply the fill colors and Name2 to get individual bars per line.

h <- ggplot(test, aes(x = Name2, fill = Name))
h + geom_bar(aes(weight = Value), position = 'dodge') +
     labs(fill = 'Name', x = 'Name') +
     scale_x_discrete(breaks = unique(test$Name2), labels = test$Name) +
     scale_fill_discrete(breaks = unique(test$Name2), labels = test$Name)

I tried to use position = 'dodge' to get the two 'yoda' bars to hug each other, but to no avail. The 'good' news is that now yoda has a single color and a single representation in the legend - that's some progress, but it's still not what you wanted. The problem is that position = 'dodge' doesn't work because the bars are defined by the values of Name2, so they are in some sense considered 'independent' or 'ungrouped'. I don't see how you can get around that in ggplot2.

The problem is that you want to generate separate bars for individual lines in the data file, even if they have the same identifier (Name), but at the same time you want (a) bars with the same name grouped together under a single name, and  (b) presumably, bars with the same name to have the same color. You haven't supplied a sufficiently rich labeling mechanism to allow that to happen. With some work, you could do what you want in base graphics, but you'd have to set the following manually: the spacing between bars, the labels, the fill colors and the legend. Most of this you can do in the barplot() call; the bar labels would likely have to be set with axis(). If you have any familiarity with barplot(), I don't think it would be all that hard - you just have to read the help page carefully.

My guess is that if you stick with ggplot2, you may end up having to do something that combines what I did above with what Brandon showed you earlier by faceting. Unfortunately, I don't have a lot of time today to invest in this problem, so hopefully someone will provide a better answer.

HTH,
Dennis


Kohske Takahashi

unread,
Jan 20, 2011, 8:54:42 PM1/20/11
to Dennis Murphy, yoda230, ggplot2
Hi, Yoda

Probably, this is what you want:

test <- data.frame(Name=c("yoda","yoda","luke"),Value=c(1:3), g=1:3)
ggplot(test,aes(Name,Value,fill=Name, group=g)) +
geom_bar(position=position_dodge(width=0.8), width=0.7)

sometimes the "group" in aes() makes some magics.

Now I'm a little surprised to see that Yoda, the grand master of Jedi
and the teacher of Luke, are interested in R and ggplot2.

--
Kohske Takahashi <takahash...@gmail.com>

Research Center for Advanced Science and Technology,
The University of  Tokyo, Japan.
http://www.fennel.rcast.u-tokyo.ac.jp/profilee_ktakahashi.html

Dennis Murphy

unread,
Jan 20, 2011, 9:14:14 PM1/20/11
to Kohske Takahashi, yoda230, ggplot2
Hi Kohske:

Thanks. I tried group, too, but not the way that you did. Useful lesson - I see it now!

Cheers,
Dennis

yoda230

unread,
Jan 21, 2011, 8:36:21 AM1/21/11
to ggplot2
Wow thanks Kohske that's perfect. Brilliant.

Remember though that I am not the one and true yoda that is yoda1!
Reply all
Reply to author
Forward
0 new messages