1
votes

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].

1

1 Answers

1
votes

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'))

plot

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.