This is a test version of Biostars. For the public version, visit https://www.biostars.org.
R Heatmaps: Non-Linear Mapping Between Colors And Values

I am thankful for How Do I Draw A Heatmap In R With Both A Color Key And Multiple Color Side Bars? in R where you can add row and column information together with the color mapping information. I use it all the time to make pictures of hierarchically clustered expression profiles measured by expression arrays.

Usually I scale the input matrix on rows (probesets) to Z-scores in order to make weigh equally in the clustering. The colors of the heatmap are mapped linearly to the Z-scores. \

The problem is, when you have a few extremes in your data set, they tend to make your heatmap a little faint. In the attached heatmap you can see that the Z-scores range from somewhere around -10 to 10, however, about 99% is in the range of -4 to 4. I would like to change the way colors are mapped to the Z-scores in such a way that the green-to-red goes from -4 to 4 and the colors of the Z-scores outside this range just do not become any more green or red then they are already, any ideas?

# import gplots for greenred colors
library(gplots)
# generate random matrix
x<-replicate(100,rnorm(100,0,1))
# draw heatmap
heatmap.3(x,density.info="histogram",col=greenred)
# introduce outliers
x[1,1] <- -10
x[2,2] <- 10
# draw heatmap with outliers
heatmap.3(x,density.info="histogram",col=greenred)

Without extremes With extremes

heatmap r

3 answers

You can use the breaks argument to do this, from the heatmap.2 documentation:

breaks (optional) Either a numeric vector indicating the splitting points for binning x into colors, or a integer number of break points to be used, in which case the break points will be spaced equally between min(x) and max(x)

To use to achieve your desired effect:

#breaks for the core of the distribution
breaks=seq(-4, 4, by=0.2) #41 values
#now add outliers
breaks=append(breaks, 10)
breaks=append(breaks, -10, 0)
#create colour panel with length(breaks)-1 colours
mycol <- colorpanel(n=length(breaks)-1,low="green",mid="black",high="red")
#now plot heatmap - I'm using heatmap.2, but am assuming this will work with Obi's heatmap.3
heatmap.2(x,density.info="histogram",col=mycol, trace='none', breaks=breaks)

The major drawback is that the outliers are a lot less obvious, but clearly the heatmap overall is a lot less 'washed out'.

Results:

Before enter image description here

After enter image description here

Thanks, thats it!

It's like a learning time machine. 16 months on and this is exactly what I needed. Thanks!

you could simply change your matrix by changing all value over 4 to 4 and all value under -4 to -4

Or write a little function

plotHeatmap <- function(M,up=4,down=-4){
   M[M>up]<- up
   M[M<(-down)]<- down
   print(heatmap.3(M,density.info="histogram",col=greenred))     
}

I tried that with my real data but then what happens is that the resulting clustering does not correspond to the biological situation any more. The values should remain the same, they reflect the expression profiles found in the samples.

You can also apply a logarithmic scaling onto the values, this will greatly compress the range.

Hmm, I can try that but I am afraid changing the values in the matrix before doing the clustering will change the clustering in a way I don´t want from the biological point of view...

Log in to answer this question.