Order of the labels in geom_col wrong, although the factor levels are set correctly

Viewed 27

I am trying to make a likert/diverging barplot in ggplot2. Although I set the order of the levels using the factor levels, the order in the barplot is not correct (I use geom_col), in the legend the order is correct.

Can someone help me? Thanks

Reporducible expample:

library(data.table)
library(ggplot2)

data = data.table::data.table(code = paste0("A", c(1,2,4,5)), 
         label = c("Very good", "Good", "Not good", "Bad"),
         pct = c(9.6, 66, -22.7, -1.7),
         group = 1)
data$label <- factor(data$label, levels = unique(data[order(code)]$label))

ggplot(data, aes(x = group, y = pct, group = label, fill = label)) +
  geom_col(width = 0.8, position = position_stack()) +
  coord_flip() 

In the plot the level "bad" comes before "not good", as supposed to the other way around.

1 Answers

The plot is technically correct. Negative values stacked 'on top' of other negative values stack to the left. The easiest way round this is simply to re-level your factors appropriately to account for this. You would then need to specify the limits inside scale_fill_* to rearrange the legend appropriately.

Note that you don't need coord_flip now, since geom_col has an orientation argument. This allows for nicer scaling of your bars so that they look more like actual bars:

data$label <- factor(data$label, c('Very good', 'Good', 'Bad', 'Not good'))

ggplot(data, aes(y = group, x = pct, group = label, fill = label)) +
  geom_col(position = position_stack(), col = 'gray50', orientation = 'y') +
  geom_vline(xintercept = 0, linetype = 2) +
  coord_fixed(20) +
  labs(x = 'Percent', y = 'Group') +
  scale_fill_brewer(limits =  c('Very good', 'Good', 'Not good', 'Bad')) +
  theme_minimal(base_size = 16)

enter image description here

If this feels wrong to you, then you can do it all in ggplot, since one alternative is to plot all the values as positive values, then fake the axis.

ggplot(data, aes(y = factor(group), x = abs(pct), group = label, fill = label)) +
  geom_col(position = position_stack(), col = 'gray50', orientation = 'y') +
  scale_x_continuous(labels = ~.x + sum(data$pct[data$pct < 0]),
                     breaks = 0:5 * 25 - 25 - sum(data$pct[data$pct < 0])) +
  geom_vline(xintercept = -sum(data$pct[data$pct < 0]), linetype = 2) +
  coord_fixed(20) +
  labs(x = 'Percent', y = 'Group') +
  scale_fill_brewer() +
  theme_minimal(base_size = 16)

enter image description here

Related