Rachel Ward
Rachel Ward

Reputation: 35

How to change order of overlaid bars with position = "identity" in ggplot2

I'm not very experienced in R and I've been having an issue with geom_col(position = "identity") that I cannot figure out.

Here is some obfuscated data that still shows my issue and the code for my graph.

#Dataframe
print(colorsshapes, n = 30)
# A tibble: 30 x 4
# Groups:   year, shape [15]
    year shape  color total
   <int> <chr>  <chr> <int>
 1  2015 circle Red     101
 2  2015 circle Blue   6960
 3  2015 star   Red     232
 4  2015 star   Blue   9436
 5  2015 square Red     218
 6  2015 square Blue   9417
 7  2016 circle Red     146
 8  2016 circle Blue   7041
 9  2016 star   Red     415
10  2016 star   Blue   9702
11  2016 square Red     381
12  2016 square Blue   9653
13  2017 circle Red     167
14  2017 circle Blue   6890
15  2017 star   Red     780
16  2017 star   Blue  10277
17  2017 square Red     754
18  2017 square Blue  10231
19  2018 circle Red     306
20  2018 circle Blue   7067
21  2018 star   Red    1066
22  2018 star   Blue  10255
23  2018 square Red    1058
24  2018 square Blue  10233
25  2019 circle Red     457
26  2019 circle Blue   6304
27  2019 star   Red    1886
28  2019 star   Blue  10082
29  2019 square Red    1870
30  2019 square Blue  10057

#Graph
basic_hist <- colorsshapes %>%
    ggplot(aes(x = shape, y = total, fill = color)) +
    geom_col(position = "identity", color = "black") +
    scale_x_discrete(name = "Shape", 
        breaks = c("star", "circle", "square"), 
        labels = c("Star", "Circle", "Square")) +
    scale_y_continuous(name = "Total", 
        limits = c(0,10500)) +
    scale_fill_manual (name = "Color", 
        breaks = c("Red", "Blue"), 
        labels = c("Red", "Blue"), 
        values = c("indianred1", "darkslategray3")) +
    facet_wrap(~year, nrow = 1) +
    geom_text (aes(x = shape, y = total, label = total), stat = "identity", 
        position = position_nudge(y = 200), show.legend = FALSE) +
    theme(axis.title = element_text(face = "bold", size = 12),
        axis.text.x = element_text(angle = 345, size = 12, hjust = 0, vjust = 1),
        axis.title.x = element_text(margin = margin(t = 10, r = 2, b = 1, l = 2)),
        legend.title = element_text(face = "bold", size = 12),
        legend.text = element_text(size = 10),
        panel.spacing = unit(0.5, "cm"), 
        strip.text = element_text(size = 12, face = "bold"))

R plots the taller bar first, making the smaller bar unseen. I'd rather not adjust the alpha levels because the legend won't perfectly match the color of the lighter bars. My supervisor also would prefer contrasting colors, which makes adjusting the alpha a little less aesthetically pleasing.

I've tried converting the fill variable to a factor and manually setting the labels. No luck. I've tried reordering the levels in the scale_fill_manual() call. No luck. I've tried variations of arrange() and sort() in the graph code. No luck. Any ideas?

Much appreciated!

Upvotes: 0

Views: 718

Answers (1)

stefan
stefan

Reputation: 125373

This could be achieved by reordering the dataset such that smaller bars are plotted last and on top using e.g. dplyr::arrange(desc(total))

library(dplyr)
library(ggplot2)

colorsshapes %>%
  arrange(desc(total)) %>% 
  ggplot(aes(x = shape, y = total, fill = color)) +
  geom_col(position = "identity", color = "black") +
  scale_x_discrete(name = "Shape", 
                   breaks = c("star", "circle", "square"), 
                   labels = c("Star", "Circle", "Square")) +
  scale_y_continuous(name = "Total", 
                     limits = c(0,10500)) +
  scale_fill_manual (name = "Color", 
                     breaks = c("Red", "Blue"), 
                     labels = c("Red", "Blue"), 
                     values = c("indianred1", "darkslategray3")) +
  facet_wrap(~year, nrow = 1) +
  geom_text (aes(x = shape, y = total, label = total), stat = "identity", 
             position = position_nudge(y = 200), show.legend = FALSE) +
  theme(axis.title = element_text(face = "bold", size = 12),
        axis.text.x = element_text(angle = 345, size = 12, hjust = 0, vjust = 1),
        axis.title.x = element_text(margin = margin(t = 10, r = 2, b = 1, l = 2)),
        legend.title = element_text(face = "bold", size = 12),
        legend.text = element_text(size = 10),
        panel.spacing = unit(0.5, "cm"), 
        strip.text = element_text(size = 12, face = "bold"))

Created on 2020-11-30 by the reprex package (v0.3.0)

Upvotes: 2

Related Questions