Search code examples
rggplot2

Creating two continuous color gradient scales for the same variable in ggplot2


I have a dataframe containing two variables Type and Time, and I am attempting to visualize the values from the Value column using geom_tile. The tiles are currently colored according to a continuous color gradient, ranging from red (indicating high values) to white (indicating low values). However, I would like to apply separate color gradients for the Type variable based on the Category it belongs to. Specifically, I want to use a navy-to-white gradient (with navy indicating high values) for the BB category and a red-to-white gradient (with red indicating high values) for the SS category.

Here's what I have tried so far:

library(ggplot)


df <- data.frame(Type = c(rep("A", 5), rep("B", 5), rep("C", 5)),
                 Time = rep(1:5, 3),
                 Value = round(runif(15, min = -3, max = 3), 2),
                 Category = c(rep("BB", 5), rep("SS", 10)))


ggplot(data = df, 
   aes(x = Time, 
       y = Type, 
       fill = Value)) + 
geom_tile(height = 0.8, 
            width = 1) +
  scale_fill_gradient2(limits = c(-3, 3), 
                       breaks = c(-3, 0, 3),
                       low = "white",
                       mid = "mistyrose",
                       high = "#A63446",
                       midpoint = 0,
                       guide = guide_colorbar(frame.colour = "black", 
                                              ticks.colour = "black")) +
  theme_bw()

enter image description here


Solution

  • You can achieve your desired result easily using the ggnewscale package which allows for multiple scales for the same aesthetic:

    library(ggplot2)
    library(ggnewscale)
    
    ggplot(
      data = df,
      aes(
        x = Time,
        y = Type,
        fill = Value
      )
    ) +
      geom_tile(
        data = ~subset(.x, Category == "SS"),
        height = 0.8,
        width = 1
      ) +
      scale_fill_gradient2(
        limits = c(-3, 3),
        breaks = c(-3, 0, 3),
        low = "white",
        mid = "mistyrose",
        high = "#A63446",
        midpoint = 0,
        guide = guide_colorbar(
          frame.colour = "black",
          ticks.colour = "black"
        ),
        name = "SS"
      ) +
      ggnewscale::new_scale_fill() +
      geom_tile(
        data = ~subset(.x, Category == "BB"),
        aes(
          x = Time,
          y = Type,
          fill = Value
        ),
        height = 0.8,
        width = 1
      ) +
      scale_fill_gradient(
        limits = c(-3, 3),
        breaks = c(-3, 0, 3),
        low = "white",
        high = "navy",
        guide = guide_colorbar(
          frame.colour = "black",
          ticks.colour = "black"
        ),
        name = "BB"
      ) +
      theme_bw() +
      theme(
        legend.box = "horizontal"
      )
    

    enter image description here