I need to plot a bar chart in R where the order of the bars is exactly like in the data_frame below, i.e. I need group 1 on the left, 2 in the middle and 3 on the right. But: I also need the bars to be arranged descending by score within the three groups and that I don't know how to do.
I already sorted the data_frame by 'group' and 'score' but ggplot only adopted the order of the 'group' variable:
data_scores <- data.frame(group = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
country = c("U", "D", "M", "D", "U", "M", "D", "M", "U"),
score = c(10, 7, 3, 15, 12, 4, 9, 7, 5))
ggplot(data_scores, mapping = aes(x = group, y = score, fill = country))
geom_bar(stat = "identity", position = position_dodge())
geom_text(aes(label = country),
position=position_dodge(width=0.9), angle = 90, hjust = 1)
This code orders the bars within each group by coutry but I need them arranged by score as it is the case in group 3.
Thank you very much in advance!
CodePudding user response:
One option would be to use a helper column made of the interaction of group
and country
. To this end I first order by group
and score
and use forcats::fct_inorder
to set the order of the levels of the helper column and map it on the group
aes:
library(ggplot2)
library(dplyr)
data_scores <- data_scores |>
arrange(group, desc(score)) |>
mutate(group_order = forcats::fct_inorder(interaction(group, country)))
ggplot(data_scores, mapping = aes(x = group, y = score, fill = country, group = group_order))
geom_col(position = position_dodge())
geom_text(aes(label = country),
position = position_dodge(width = 0.9), angle = 90, hjust = 1
)
CodePudding user response:
Well, you could generate bar, text geoms separately and sum them later. Not very pretty, but works:
reorder_group <- function(df, fn) {
df %>%
group_by(group) %>%
group_map(function(x, ...) {
x %>%
mutate(country = reorder(country, score, decreasing = TRUE)) %>%
fn()
}, .keep = TRUE)
}
g_col <-
data_scores %>%
reorder_group(function(df) geom_col(data = df, position = position_dodge()))
g_text <-
data_scores %>%
reorder_group(function(df) {
geom_text(
aes(label = country),
data = df,
position = position_dodge(width = 0.9), angle = 90, hjust = 1
)
})
g_main <- ggplot(data_scores, aes(x = group, y = score, fill = country))
reduce(c(g_col, g_text), ` `, .init = g_main)