The key here is understanding that heatmap.2
uses the col
argument in combination with the breaks
argument.
Take a look at the code and figure below to see what I mean.
library(gplots)
set.seed(100)
dat = matrix( rexp(25,1/2), ncol=5 )
breaks = 0:5
col = c("green","blue","red","yellow","brown")
heatmap.2( dat, breaks=breaks, col=col )
As you can see, there must be n-1
colors for n
breaks. For your particular question, the problem is to map the correct colors to the breaks. I'm using the scale="none"
option as @josilber pointed out.
breaks = seq(0,max(dat),length.out=1000)
gradient1 = colorpanel( sum( breaks[-1]<=1 ), "white", "green", "black" )
gradient2 = colorpanel( sum( breaks[-1]>1 ), "black", "red" )
hm.colors = c(gradient1,gradient2)
heatmap.2(as.matrix(dat),scale="none",breaks=breaks,col=hm.colors,
Colv=FALSE,dendrogram="row",trace="none",
margin=c(5,10), hclust=hclustfunc,distfun=distfunc,lwid=c(1.5,2.0))
Another alternative would be to have two gradients: green->black and black->red. Then, you could manually set the zero values to white by making them NA
and setting na.color="white"
.
breaks = seq(0,max(dat),length.out=1000)
gradient1 = colorpanel( sum( breaks[-1]<=1 ), "green", "black" )
gradient2 = colorpanel( sum( breaks[-1]>1 ), "black", "red" )
hm.colors = c(gradient1,gradient2)
dat[dat==0] = NA
heatmap.2(as.matrix(dat),scale="none",breaks=breaks,col=hm.colors,na.color="white",
Colv=FALSE,dendrogram="row",trace="none",
margin=c(5,10), hclust=hclustfunc,distfun=distfunc,lwid=c(1.5,2.0))
And finally, you could just manually edit the gradient for the zero values.
breaks = seq(0,max(dat),length.out=1000)
gradient1 = colorpanel( sum( breaks[-1]<=1 ), "green", "black" )
gradient2 = colorpanel( sum( breaks[-1]>1 ), "black", "red" )
hm.colors = c(gradient1,gradient2)
hm.colors[1] = col2hex("white")
heatmap.2(as.matrix(dat),scale="none",breaks=breaks,col=hm.colors,na.color="white",
Colv=FALSE,dendrogram="row",trace="none",
margin=c(5,10), hclust=hclustfunc,distfun=distfunc,lwid=c(1.5,2.0))
Log fold changes
On another note, it appears that you might be looking at fold changes or some type of ratio. It is fairly common to plot the log fold changes when making a heat map. I "greyed" out the zero values.
dat[dat==0] = NA
heatmap.2( as.matrix(log2(dat)), col=greenred(100),
scale="none", na.color="grey",symbreaks=TRUE,
Colv=FALSE,dendrogram="row",trace="none",
margin=c(5,10), hclust=hclustfunc,distfun=distfunc,lwid=c(1.5,2.0))
For an explanation of @josilber's nice solution:
This code hmcols <- c(colfunc1(200), colfunc2(200*(max(dat) - 1)))
makes
a character vector of length 774 (seen by length(hmcols)
). Thus, this means that there should be 775 breaks defined. The heatmap.2
function by default makes n+1
breaks where n
is the length of the vector used in the col
argument. So the number of breaks and colors is worked out, but how does hmcols <- c(colfunc1(200), colfunc2(200*(max(dat) - 1)))
map the colors to the breaks correctly? The trick is in clever way that the hmcols
vector was created. The number of colors in the first gradient is 200. Since breaks
was not explicitly defined, we know that the breaks will be evenly spaced. Since the first gradient goes from 0 to 1 and there are 200 breaks, the width of each break should be 0.005 (or 1/200). Since the second gradient goes from 1 to 3.869 (max(dat)
), there should be 2.869/0.005=573.8 breaks (574 breaks when rounding up). Note that the 200*(max(dat) - 1))
does this calculation; it outputs 573.8. Thus, there are then 200+574 colors mapped to the correct breaks and everything works!