Search code examples
rggplot2plotdata.table

Reorder entire data.table based on a subset of values


I am trying to plot some categorical data and I'd like the data to be ordered by a numeric value. I can reorder the data.table using the reorder base function, but I cannot figure out how to reorder the entire list based on only on a subset of the data.

dt <- data.table(Model = c(rep("M1", 4), rep("M2", 4)), 
           Var = rep(c("First", "Second", "Third", "Fourth"), 2),
           Value = c(1,3,4,5, 6,7,2,8))

ggplot(dt, aes(x = Model, y = Var)) +
  geom_tile(aes(fill = Value)) # Without reorder data are plotted alphabetically

dt[, Var := reorder(Var, Value, decreasing = TRUE)]

ggplot(dt, aes(x = Model, y = Var)) +
  geom_tile(aes(fill = Value))
# Reorder based on all Vars, but I want to reorder WITHIN M1

enter image description here

What I am trying to do is base the reorder only on M1. In this case, that should reorder the Vars to "First, Second, Third, Fourth".

Is there a way to accomplish this that doesn't involve creating a dummy column where M1's Vars are repeated for M2?

Various subset attempts I've tried that did not work:

dt[Model = "M1", Var := reorder(Var, Value, decreasing = TRUE), by = "M1"]
dt[, Var := reorder(Var, Value, decreasing = TRUE), by = "M1"]
setorder(dt, Value) # Does not reorder at all 

Solution

  • One option would be to use e.g. an ifelse to set non-M1 values to NA and use na.rm=TRUE:

    library(data.table)
    library(ggplot2)
    
    dt[, Var := reorder(Var,
      ifelse(Model == "M1", Value, NA),
      na.rm = TRUE, 
      decreasing = TRUE
    )]
    
    ggplot(dt, aes(x = Model, y = Var)) +
      geom_tile(aes(fill = Value))