Search code examples
rsortingggplot2facet-grid

Different reorder in ggplot2's facet_grid inner elements with multiple repeated values


This might be a very particular case I've been trying to accomplish but nevertheless quite useful. I need to sort ggplot2's facet_grid inner elements with multiple repeated values based on another variable. Example with a given data.frame df (shown below). When using factor you can define a specific order for its levels, but in this case, there are different orders because it is based in a third value, and in the example, for var2 = TRUE's grid, A would be the first (ranked) element and for var2 = FALSE's grid, A should be the last.

df <- data.frame(var1 = c(TRUE, TRUE, FALSE, FALSE, FALSE),
                 var2 = c('C','A','A','Z','C'),
                 n = c(5,10,1,3,3))
ggplot(df, aes(reorder(var2,n), n)) + 
  geom_col() + facet_grid(var1~.) + coord_flip()

example ggplot2

I wish to sort both grids by the n variable and the result should be C,Z,A for the FALSE grid and A,C,Z for the TRUE grid. There should by like an ungroup() function for ggplot2's reorder...

BONUS: Even more complex, I have a tidyverse friendly function in the lares library for calculating and plotting frequencies (freqs). It uses the !!!variables lazy evaluation for each variable and sometimes these variables might be more than one. For instance, distr(df, var1, var2, var3) or simply distr(df, var1). That is why I can't (or at least I don't know how) dynamically convert these variables as sorted factors if that is the solution.

Is there a way to do this without the use of cowplot or gridExtra which makes different plots and then paste them all together? It is too slow...


Solution

  • Does this work for you? See more here

    library(tidyverse)
    
    df <- data.frame(var1 = c(TRUE, TRUE, FALSE, FALSE, FALSE),
                     var2 = c('C','A','A','Z','C'),
                     n = c(5,10,1,3,3))
    
    reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) {
      new_x <- paste(x, within, sep = sep)
      stats::reorder(new_x, by, FUN = fun)
    }
    
    scale_x_reordered <- function(..., sep = "___") {
      reg <- paste0(sep, ".+$")
      ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...)
    }
    
    ggplot(df, aes(reorder_within(var2, n, var1), n)) +
      geom_col() +
      scale_x_reordered() +
      facet_grid(var1 ~ ., scales = "free", space = "free") +
      coord_flip() +
      theme_minimal() +
      theme(panel.grid.major.y = element_blank()) 
    

    Created on 2019-03-08 by the reprex package (v0.2.1.9000)