3

My data (reproduced below) contain three variables, Tools (categorical variable), Proficiency (value column) and Category (grouping column). I would like to sort the columns based on descending order of Proficiency value, while maintaining separation of Category groups, and without using facet_grid or facet_wrap (because I am using coord_flip). Reproducible data is below. To sort by Category, I specify the levels of Tools based on the Category factor.

library(tidyverse)

df1 <- structure(list(Tools = structure(c(1L, 8L, 9L, 5L, 6L, 10L, 2L, 
3L, 4L, 7L), .Label = c("Tool1", "Tool7", "Tool8", "Tool9", "Tool4", 
"Tool5", "Tool10", "Tool2", "Tool3", "Tool6"), class = "factor"), 
    Proficiency = c(3, 2, 5, 4, 3, 3, 3, 2, 2, 2), Category = structure(c(1L, 
    3L, 3L, 2L, 2L, 3L, 1L, 1L, 1L, 2L), .Label = c("Category1", 
    "Category2", "Category3"), class = "factor")), row.names = c(NA, 
-10L), class = "data.frame")

df1$Tools <- factor(df1$Tools, levels = df1$Tools[order(df1$Category)])

ggplot(data = df1, aes(x = Tools, y = Proficiency, fill = Category)) +
  geom_col() + 
  scale_x_discrete(limits = rev(levels(df1$Tools)))

This produces the below plot, which is obviously not grouped in descending order of Proficiency value.

first_image

One way to accomplish the desired grouping and sorting is by using facet_grid() and reordering Tools based on Proficiency within the aes call:

ggplot(data = df1, aes(x = reorder(Tools, -Proficiency), y = Proficiency, fill = Category)) + 
  geom_col() + 
  facet_grid(~ Category, scales = "free_x", space = "free_x")

image2

However, I would like to use coord_flip for this plot. Unfortunately, coord_flip does not seem to work well with facet_grid (github issues one, two) .

Predictably, sorting by Proficiency without using facet_grid causes the plot to override the Category groups.

image3

My desired output is the above image, where the Tools are sorted firstly by Category, and secondarily by Proficiency. Any help is much appreciated.

This answer looked promising, but applying a similar approach here didn't work for me; the below manipulation just set up the plot for ordering via Proficiency:

df1$Tools <- with(df1, factor(Tools, levels=Tools[order(ave(Proficiency, Category, FUN=min),Proficiency)]))`
heds1
  • 3,203
  • 2
  • 17
  • 32
  • Possible duplicate https://stackoverflow.com/questions/5208679/order-bars-in-ggplot2-bar-graph ? – Ronak Shah Jul 03 '19 at 01:41
  • @RonakShah that question relates to ordering by just one variable, whereas I'm looking to order based on two variables. – heds1 Jul 03 '19 at 01:43

2 Answers2

5

One way is to arrange your dataframe into the desired order and set the factor levels of Tools with that order.

library(dplyr)
library(ggplot2)

df1 %>%
  arrange(desc(Category), desc(Proficiency)) %>%
  mutate(Tools = factor(Tools, levels = Tools)) %>%
  ggplot(aes(x = Tools, y = Proficiency, fill = Category)) + 
  geom_col() + 
  coord_flip() 

enter image description here

Ritchie Sacramento
  • 29,890
  • 4
  • 48
  • 56
0

Use function fct_infreq( )


ggplot(df2, aes(fct_infreq(x),y))+
 geom_col()
ThomasPepperz
  • 176
  • 11