How to Assign Your Color Scale on Raw Data in Heatmap.2()

How to assign your color scale on raw data in heatmap.2()

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 )

Sample Image

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))

Sample Image

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))

Sample Image

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))

Sample Image

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!

How to change the color key value in heatmap.2?

It's hard-coded. You will need to change it in the code. It appears about midway down the section that draws the key and the line is:

else mtext(side = 1, "Value", line = 2)

This is the section of the heatmap.2 code that creates the key (at least up to the point where the word "Value" appears) :

 if (key) {
par(mar = c(5, 4, 2, 1), cex = 0.75)
tmpbreaks <- breaks
if (symkey) {
max.raw <- max(abs(c(x, breaks)), na.rm = TRUE)
min.raw <- -max.raw
tmpbreaks[1] <- -max(abs(x), na.rm = TRUE)
tmpbreaks[length(tmpbreaks)] <- max(abs(x), na.rm = TRUE)
}
else {
min.raw <- min(x, na.rm = TRUE)
max.raw <- max(x, na.rm = TRUE)
}
z <- seq(min.raw, max.raw, length = length(col))
image(z = matrix(z, ncol = 1), col = col, breaks = tmpbreaks,
xaxt = "n", yaxt = "n")
par(usr = c(0, 1, 0, 1))
lv <- pretty(breaks)
xv <- scale01(as.numeric(lv), min.raw, max.raw)
axis(1, at = xv, labels = lv)
if (scale == "row")
mtext(side = 1, "Row Z-Score", line = 2)
else if (scale == "column")
mtext(side = 1, "Column Z-Score", line = 2)
else mtext(side = 1, "Value", line = 2)
.... lots more code below

You should type heatmap.2 , then copy the source code to an editor and then use the search function to find "Value". Change "Value" to something else (in quotes) and then type heatmap.2 <- and paste in the code and hit return. (Unless you save this it will only persist as long as the session continues.)

R - heatmap.2 (gplots): change colors for breaks

You do not provide a reproducible example, so I had to guess for some parts.

### your data
mean <- read.table(header = TRUE, sep = ';', text = "
sp1;sp2;sp3;sp4;sp5;sp6;sp7;Sp8;sp9;sp10
sp1;100.00;67.98;66.04;71.01;67.71;67.25;66.96;65.48;67.60;68.11
sp2;67.98;100.00;65.60;67.63;81.63;78.10;78.11;65.03;78.11;85.50
sp3;66.04;65.60;100.00;65.32;64.98;64.59;64.55;75.32;65.21;65.36
sp4;71.01;67.63;65.32;100.00;67.20;66.90;66.69;65.17;67.48;67.86
sp5;67.71;81.63;64.98;67.20;100.00;78.28;78.38;64.41;77.36;82.27
sp6;67.25;78.10;64.59;66.90;78.28;100.00;83.61;64.47;75.74;77.96
sp7;66.96;78.11;64.55;66.69;78.38;83.61;100.00;63.80;75.66;77.72
Sp8;65.48;65.03;75.32;65.17;64.41;64.47;63.80;100.00;65.63;64.59
sp9;67.60;78.11;65.21;67.48;77.36;75.74;75.66;65.63;100.00;77.78
sp10;68.11;85.50;65.36;67.86;82.27;77.96;77.72;64.59;77.78;100.00")

### your code
library(gplots)
meanm <- as.matrix(mean)

### define 4 colors to use for the space between 5 breaks
col = c("green","blue","red","yellow")
breaks <- c(0, 45, 65, 95, 100)
heatmap.2(meanm, breaks = breaks, col = col)

This yields the following plot:

Sample Image

I hope it makes the essence of defining the breaks and the colors clear.

UPDATE with gradient

I filled your four wanted "zones" defined by the 5 breakpoints with color gradients. I invented something: yellow-green, green-blue, blue-darkblue, darkblue-black.

breaks = seq(0, max(meanm), length.out=100)

### define the colors within 4 zones
gradient1 = colorpanel( sum( breaks[-1]<=45 ), "yellow", "green" )
gradient2 = colorpanel( sum( breaks[-1]>45 & breaks[-1]<=65 ), "green", "blue" )
gradient3 = colorpanel( sum( breaks[-1]>65 & breaks[-1]<=95 ), "blue", "darkblue" )
gradient4 = colorpanel( sum( breaks[-1]>95 ), "darkblue", "black" )

hm.colors = c(gradient1, gradient2, gradient3, gradient4)

heatmap.2(meanm, breaks = breaks, col = hm.colors)

This yields the following graph:

Sample Image

Please let me know whether this is what you want.

Customize range heatmap.2

Using scale = "row" will scale your data by row and doesn't keep your original, raw values so you should use scale = "none" if you want to preserve those.

You can set breaks manually by using the breaks argument. In this case, I think you could achieve what you're looking for by creating a sequence from -3 to 3, and setting length.out to one more than the number of colours you've defined (there needs to be 1 more breaks than colours):

heatmap.2(hmdat[select,],scale="none", col = hmcol, trace="none", margin=c(7, 5),cexCol=0.9,cexRow=0.5,density.info="density",breaks = seq(-3, 3, length.out = 101))

You might get warnings about there being no data for some values, and you may need to add symbreaks = TRUE to get the symmetrical effect you're looking for.

I don't think there is a simple option to change the labels of the color key, but you can try the solution in this question: How to change the color key value in heatmap.2?

Adjusting colour heatmap


I'm not certain to understand exactly the colors you want. If you want a continuous
color gradient, you need two colors for the values >3 (the gradient should be between red
and which other color ?). Basically one color is missing (I added "gold").
You will probably be able to easily adapt the example below as you whish.

Note that the number of breaks should not be too high (not thousands as in your questions)
otherwise the key will be entirely white.

Note also that green to red gradients are really not recommended as an non negligible
proportion of the human population is color blind to these colors (prefer blue - red or blue - green).

As far as I know it is not possible to place the columns and rows headings
on the top and on the left margins with heatmap.2. It is not possible neither to draw boxes. However you can draw horizontal and vertical lines.

You might look at the Bioconductor package ComplexHeatmap that allows more control (including drawing boxes and changing the location of the labels).

library(gplots)
#>
#> Attachement du package : 'gplots'
#> The following object is masked from 'package:stats':
#>
#> lowess
data <- read.csv(text = ',MUT,AB1,M86,MU0,MZ4
2pc0,9.3235,9.2234,8.5654,6.5688,6.0312
2hb4,7.4259,7.9193,7.0837,6.1959,9.6501
3ixo,9.1124,4.8244,9.2058,5.6194,4.8181
2i0d,10.1331,9.9726,1.7889,2.1879,1.0692
2q5k,10.7538,0.377,9.8693,1.5496,9.869
4djq,12.0394,2.4673,3.7014,10.8828,1.4023
2q55,10.7834,1.4322,5.3941,0.871,1.7253
2qi1,10.0908,10.7989,4.1154,2.3832,1.2894', comment.char="#")

rnames <- data[,1] # assign labels in column 1 to "rnames"
mat_data <- data.matrix(data[,2:ncol(data)]) # transform column 2-5 into a matrix
rownames(mat_data) <- rnames # assign row names

# First define your breaks
col_breaks <- seq(0,max(mat_data), by = 0.1)

# Then define wich color gradient you want for between each values
# Green - red radient not recommended !!
# NB : this will work only if the maximum value is > 3
my_palette <- c(colorRampPalette(c("forestgreen", "yellow"))(20),
colorRampPalette(c("yellow", "gold"))(10),
colorRampPalette(c("gold", "red"))(length(col_breaks)-31))

# x11(width = 10/2.54, height = 10/2.54)
mat_data <- round(mat_data,2) # probably better to round your values for easier reading

heatmap.2(mat_data,
cellnote = mat_data, # same data set for cell labels
main = "Correlation", # heat map title
notecol="black", # change font color of cell labels to black
density.info="none", # turns off density plot inside color legend
trace="none", # turns off trace lines inside the heat map
margins =c(4,4), # widens margins around plot
col=my_palette, # use on color palette defined earlier
breaks=col_breaks, # enable color transition at specified limits
dendrogram="none", # only draw a row dendrogram
Colv="NA", # turn off column clustering

# add horizontal and vertical lines (but no box...)
colsep = 3,
rowsep = 3,
sepcolor = "black",

# additional control of the presentation
lhei = c(3,10), # adapt the relative areas devoted to the matrix
lwid = c(3,10),
cexRow = 1.2,
cexCol = 1.2,
key.title = "",
key.par = list(mar = c(2,0.5,1.5,0.5), mgp = c(1, 0.5, 0))
)

Sample Image

Created on 2018-02-25 by the reprex package (v0.2.0).

How to color the branches and tick labels in the heatmap.2?

Solution: use the color_branches function from the dendextend package (or the set function, with the "branches_k_color", "k", and "value" parameters ).

First we need to get the data into R and create the relevant objects ready (this part is the same as the code in the question):

test <- read.delim("clipboard", sep="")

rnames <- test[,1]
test <- data.matrix(test[,2:ncol(test)]) # to matrix
rownames(test) <- rnames
test <- scale(test, center=T, scale=T) # data standarization
test <- t(test) # transpose

## Creating a color palette & color breaks

my_palette <- colorRampPalette(c("forestgreen", "yellow", "red"))(n = 299)

col_breaks = c(seq(-1,-0.5,length=100), # forestgreen
seq(-0.5,0.5,length=100), # yellow
seq(0.5,1,length=100)) # red

# distance & hierarchical clustering
distance= dist(test, method ="euclidean")
hcluster = hclust(distance, method ="ward.D")

Next, we get the dendrogram and the heatmap ready:

dend1 <- as.dendrogram(hcluster)

# Get the dendextend package
if(!require(dendextend)) install.packages("dendextend")
library(dendextend)
# get some colors
cols_branches <- c("darkred", "forestgreen", "orange", "blue")
# Set the colors of 4 branches
dend1 <- color_branches(dend1, k = 4, col = cols_branches)
# or with:
# dend1 <- set(dend1, "branches_k_color", k = 4, value = cols_branches)

# get the colors of the tips of the dendrogram:
# col_labels <- cols_branches[cutree(dend1, k = 4)] # this may need tweaking in various cases - the following is a more general solution.

# The following code will work on its own once I uplode dendextend 0.18.6 to CRAN - but that can
# take several good weeks until that happens. In the meantime
# Either use devtools::install_github('talgalili/dendextend')
# Or just the following:
source("https://raw.githubusercontent.com/talgalili/dendextend/master/R/attr_access.R")

col_labels <- get_leaves_branches_col(dend1)
# But due to the way heatmap.2 works - we need to fix it to be in the
# order of the data!
col_labels <- col_labels[order(order.dendrogram(dend1))]

# Creating Heat Map
if(!require(gplots)) install.packages("gplots")
library(gplots)
heatmap.2(test,
main = paste( "test"),
trace="none",
margins =c(5,7),
col=my_palette,
breaks=col_breaks,
dendrogram="row",
Rowv = dend1,
Colv = "NA",
key.xlab = "Concentration (index)",
cexRow =0.6,
cexCol = 0.8,
na.rm = TRUE,
RowSideColors = col_labels, # to add nice colored strips
colRow = col_labels # to add nice colored labels - only for qplots 2.17.0 and higher
)

Which produces this plot:

Sample Image

For more details on the package, you can have a look at its vignette.

p.s.: to get the labels colored depends on parameters of heatmap.2, and this should be asked from the maintainer of gplots (i.e.: from greg at warnes.net)

update: this answer now includes the new "colRow" parameter in qplots 2.17.0.

Change Scale of Heatmap to Show More Colours

Or was that about it?

x <- seq(3, 5, by = 1)
y <- seq(5, 101, by = 2)
z <- seq(3, 10^-13, length = 146)

combinations <- expand_grid(x, y) %>%
subset(y > x) %>%
cbind(z)

combinations %>%
ggplot(aes(x, y, z=z)) +
geom_contour_filled()+
geom_point(data = combinations %>% filter(z<1e-6),
size=10, color = "red")

Do it this way. It has to work !!

library(tidyverse)
library(ggplot2)

x <- seq(3, 5, by = 1)
y <- seq(5, 101, by = 2)
z <- seq(3, 10^-13, length = 146)

combinations <- expand_grid(x, y) %>%
subset(y > x) %>%
cbind(z)

combinations %>%
ggplot(aes(x, y, z=z)) +
geom_contour_filled()+
geom_point(data = combinations %>% dplyr::filter(z<1e-6),
size=10, color = "red")

Why colors did not appear in Key of heatmap.2()

The colours are being parsed at very high resolution. You have assigned a colour gradient to every value in your matrix, total of 17410. Try decreasing the colour gradient to 128 or 256: col=bluered(256).

Alternatively, increase the key size keysize=1 to display the higher colour gradient.



Related Topics



Leave a reply



Submit