11

So I am trying to make a stacked bar graph with bar width mapped to a variable; but I want the spacing between my bars to be constant.

Does anyone know how to make the spacing constant between the bars?

Right now I've got this:

p<-ggplot(dd, aes(variable, value.y, fill=Date, width=value.x / 15))+ coord_flip() + opts(ylab="") 

p1<-p+ geom_bar(stat="identity") + scale_fill_brewer(palette="Dark2") + scale_fill_hue(l=55,c=55)

p2<-p1 + opts(axis.title.x = theme_blank(), axis.title.y = theme_blank())

p2

enter image description here

Thanks in advance.

Here's my data by the way (sorry for the long, bulky dput):

> dput(dd)
structure(list(variable = structure(c(1L, 1L, 1L, 1L, 1L, 3L, 
3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 7L, 7L, 7L, 7L, 7L, 2L, 2L, 
2L, 2L, 2L, 6L, 6L, 6L, 6L, 6L, 5L, 5L, 5L, 5L, 5L, 9L, 9L, 9L, 
9L, 9L, 8L, 8L, 8L, 8L, 8L), .Label = c("Alcohol and Tobacco", 
"Health and Personal Care", "Clothing", "Energy", "Recreation and Education", 
"Household", "Food", "Transportation", "Shelter"), class = "factor", scores = structure(c(2.91, 
5.31, 10.08, 15.99, 4.95, 11.55, 11.2, 27.49, 20.6), .Dim = 9L, .Dimnames = list(
    c("Alcohol and Tobacco", "Clothing", "Energy", "Food", "Health and Personal Care", 
    "Household", "Recreation and Education", "Shelter", "Transportation"
    )))), value.x = c(2.91, 2.91, 2.91, 2.91, 2.91, 5.31, 5.31, 
5.31, 5.31, 5.31, 10.08, 10.08, 10.08, 10.08, 10.08, 15.99, 15.99, 
15.99, 15.99, 15.99, 4.95, 4.95, 4.95, 4.95, 4.95, 11.55, 11.55, 
11.55, 11.55, 11.55, 11.2, 11.2, 11.2, 11.2, 11.2, 27.49, 27.49, 
27.49, 27.49, 27.49, 20.6, 20.6, 20.6, 20.6, 20.6), Date = structure(c(5L, 
4L, 3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L, 5L, 4L, 
3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L, 5L, 4L, 3L, 
2L, 1L, 5L, 4L, 3L, 2L, 1L, 5L, 4L, 3L, 2L, 1L), .Label = c("1993-2001", 
"2001-2006", "2007-2010", "2010-2011", "2012 Jan - May"), class = "factor"), 
    value.y = c(2.1, 2.5, 7.6, 21.7, 2.8, 1.5, 0.3, -4.1, -4.2, 
    4.7, 3, 16.9, 1.9, 32.8, 23.9, 3.2, 4.6, 11.3, 8.9, 12.9, 
    1.7, 2, 7.8, 5.9, 10, 1.9, 2.1, 5.6, 2.2, 9.9, 1.4, 1.3, 
    2.2, 0.6, 17.3, 1.1, 2.3, 6.4, 13.1, 10, 4.3, 7.6, 0.9, 15.2, 
    20.5)), .Names = c("variable", "value.x", "Date", "value.y"
), row.names = c(NA, -45L), class = "data.frame")
Justin
  • 42,475
  • 9
  • 93
  • 111
user1443010
  • 267
  • 3
  • 9

2 Answers2

9

For a categorical or "discrete" scale - you can adjust the width, but it needs to be between 0 and 1. Your value.x's put it over 1, hence the overlap. You can use rescale, from the scales packages to adjust this quickly so that the within category width of the bar is representative of some other variable (in this case value.x)

install.packages("scales")
library(scales) 
ggplot(dd,aes(x=variable,y=value.y,fill=Date)) +
geom_bar(aes(width=rescale(value.x,c(0.5,1))),stat="identity",position="stack")' +
coord_flip()

Play with rescaling for optimal "view" change 0.5 to 0.25... etc.

enter image description here

Personally, I think something like this is more informative:

ggplot(dd,aes(x=variable,y=value.y,fill=Date)) +
geom_bar(aes(width=rescale(value.x,c(0.2,1))),stat="identity") +
coord_flip() + facet_grid(~Date) + opts(legend.position="none")

enter image description here

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255
  • Thanks for the reply, but I'm actually trying to stop the overlap not by readjusting the width of the bars (I need the large width differential in order for it to be visually effective), I'm looking to force the amount of blank space between bars to be constant. Can this be done? – user1443010 Jul 05 '12 at 19:04
  • Also I see how in some situations the facet grid would be a better choice, but in this situation the value in the years culminates in a final value so for my purposes the original format is good. – user1443010 Jul 05 '12 at 19:07
  • For categorical variables, I don't believe there is a way to adjust the width uniquely for each element of the scale. Although, there have been some adjustments to scale_x_discrete() in 0.91, so perhaps your question would be better answered on the ggplot2 mailing list. With respect to the best view, perhaps, putting a label on each bar would be helpful if you're going to keep them together but still want to compare between categories. – Brandon Bertelsen Jul 05 '12 at 19:31
5

Attempt # 2.

I'm tricking ggplot2 into writing a continuous scale as categorical.

# The numbers for tmp I calculated by hand. Not sure how to program 
# this part but the math is 
# last + half(previous_width) + half(current_width)
# Change the 1st number in cumsum to adjust the between category width

tmp <- c(2.91,7.02,14.715,27.75,38.22,46.47,57.845,77.19,101.235) + cumsum(rep(5,9))

dd$x.pos1 <- rep(tmp,each=5)
ggplot(dd,aes(x=x.pos1,y=value.y,fill=Date)) +
geom_bar(aes(width=value.x),stat="identity",position="stack") + 
scale_x_continuous(breaks=tmp,labels=levels(dd$variable)) + 
coord_flip()

enter image description here

For good measure you're probably going to want to adjust the text size. That's done with ... + opts(axis.text.y=theme_text(size=12))

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255