6

I want a plot like this except that each facet sums to 100%. Right now group M is 0.05+0.25=0.30 instead of 0.20+0.80=1.00.

df <- rbind(
    data.frame(gender=c(rep('M',5)), outcome=c(rep('1',4),'0')),
    data.frame(gender=c(rep('F',10)), outcome=c(rep('1',7),rep('0',3)))
)

df

ggplot(df, aes(outcome)) +
    geom_bar(aes(y = (..count..)/sum(..count..))) +
    facet_wrap(~gender, nrow=2, ncol=1) 

(Using y = ..density.. gives worse results.)

Andrew
  • 1,619
  • 3
  • 19
  • 24
  • The answers provided here are the correct method. The ..density.. method provided in many other answers, http://stackoverflow.com/questions/10064080/plot-relative-frequencies-with-dodged-bar-plots-in-ggplot2, http://stackoverflow.com/questions/17368223/ggplot2-multi-group-histogram-with-in-group-proportions-rather-than-frequency, http://stackoverflow.com/questions/3695497/ggplot-showing-instead-of-counts-in-charts-of-categorical-variables yields values that are incorrect to varying degrees. – russellpierce Jul 15 '13 at 13:18

2 Answers2

17

here's another way

ggplot(df, aes(outcome)) +
    geom_bar(aes(y = ..count.. / sapply(PANEL, FUN=function(x) sum(count[PANEL == x])))) +
    facet_wrap(~gender, nrow=2, ncol=1) 
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
  • 1
    I like how this is short, but when I try to switch from facet to position=dodge, the heights sum to 100% over all groups (instead of within groups) – Andrew Jun 05 '12 at 16:27
  • 1
    Any way to extend this to a plot that's both faceted and split into groups within panels? – RoyalTS Mar 05 '14 at 15:30
  • @Matthew Plourde: excellent answer. Do you mind explaining the use of `..count..` in your answer? Is it simply a value within the plot's namespace? – Jubbles Jul 03 '14 at 17:57
9

I usually do this by simply precalculating the values outside of ggplot2 and using stat = "identity":

df1 <- melt(ddply(df,.(gender),function(x){prop.table(table(x$outcome))}),id.vars = 1)

ggplot(df1, aes(x = variable,y = value)) +
    facet_wrap(~gender, nrow=2, ncol=1) +
    geom_bar(stat = "identity")
joran
  • 169,992
  • 32
  • 429
  • 468
  • 1
    This is correct. I am hoping for a simpler answer for what seems like a relatively common kind of chart. :) – Andrew Jun 04 '12 at 21:12
  • @andrew - I do this *alot*. It is relatively easy to make your own `geom`, and this would be a great addition to the built in tools for ggplot2. – Chase Jun 04 '12 at 21:37
  • @Chase I could be wrong, but I think it would take more than a new geom because (I think) aesthetics are mapped to variables _before_ the faceting is done. So I think this might be a design feature way upstream of the geom. – joran Jun 04 '12 at 22:04