Search code examples
rggplot2geom-bar

Reorder geom_bar plot with two categories by the numerical value of just one of those categories


I realize that the title of this question can be a bit confusing, what what I am trying to resolve is the following. Assume I have the following data frame:

total_cash_and_card <- data.frame(amount_type=as.character(c('cash', 'cash', 'cash', 'cash', 'cash', 'cash', 'card', 'card', 'card', 'card', 'card', 'card')),
                                user_id=as.character(c('Blah_1', 'Blah_17', 'abcd1', 'user27', 'foobar', 'scrum', 'abcd1', 'foobar', 'Blah_1', 'Blah_17', 'user27', 'scrum')), 
                                total=as.numeric(c(47,21,17,9,2,1,55,45,32,12,10,3)), 
                                stringsAsFactors=FALSE)

And I produce the following plot (using the following code):

g = ggplot(data=total_cash_and_card, aes(x = user_id, y = total, fill=amount_type)) +
  geom_bar(colour="black", stat="identity",
           position=position_dodge(),
           size=.3) +
  labs(x="", y="Amount", caption="(based on sample data)", title='Cash Amount vs Card Amount') +
  theme_few(base_size = 10) + 
  scale_color_few() +
  theme(axis.text.x=element_text(angle = 45, hjust = 1))
  #theme(
    #axis.text.y = element_blank())
    #axis.ticks.y = element_blank())

p = ggplotly(g)
p = layout(p, margin = m, showlegend = TRUE)
p

myplot

How could I reorder my plot so that the x-axis(aka user_id) is ordered from left to right based on the 'total' when it belongs to the 'card' category (indicated by the amount_type column)? (i.e. how do I reorder my plot so that the reddish bars go from greatest to least, moving from left to right?). Hope that my question is clear enough, and thanks in advance for the help!


Solution

  • I removed the theme_few and ggplotly which require additional packages (as per eipi10's comment). What you need to do in this case is determine the order that you want user_id in and then use factor to apply that order.

    library(tidyverse) #for dplyr and ggplot2
    
    order <- total_cash_and_card %>% 
      filter(amount_type == "card") %>% 
      pull(user_id)
    
    ggplot(data=total_cash_and_card, aes(x = factor(user_id, order), y = total, fill=amount_type)) +
      geom_col(colour="black", position=position_dodge(), size=.3) +
      labs(x="", y="Amount", caption="(based on sample data)", title='Cash Amount vs Card Amount')
    

    enter image description here