简体   繁体   中英

ggplot make range of color scale a subset of the range of the data

I'm trying to modify the scale of a heatmap with geom_raster such that the color change occurs over a subset of the data and anything outside that subset doesn't get any more or less colorful.

library(tidyverse)
library(viridis)
library(reshape2)

q <- letters[1:5]
w <- rev(letters)[1:5]
x1 <- rnorm(5, 0, 1)
x2 <- rnorm(5, 0, 1)
x3 <- rnorm(5, 0, 1)
x4 <- rnorm(5, 0, 1)
x5 <- rnorm(5, 10, 1)

test.df <- melt(data.frame(q,w,x1,x2,x3,x4,x5))

ggplot(test.df, aes(q,variable,fill=value))+geom_raster()+scale_fill_viridis()

If you run that, you get this heatmap:

热图 .

The top row is "hogging" some of the color range. Since the vast majority of the data is between -2 and 2, I'd like to make it so that the color scale change occurs over that range, and anything outside of it is just yellow or purple. To me, anything over 2 should just be "very high" and anything under -2 should be "very low", but the numbers between -2 and 2 are what I want to see.

I don't think cut is what I want because then I need to supply a bunch of colors, and I don't want to remove any data or change any data over some value to some maximum or anything like that. Setting limits in the scale_viridis command helps but removes data outside the limits.

You can use a function such as dplyr::case_when to truncate the values at your endpoints. Then if you want, you can set labels on the legend accordingly. Note that I typed the labels manually in order to do "<= -2" and ">= 2" ; not sure if this would suffice, or if you may need something more dynamic.

library(tidyverse)
library(viridis)
library(reshape2)

set.seed(1234)
q <- letters[1:5]
w <- rev(letters)[1:5]
x1 <- rnorm(5, 0, 1)
x2 <- rnorm(5, 0, 1)
x3 <- rnorm(5, 0, 1)
x4 <- rnorm(5, 0, 1)
x5 <- rnorm(5, 10, 1)

test.df <- melt(data.frame(q,w,x1,x2,x3,x4,x5)) %>%
  mutate(val_trimmed = case_when(
    value > 2 ~ 2,
    value < -2 ~ -2,
    T ~ value
  )) 

ggplot(test.df, aes(x = q, y = variable, fill = val_trimmed)) +
  geom_raster() +
  scale_fill_viridis(labels = c("<= -2", "-1", "0", "1", ">= 2"), breaks = -2:2) +
  labs(caption = "Note: values truncated above 2 and below -2")

Created on 2018-08-13 by the reprex package (v0.2.0).

You can use scale_fill_gradientn to have full control on your color gradient. The code below will assign different colors across [-2, 2] but will keep the edge colors consistent beyond these values. Please try to set seed in your questions using set.seed for reproducibility.

ggplot(test.df, aes(q, variable, fill = value)) + 
  geom_raster() + 
  scale_fill_gradientn(
    colours = c("blue", "blue", "red", "red"),
    values = c(-999, -2, 2, 999)
  )

Simply increase the number of colors and values to extend your color gradient.

If the values only exceed the scale at one end (looks to be the case with your data, you have values greater than 2, but not less than -2) you can change values that exceed your maximum to NA in your dataframe and then use the na.value = option in scale_fill_viridis() to make all of the NA values a certain color.

#change values greater than 2 to NA
test.df$value <- ifelse(test.df$value <= 2, test.df$value, NA)

ggplot(test.df, aes(q, variable, fill = value)) +
  geom_raster() +
  scale_fill_viridis(na.value = "yellow", #make NAs (values > 2) yellow
                     limits = c(-2,2), #define limits of scale
                     labels = c(as.character(-2:1), ">= 2"), breaks = -2:2)

在此输入图像描述

This solution is less flexible than the other answers, as it won't work if you have values that exceed your range on the high and low end of the scale, but it's an easy, concise way to do this if you only have outliers on one end of the scale.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM