I am attempting to create a diverging stacked bar like here, and am experiencing a similar issue to this SO question. My approach is slightly different though as I am managing i
You can use position_stack(reverse=TRUE)
:
ggplot(x, aes(x = 1, y = count, fill = response)) +
geom_col(position = position_stack(reverse=TRUE)) +
scale_fill_brewer(palette = "RdBu") +
coord_flip()
A tough one! I played with ordering and it seems that geom_bar
and geom_col
don't like it when you combine positive and negative values in the common same order. So I divided your data inside the dataframe for positive and negative values, generated colors for every response value and used two geoms for positive and negative values separately:
library(tidyverse)
library(RColorBrewer)
x <- tribble(
~response, ~count,
0, -27,
1, -9,
2, -41,
3, -43,
4, -58,
5, -120,
5, 120,
6, 233,
7, 379,
8, 388,
9, 145,
10, 61
) %>%
# Get absolute values and add dummy to distuingish positive and negative values
mutate(subzero = count < 0,
count = abs(count))
# Generate variable with colors from ColorBrewer for every response level (ugly but works)
colors <- brewer.pal(length(unique(x$response)),"RdBu")
x$colors <- NA
for (i in 1:nrow(x)){
x$colors[i] <- colors[x$response[i]+1]
}
ggplot() +
geom_bar(data = x[x$subzero==T,], aes(x = "", y = -count, fill = reorder(colors, response)), position="stack", stat="identity") +
geom_bar(data = x[x$subzero==F,], aes(x = "", y = count, fill = reorder(colors, -response)), position="stack", stat="identity") +
geom_hline(yintercept = 0, color =c("black")) +
scale_fill_identity("Response", labels = unique(x$response), breaks=unique(x$colors), guide="legend") +
coord_flip() +
labs(y="",x="") +
theme(legend.position = "bottom", legend.direction = "horizontal") +
scale_y_continuous(breaks=seq(-1400,1400,200), limits=c(-1400,1400))
UPD: made Y-scale balanced so it look more clear
Although not intuitive (for me), use:
ggplot(x, aes(x = 1, y = order(count), fill = response)) +
geom_col() +
scale_fill_brewer(palette = "RdBu",direction=1) +
coord_flip()
It takes into account the ordering based on response (rather than order(response))