Search code examples
rggplot2geom-bar

Reorder Overlaid Bars in Plot so Longer Bars are in back -R


I have a barplot that I want to overlay. The issue is that longer bars are covering shorter bars. There's a function in excel that allows for longer bars to be pushed to the back, and shorter bars brought to the forefront. How can I do that in R?

My code is below:

ggplot(df2) +geom_bar(aes(x = id, y = `Feb-20`), position = "identity",stat="identity", fill = 'green') +
  geom_bar(aes(x = id, y = `Mar-20`), position = "identity", stat="identity",fill = 'navy') +
  geom_bar(aes(x = id, y = `Apr-20`), position = "identity", stat="identity", fill = 'red') 

And produces this chart:

enter image description here

Now, I've seen some solutions to this issue by changing the transparency. Since I have three factors, changing the alpha hasn't been very clear:

enter image description here

How can I change the overlay ordering of the bars, so longer bars are in the back?


Solution

  • I would recommend you switch to geom_col if you are going to be plotting bars, but supplying x= and y= aesthetics. See here for the documentation explanation. With that being said, it will work either way. Basically:

    • Tidy Data: I cannot confirm, but it seems that your dataset df2 is not organized following Tidy Data Principles, which makes things much easier with ggplot2 and many other methods of data analysis. Instead of having your y values split among df2$Mar-20 and df2$Apr-20, you should have a column for the category (let's call it df2$date) and a column for the actual value df2$y. You would then have one call to geom_bar giving aes(x=id, y=y). You can do this via dplyr::gather() or melt from the reshape2 package.

    • Arrange Data: Outside of any other influence (such as ordering of the levels of a factor), the plotting function in ggplot2 will plot data according to the arrangement of the actual dataframe for the x= and y= aesthetic. This means if you order the data beforehand on a particular, non-factor value, this will dictate the order in which ggplot2 will plot. So, you should order the plot based on descending df2$y prior to plotting to have the largest bars plotted first and smallest last, which means the smallest will be in front.

    Here's a complete example with dummy data:

    library(ggplot2)
    library(dplyr)
    
    set.seed(1234)
    df <- data.frame(
      x=rep(LETTERS[1:10],3),
      y=sample(1:100,30,replace=TRUE),
      id=c(rep('Group1',10),rep('Group2',10),rep('Group3',10))
    )
    
    df %>%
    arrange(-y) %>%
    ggplot(aes(x,y)) + theme_bw() +
      geom_bar(aes(fill=id),stat='identity',position=position_identity())
    

    enter image description here

    Try that ggplot() function without the arrange() function and you'll see the effect is what you're looking to do.