Simon
Simon

Reputation: 685

ggplot stacked bar chart (proportion) scaled to x variable

I need to create a stacked bar chart of the relative proportion, scaled to the x variable. Here's what I mean.

With a dataframe something like this:

df <- data.frame(foo = rep(1:5,500), bar = as.factor(c(rep("a",100), rep("b",100), rep("c",100), rep("d",100), rep("e",100))), baz = c(rep("R", 5*250), rep("CRAN", 5*250)), val = rbinom(5*500,1,0.1))

I need to create a plot that combines the following two plots. I need the shape of the second plot and the bar colour coding of the first plot (scaled to the second plot. Ideally I would also plot a density over it (like the first plot).

library(ggplot2)
ggplot(subset(df, val == 1), aes(x = foo)) + geom_bar(aes(fill = bar), position = "fill") + scale_fill_brewer(type = "div", palette = 8, direction = 1) +  facet_wrap(~baz) + geom_density(aes(foo))
ggplot(subset(df, val == 1), aes(x = foo, y = as.factor(foo))) + geom_col(position = "identity") + scale_fill_brewer(type = "div", palette = 8, direction = 1) +  facet_wrap(~baz)

The end result should be like the facet on the left (on the image below). Gimped up geom_bar

How do I do this in ggplot2?

Upvotes: 1

Views: 528

Answers (3)

Simon
Simon

Reputation: 685

This is the solution that I came up with:

df <- data.frame(foo = rep(1:5,500), bar = as.factor(c(rep("a",100), rep    ("b",100), rep("c",100), rep("d",100), rep("e",100))), baz = c(rep("R", 5*250), rep("CRAN", 5*250)), val = rbinom(5*500,1,0.1))

p <- ggplot(subset(df, val == 1), aes(x = foo)) + geom_bar(aes(fill = bar), position = "fill") + scale_fill_brewer(type = "div", palette = 8, direction = 1) +  facet_wrap(~baz)
p1 <- ggplot(subset(df, val == 1), aes(x = foo, y = as.factor(foo))) + geom_col(position = "identity") + scale_fill_brewer(type = "div", palette = 8, direction = 1) +  facet_wrap(~baz)

z <- ggplot_build(p)
z1 <-ggplot_build(p1)
z$data[[1]]$ymin <- z$data[[1]]$ymin*z$data[[1]]$x
z$data[[1]]$ymax <- z$data[[1]]$ymax*z$data[[1]]$x
z$data[[1]]$y <- z$data[[1]]$y*z$data[[1]]$x
z$layout$panel_ranges <- z1$layout$panel_ranges

plot(ggplot_gtable(z))

Here's what it looks like:

Just what I was aiming for

This works, but I'm open to other (less hacked together) solutions.

Upvotes: 0

pogibas
pogibas

Reputation: 28339

Maybe something like this would work: In geom_bar() added stat = "identity" and removed fill = "position". And you can replace density with histogram (which is basically the same density).

ggplot(subset(df, val == 1), aes(foo)) + 
    geom_bar(aes(y = foo, fill = bar), stat = "identity") + 
    geom_histogram(aes(foo), color = "black") +
    facet_wrap( ~ baz) +
    scale_fill_brewer(type = "div", palette = 8, direction = 1) +
    labs(x = NULL, y = NULL) +
    theme(legend.position = "bottom")

enter image description here

Upvotes: 1

kangaroo_cliff
kangaroo_cliff

Reputation: 6222

How about

 library(gridExtra)
 grid.arrange(p1, p2, ncol=1)

where p1 and p2 are the two ggplots.

p1 <- ggplot(subset(df, val == 1), aes(x = foo)) + geom_bar(aes(fill = bar), 
       position = "fill") + scale_fill_brewer(type = "div", palette = 8, 
       direction = 1) +  facet_wrap(~baz) + geom_density(aes(foo))

p2 <- ggplot(subset(df, val == 1), aes(x = foo, y = as.factor(foo))) + 
       geom_col(position = "identity") + scale_fill_brewer(type = "div", 
       palette = 8, direction = 1) +  facet_wrap(~baz)

Upvotes: 1

Related Questions