Search code examples
rggplot2plotdplyrforcats

Reorder variables in ggplot2 by more than one level using fct_relevel() from forcats package


I need to make a graph (using ggplot2) that organizes bars by the value of different categories. If you see below, I was able to sort by my first level ("Very Important"), but I have not been able to get the second level ("Important) to get organized correctly - example: 'Passion for farming' should end up above 'Cultivating a healthy workplace'.

library(ggplot2)
library(dplyr)
library(forcats)
library(reshape)

data<- data.frame(Category=c("Open attitude","Flexible","Interest in learning","Passion for farming",
                           "Dependable business networks","Community ties", "Reliable crew",
                           "Family support", "Responsive government", "Protect natural resources and biodiversity",
                           "Build healthy soil", "Diversify farm products", "Minimize external inputs",
                           "Water-use efficiency", "Effective planning and monitoring", "Cultivating a healthy workplace",
                           "Diversifying markets and venues", "Focusing on recurrent customers",
                           "Appropriate equipment and infrastructure", "Financial leeway and capacity"),
                     Very.important=c(78.57,85.71,85.71,92.86,100.00,85.71,78.57,64.29,50.00,57.14,
                                      100.00,64.29,57.14,57.14,78.57,92.86,71.43,71.43,64.29,71.43),
                  Important=c(21.43,14.29,14.29,7.14,0.00,14.29,21.43,35.71,21.43,35.71,
                              0.00,35.71,28.57,35.71,21.43,0.00,14.29,7.14,28.57,21.43),
                  Slightly.important=c(0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,28.57,7.14,
                  0.00,0.00,14.29,7.14,0.00,7.14,14.29,21.43,7.14,7.14),
                  Not.important=c(0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,
                                  0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00))
data 
alldata <- melt(data)

First, to organize the variables in a new data.frame, I am using fct_relevel() from forcats package. However, even though I am adding 'Important' as a second level in the arrange function, it is not being recognized. The graph turns out the same as if I only include 'Very Important' in the function.

alldata1 = alldata %>%
  ungroup() %>%
  arrange(fct_relevel(variable, "Very.important"), value) %>%
  mutate(Category= fct_inorder(Category))

I am including my code for the graph for your reference.

mycolors <- c('#0570b0','#74a9cf','#bdc9e1','#f1eef6')

ALLres <- ggplot(data = alldata1, aes(x =Category, y = value, fill = variable)) +
  labs(y="Percentage", x = "") +
  geom_col(width = 0.7, position = position_stack(reverse = T)) +
  coord_flip() +
  theme_bw() +
  theme(text = element_text(size = rel(3), colour = "black"), # x-label
        axis.text.y = element_text(size = rel(3.5), colour = "black"),
        axis.text.x = element_text(size = rel(3), colour = "black")) +
  theme(legend.text = element_text(size = rel(3))) + #legend size
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
  theme(legend.position="bottom") +
  scale_fill_manual (values=mycolors,  
                     name = "Response",
                     labels = c("Very Important", "Important",
                                "Slightly Important", "Not Important"))
ALLres

Thank you in advance!


Solution

  • You can arrange the data first on Very.important and then Important and assign the factor levels of Category column.

    library(tidyverse)
    
    mycolors <- rev(c('#0570b0','#74a9cf','#bdc9e1','#f1eef6'))
    
    data %>%
      arrange(Very.important, Important) %>%
      mutate(Category = factor(Category, Category)) %>%
      pivot_longer(cols = -Category) %>%
      ggplot(aes(x=Category, y = value, fill = name)) +
      labs(y="Percentage", x = "") +
      geom_col(width = 0.7) +
      coord_flip() +
      theme_bw() +
      theme(text = element_text(size = rel(3), colour = "black"), # x-label
            axis.text.y = element_text(size = rel(3.5), colour = "black"),
            axis.text.x = element_text(size = rel(3), colour = "black")) +
      theme(legend.text = element_text(size = rel(3))) + #legend size
      theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
      theme(legend.position="bottom") + 
      scale_fill_manual (values=mycolors,  
                         name = "Response")
    

    enter image description here