Reputation: 41
I am plotting a bar chart using ggplot that has two values associated with each name, one value is positive and the other negative. I would like like to order the bars in the chart by the positive value in descending order, rather than by alphabetical order of the name.
If there is a general manual override for the ordering of names, I would also be interested in this to.
I have already explored other ggplot threads online that order the bars in descending order when you only have one variable and I understand how to do this. However, when I try to do it when there are two variables for the then I have this issue.
Here is an analogous example of my data and the plot function I have written:
example_data <- data.frame(NAME = rep(c('C', 'D', 'A', 'E', 'B'),2),
Variable = c(rep('S', 5), rep('L', 5)),
Values = c(-39,-21,-19,-11,-9,30,16,13,7,6))
ggplot(data = example_data,
aes(x = NAME, y = Values, fill = Variable)) +
geom_bar(stat = "identity", alpha=1) +
geom_text(aes(label=round(Values,1))) +
ylab("Unit of measurement") +
scale_fill_manual(values=c('#AED6F1','#F5B7B1'))
I thought of trying something like the following, but it doesn't produce the expected outcome:
ggplot(data = example_data,
aes(x = reorder(NAME, Values), y = Values, fill = Variable)) +
geom_bar(stat = "identity", alpha=1) +
geom_text(aes(label=round(Values,1))) +
ylab("Unit of measurement") +
scale_fill_manual(values=c('#AED6F1','#F5B7B1'))
I expected the outcome to order the bars as [C, D, A, E, B], but the order of the Names in the first output is [A, B, C, D, E] and in the second output is [C, A, D, E, B].
Upvotes: 2
Views: 900
Reputation: 29085
You can sort your data frame's rows in descending order based on the Values column, then reorder NAME by first appearance using fct_inorder
from the forcats
package.
library(dplyr)
example_data %>%
arrange(desc(Values)) %>%
mutate(NAME = forcats::fct_inorder(NAME)) %>%
ggplot(aes(NAME, Values, fill = Variable)) +
geom_col() + # identical to geom_bar(stat = "identity"), with less typing
geom_text(aes(label = Values)) +
ylab("Unit of measurement") +
scale_fill_manual(values=c('#AED6F1', '#F5B7B1'))
This is a relatively simple case, but the same approach will work even if you had complex ordering logic that involves sorting by multiple variables.
Upvotes: 2