Setting Midpoint for continuous diverging color scale on a heatmap

我只是一个虾纸丫 提交于 2020-01-21 19:15:11

问题


I need to adjust the midpoint location for a heatmap via ggplot2. I've googled around and have seen scale_fill_gradient2 be a great fit but the colors don't seem to match up to what I'm looking for. I know z needs a range from 0 to 1. Example dataset generation below:

library(ggplot2)
library(tibble)
library(RColorBrewer)

set.seed(5)
df <- as_tibble(expand.grid(x = -5:5, y = 0:5, z = NA))
df$z <- runif(length(df$z), min = 0, max = 1)

I tried plotting with the scale_fill_gradient2 but the blue color isn't coming as "dark" as I'd like.

ggplot(df, aes(x = x, y = y)) + 
  geom_tile(aes(fill = z)) + 
  scale_fill_gradient2(
    low = 'red', mid = 'white', high = 'blue',
    midpoint = 0.7, guide = 'colourbar', aesthetics = 'fill'
  ) + 
  scale_x_continuous(expand = c(0, 0), breaks = unique(df$x)) + 
  scale_y_continuous(expand = c(0, 0), breaks = unique(df$y))

Therefore, I'm using scale_fill_distiller with the color palette 'RdBu' which comes out with the color scale I need but the ranges and the midpoints aren't right.

ggplot(df, aes(x = x, y = y)) + 
  geom_tile(aes(fill = z)) +
  scale_fill_distiller(palette = 'RdBu') + 
  scale_x_continuous(expand = c(0, 0), breaks = unique(df$x)) +
  scale_y_continuous(expand = c(0, 0), breaks = unique(df$y))

Is there a way to get the 2nd color scale but with the option to set midpoint range as the first?


回答1:


The color scales provided by the colorspace package will generally allow you much more fine-grained control. First, you can use the same colorscale but set the mid-point.

library(ggplot2)
library(tibble)
library(colorspace)

set.seed(5)
df <- as_tibble(expand.grid(x = -5:5, y = 0:5, z = NA))
df$z <- runif(length(df$z), min = 0, max = 1)

ggplot(df, aes(x = x, y = y)) + 
  geom_tile(aes(fill = z)) + 
  scale_fill_continuous_divergingx(palette = 'RdBu', mid = 0.7) + 
  scale_x_continuous(expand = c(0, 0), breaks = unique(df$x)) + 
  scale_y_continuous(expand = c(0, 0), breaks = unique(df$y))

However, as you see, this creates the same problem as before, because you'd have to be further away from the midpoint to get darker blues. Fortunately, the divergingx color scales allow you to manipulate either branch independently, and so we can create a scale that turns to dark blue much faster. You can play around with l3, p3, and p4 until you get the result you want.

ggplot(df, aes(x = x, y = y)) + 
  geom_tile(aes(fill = z)) + 
  scale_fill_continuous_divergingx(palette = 'RdBu', mid = 0.7, l3 = 0, p3 = .8, p4 = .6) + 
  scale_x_continuous(expand = c(0, 0), breaks = unique(df$x)) + 
  scale_y_continuous(expand = c(0, 0), breaks = unique(df$y))

Created on 2019-11-05 by the reprex package (v0.3.0)




回答2:


Claus' answer is great (and I'm a fan of his work), but I'd like to add that you can retain control within vanilla ggplot as well if you use the scale_fill_gradientn() function:

library(ggplot2)
library(tibble)

set.seed(5)
df <- as_tibble(expand.grid(x = -5:5, y = 0:5, z = NA))
df$z <- runif(length(df$z), min = 0, max = 1)

ggplot(df, aes(x = x, y = y)) + 
  geom_tile(aes(fill = z)) + 
  scale_fill_gradientn(
    colours = c("red", "white", "blue"),
    values = c(0, 0.7, 1)
  ) + 
  scale_x_continuous(expand = c(0, 0), breaks = unique(df$x)) + 
  scale_y_continuous(expand = c(0, 0), breaks = unique(df$y))

A notable downside is that you'd have to provide the values argument in rescaled space, so between 0-1. Consider if your fill values range from 0-10 instead and want the midpoint on 0.7, you'd have to provide values = c(0, 0.07, 1).



来源:https://stackoverflow.com/questions/58718527/setting-midpoint-for-continuous-diverging-color-scale-on-a-heatmap

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!