Reputation: 4487
I want to produce a reverse pyramid graph where the bar stacked on each other with different width.
1st, I have a stacked bar chart as below code sample
library(dplyr)
library(ggplot2)
sample <- data_frame(x=c(1, 1, 1, 1, 2, 2, 2, 2),
y=c(5,10,15, 20, 10, 5, 20, 10),
w=c(1, 2, 3, 4, 1, 2, 3, 4),
group=c("a", "b", "c", "d", "a", "b", "c", "d"))
ggplot() +
geom_bar(data=sample,
aes(x=x,y=y,group=group, fill=group),
stat="identity", position=position_stack())
Then I added the width to aes
so the one with lower w
value will be smaller while they still stacked on each other. However, the bars didn't stack with warnings.
ggplot() +
geom_bar(data=sample,
aes(x=x,y=y,group=group, fill=group, width=w/5),
stat="identity", position=position_stack())
Warning: Ignoring unknown aesthetics: width
Warning message:
position_stack requires non-overlapping x intervals
Any helps on make bar plot stacked or ideas on different plot type that can cover similar concepts would be highly appreciated. Thanks!
Upvotes: 3
Views: 1534
Reputation: 4378
A rather lengthy version with ribbons
library(dplyr)
library(ggplot2)
sample <- data_frame(x=c(1, 1, 1, 1, 2, 2, 2, 2),
y=c(5,10,15, 20, 10, 5, 20, 10),
w=c(1, 2, 3, 4, 1, 2, 3, 4),
group=c("a", "b", "c", "d", "a", "b", "c", "d"))
# make factors for non-numeic items
sample$x <- factor(sample$x)
sample$group <- factor(sample$group)
# calcualte cumulative sums
sample2 <- sample %>%
group_by(x) %>%
arrange(desc(group)) %>%
mutate(ycum=cumsum(y)) %>%
ungroup() %>%
select(x, group, ycum, w)
# Ffor each point, make another row lagged
sample2lead <- sample2 %>%
group_by(x) %>%
mutate(ycum = lag(ycum, default=0), w=lag(w, default=max(sample2$w))) %>%
ungroup() %>%
select(x, group, ycum, w)
# combine
combined <- bind_rows(sample2, sample2lead) %>%
arrange(x, ycum, desc(group))
# plot a ribbon forming trapezoids
ggplot() +
geom_ribbon(data=combined,
aes(x=ycum, ymin=-w/2, ymax=w/2, fill=group)) +
coord_flip() +
facet_grid(~x)
Upvotes: 4
Reputation: 1321
It's a bit of a hack.
I'll use geom_rect()
instead of real columns. As such I need to create data.frame()
with precalculated positions for rectangle boundaries.
df_plot <- sample %>%
arrange(desc(group)) %>% # Order so lowest 'groups' firtst
group_by(x) %>%
mutate(yc = cumsum(y), # Calculate position of "top" for every rectangle
yc2 = lag(yc, default = 0) ,# And position of "bottom"
w2 = w/5) # Small scale for width
# Plot itself
ggplot(df_plot) +
geom_rect(
aes(xmin = x - w2 / 2, xmax = x + w2 / 2,
ymin = yc, ymax = yc2,
group = group, fill=group))
Upvotes: 7