I'm trying to plot a geom_bar with the stack order depending on the cumulative value of each group in each bar. therefore, each bar should have a different order. Here is a reproducible example
set.seed(8)
#create dataframe
name <- c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z", "aa")
group <- c("1","1","1","2","2", "2", "1","1","1","1","1","1","1","1","1","1","1","1","2","2","2","2","2","2","2","2")
subgroup <- c("C", "C", "C", "C", "C", "C", "A", "A", "A","A","A","A","B","B","B","B","B","B","B","B", "C", "C", "C", "C", "C", "C")
value <- runif(26, min = 0, max = 10)
df <- data.frame(name, group, subgroup,value)
#plot
ggplot(data=df, aes(x=group, y=value))
geom_bar(stat="identity",aes(fill=reorder(subgroup, value)))
The latter results in the following plot:
Note that it is clear that the B subgroup represents a higher value than C in group 1, but it is plotted above C. I want that, for each group, the subgroups are ordered based on their cumulative value in the group. Does anybody know how to achieve this? Thanks in advance!
CodePudding user response:
You could do this by precalculating the counts and using geom_tile
instead of geom_bar
. This way will work automatically with any number of groups and subgroups without manual intervention.
library(dplyr); library(ggplot2)
df %>%
count(group, subgroup, wt = value) %>%
group_by(group) %>%
arrange(group, -n) %>%
mutate(middle = cumsum(n) - n/2) %>%
ungroup() %>%
ggplot(aes(group, fill = subgroup))
geom_tile(aes(y = middle, height = n), width = 0.9)
CodePudding user response:
Try using a new column with the cumulative values and then use fct_reorder to order the stacks.
see example below:
df %>%
group_by(group,subgroup) %>%
mutate(csum = cumsum(value)) %>%
ggplot()
aes(x = group, y = csum)
geom_bar(stat = "identity", aes(fill = fct_reorder(subgroup, csum)))
CodePudding user response:
And another option would be to use the group
aes. To this end first aggregate your data and arrange your data by group and (cumulated) value as in the approach by @JonSpring. Afterwards you could add a helper column as the interaction of group
and subgroup
and set the order via forcats::fct_inorder
. This helper column could then be mapped on the group
aes to set the order of the stack:
library(dplyr)
library(ggplot2)
df1 <- df |>
count(group, subgroup, wt = value) |>
arrange(group, n) |>
mutate(group_aes = forcats::fct_inorder(paste(group, subgroup, sep = ".")))
# plot
ggplot(data = df1, aes(x = group, y = n, group = group_aes))
geom_col(aes(fill = subgroup))