Как указать низкий и высокий уровень и получить две шкалы на двух концах, используя scale_fill_gradient

Мой вопрос заключается в том, что мне нужен расходящийся цвет для моей тепловой карты с использованием geom_tile, а цвет градиента варьируется на обоих концах шкалы. Например, вся шкала (-1,1), мне нужны только значения от -1 до -0,5, а значения от 0,5 до 1,0 имеют градиентный цвет, а значения от -0,5 до 0,5 остаются белыми. Однако я не могу найти вариант в scale_fill_gradient для достижения цели. Воспроизводимый пример приведен ниже, а данные взяты из тепловых карт ggplot2: использование разных градиентов для категории

nba <- read.csv("http://datasets.flowingdata.com/ppg2008.csv")
nba$Name <- with(nba, reorder(Name, PTS))

library("ggplot2")
library("plyr")
library("reshape2")
library("scales")

nba.m <- melt(nba)
nba.s <- ddply(nba.m, .(variable), transform,
               rescale = scale(value))

ggplot(nba.s, aes(variable, Name))+geom_tile(aes(fill = rescale), colour = "white") + 
scale_fill_gradient(low = "darkgreen", high = "darkred") 

person MYjx    schedule 15.10.2014    source источник


Ответы (1)


Вы можете попробовать добавить белую середину к scale_fill_gradient2:

gg <- ggplot(nba.s, aes(variable, Name))
gg <- gg + geom_tile(aes(fill = rescale), colour = "white")
gg <- gg + scale_fill_gradient2(low = "darkgreen", mid = "white", high = "darkred")
gg <- gg + labs(x="", y="")
gg <- gg + theme_bw()
gg <- gg + theme(panel.grid=element_blank(), panel.border=element_blank())
gg

введите здесь описание изображения

Но у вас будет наибольшая гибкость, если вы будете следовать ответу в сообщении SO, на которое вы ссылались, и использовать scale_fill_gradientn.

ИЗМЕНИТЬ (чтобы показать пример из обсуждения комментариев)

# change the "by" for more granular levels

green_seq <- seq(-5,-2.000001, by=0.1)
red_seq <- seq(2.00001, 5, by=0.1)

nba.s$cuts <- factor(as.numeric(cut(nba.s$rescale, 
                             c(green_seq, -2, 2, red_seq), include.lowest=TRUE)))

# find "white"
white_level <- as.numeric(as.character(unique(nba.s[nba.s$rescale >= -2 & nba.s$rescale <= 2,]$cuts)))
all_levels <- sort(as.numeric(as.character(unique(nba.s$cuts))))

num_green <- sum(all_levels < white_level)
num_red <- sum(all_levels > white_level)

greens <- colorRampPalette(c("#006837", "#a6d96a"))
reds <- colorRampPalette(c("#fdae61", "#a50026"))

gg <- ggplot(nba.s, aes(variable, Name))
gg <- gg + geom_tile(aes(fill = cuts), colour = "white")
gg <- gg + scale_fill_manual(values=c(greens(num_green),
                                      "white", 
                                      reds(num_red)))
gg <- gg + labs(x="", y="")
gg <- gg + theme_bw()
gg <- gg + theme(panel.grid=element_blank(), panel.border=element_blank())
gg <- gg + theme(legend.position="bottom")
gg

введите здесь описание изображения

Легенда далека от идеала, но потенциально вы можете исключить ее или обойти другими способами.

person hrbrmstr    schedule 15.10.2014
comment
Спасибо за ответ! Однако я хочу, чтобы все значения, в данном случае от -2 до 2, стали полностью белыми без эффекта градиента... - person MYjx; 15.10.2014
comment
если это и решение gradientn не работают, вам придется сделать свои собственные cut значений и вручную указать цвета градиента с помощью scale_fill_manual. - person hrbrmstr; 15.10.2014
comment
да, я пробовал scale_fill_manual, это сработало, но я не хочу указывать цвет каждый раз, так как у меня много данных каждый день. Вот почему я хочу использовать gradientn. Я пытался использовать breaks, но, похоже, он работает только для легенды, а не для самого цвета. - person MYjx; 15.10.2014
comment
Вы можете создать две функции цветовой шкалы - greens <- colorRampPalette(c("#006837", "#a6d96a")) и reds <- colorRampPalette(c("#fdae61", "#a50026")), затем сделать cut настолько детализированным, насколько хотите (сохраняя диапазон -2:2 нетронутым), вычислить количество уровней ниже и выше и пройти их в качестве параметров для этих двух генераторов палитр и очень программно построить ручную цветовую шкалу. - person hrbrmstr; 15.10.2014
comment
Спасибо! @hrbrmstr Сегодня у меня была возможность поговорить с Хэдли Викманом, и у него тоже не было простого решения. Я думаю, что на данный момент это лучший способ справиться с этим! :) - person MYjx; 17.10.2014