Reputation: 403
I want to build custom heatmap with color ranges based on multiple conditions.
I found a similar post that focuses on Heatmap with conditions. However, it does not address my question of having dedicated color scales for different conditions.
library(ggplot2)
library(reshape2)
tt <- data.frame(C1=c(0.4,.5,.5, 0, .8,.8),
C2=c(.5,.6,.7, 0.6, .7,.8),
C3=c(.8,.7,.9, 0, .8,.7),
C4=c(.8,.1,.6, 0.9, .5,.9),
C5=c(0.4,.6,.6, 0.5, .8,.8),
C6=c(0.8,.7,.5, 0.1, .8,.8),
C7=c(0.8,.6,.4, 0, .8,.8))
row.names(tt) <- paste("F", 1:6, sep='')
tt <- as.matrix(tt)
tt_melt <- melt(tt)
colnames(tt_melt) <- c('rows', 'columns', 'performance')
tt_melt$cut <- cut(tt_melt$performance,
breaks=c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0),
labels=as.character(c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)),
include.lowest=TRUE)
perf_cols <- c(colorRampPalette(c("red", "green"))( 9 ))
perf_text_cols <- c(rep("white", 9))
gg <- ggplot(data=tt_melt, aes(x=columns, y=rows, fill=cut))
gg <- gg + geom_tile()
gg <- gg + geom_text(aes(label=performance, color=cut))
gg <- gg + labs(title = '')
gg <- gg + coord_equal()
gg <- gg + scale_colour_manual(values = perf_text_cols)
gg <- gg + scale_fill_manual(values=perf_cols)
gg <- gg + theme_minimal(base_size = 12, base_family = "")
gg <- gg + theme(legend.position="none")
gg
The heatmap from the above code looks like this:
However, I want the heatmap to have multiple color gradients based on the given conditions.
For ex, the conditions are below:
If the values are < 0.4 -> Green
If the values are > 0.5 -> Red
Values that lie between 0.4 and 0.5 then -> Grey
These colors would be having their own gradient scale. Higher the value in a condition darker the shade of that color.
Upvotes: 2
Views: 1005
Reputation: 23797
If your aim is not a real color hue gradient but just to make the color "darker", you could add a layer of grey or even black tiles with changing alpha. This needs to be relative to your midpoint though. I think the approach with cuts is good, although I would suggest to make the cuts bigger.
In the end of the day, this is sort of reproducing a diverging color scale and I am not sure if user mindlessgreens solution is not much more straight forward - really depends on your use case, I guess.
## your data preparation until tt_melt
## the cut approach seems good to me, but make the cuts reasonable
tt_melt$cut <- cut(tt_melt$performance, breaks=c(-Inf, 0.4, 0.5, Inf))
## you will need to add an alpha relative to your midpoint
tt_melt$dist = abs(tt_melt$performance - .5)
ggplot(tt_melt, aes(x = columns, y = rows)) +
geom_tile(aes(fill = cut)) +
scale_fill_manual(values = c("Red", "grey", "green")) +
## now add a layer of grey values based on performance, I am using alpha in order to avoid new fill scale
## remove your neutral values
geom_tile(data = dplyr::filter(tt_melt, cut != "(0.4,0.5]"),
aes(alpha = dist), fill = "black") +
geom_text(aes(label = performance), color = "white") +
scale_alpha(range = c(.5,.1))
Upvotes: 1
Reputation: 12142
Maybe something like this could be an option, using a custom color palette.
pal <- c("#238b45",
"#74c476",
"#bae4b3",
"#edf8e9",
"#cccccc",
"#fee5d9",
"#fcae91",
"#fb6a4a",
"#cb181d")
ggplot(data=tt_melt, aes(x=columns, y=rows, fill=performance))+
geom_tile()+
geom_text(aes(label=performance))+
scale_fill_gradientn(colors=pal,breaks=c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0))+
labs(title = '')+
coord_equal()+
theme_minimal(base_size = 12)+
theme(legend.position="none")
Update: Random test data and fixed gradient scale limits.
By adding limits=c(0,1)
to gradient scale, the palette is fixed from 0 to 1 regardless of input data range. Makes images comparable.
library(dplyr)
library(tidyr)
pal <- c("#238b45",
"#74c476",
"#bae4b3",
"#edf8e9",
"#cccccc",
"#fee5d9",
"#fcae91",
"#fb6a4a",
"#cb181d")
breaks <- c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0)
# randomly generate data
m <- as.data.frame(matrix(sample(seq(0,1,0.01),36),nrow=6)) %>%
mutate(rows=factor(row_number())) %>%
tidyr::pivot_longer(-rows,names_to="columns",values_to="performance")
# limits used in gradient scale
ggplot(data=m, aes(x=columns, y=rows, fill=performance))+
geom_tile()+
geom_text(aes(label=performance))+
scale_fill_gradientn(colors=pal, breaks=breaks, limits=c(0,1))+
labs(title = 'Range 0:1')+
coord_equal()+
theme_minimal(base_size = 12)
Upvotes: 2