Question: How Do I Draw A Heatmap In R With Both A Color Key And Multiple Color Side Bars?
14
gravatar for Obi Griffith
2.1 years ago by
Obi Griffith6.9k
St Louis, MO, USA
Obi Griffith6.9k wrote:

I often use heatmap.2 {gplots} because of its many improvements/options over the standard heatmap function. However, occasionally I require multiple color side bars (heatmap.2 only supports one on each axis). It is possible to do this with heatmap.plus. However, you then lose other features like the value color key, breaks, level trace, etc. Furthermore, beyond ~3 columns/rows of color sidebars, the bars are too squeezed together to see clearly, or to be able to read the labels. Any solutions out there?

ADD COMMENTlink modified 11 months ago by David670 • written 2.1 years ago by Obi Griffith6.9k
27
gravatar for Obi Griffith
2.1 years ago by
Obi Griffith6.9k
St Louis, MO, USA
Obi Griffith6.9k wrote:

I answered my own question by finding this post in the R-help mailing list. If you replace the corresponding blocks in heatmap.2 with blocks of code provided in that post you can get multiple color side bars in heatmap.2. The next message in the thread provides a solution for when you want more than two or three color side bars not too squished together. Using these changes I created a new heatmap.3 function that accepts number of row/column color side bars as a parameter and spaces them out appropriately. I also added a parameter for specifying a name for the color key besides "Value". Here is the code (github). You can just source this file and then call the heatmap.3 function with the new options as in the below example.

UPDATE: After several requests I created a fully functioning script on fake data. Of course, it is up to you to make sure you are setting up data and color side bars correctly when it comes to your own real data.

UPDATE: @Nachocab has made further improvements that allows a 1-dimensional data.frame for the annotations, and fixes the NA problem in the color key. I have modified my link above to point to his new improved version at github.

setwd("/Your/Working/Dir") #Put heatmap.3 code here
library("gplots")

#Create a fake dataset
prob_matrix=replicate(100, rnorm(20)) 
drug_names=paste("drug",letters[1:20],sep="_")
patient_ids=paste("patient",c(1:100),sep="_")
rownames(prob_matrix)=drug_names
colnames(prob_matrix)=patient_ids

#Create fake color side bars
drug_colors=sample(c("darkorchid","darkred"), length(drug_names), replace = TRUE, prob = NULL)
subtype_colors=sample(c("red","blue","cyan","pink","yellow","green"), length(patient_ids), replace = TRUE, prob = NULL)
Mcolors=sample(c("black","white","grey"), length(patient_ids), replace = TRUE, prob = NULL)
Ncolors=sample(c("black","white","grey"), length(patient_ids), replace = TRUE, prob = NULL)
Tcolors=sample(c("black","white","grey"), length(patient_ids), replace = TRUE, prob = NULL)
HER2colors=sample(c("black","white","grey"), length(patient_ids), replace = TRUE, prob = NULL)
PRcolors=sample(c("black","white","grey"), length(patient_ids), replace = TRUE, prob = NULL)
ERcolors=sample(c("black","white","grey"), length(patient_ids), replace = TRUE, prob = NULL)
rlab=cbind(drug_colors,drug_colors) #note, duplicated columns because function expects matrix of at least 2xn
clab=cbind(subtype_colors,Mcolors,Ncolors,Tcolors,HER2colors,PRcolors,ERcolors)
colnames(rlab)=c("Class","")
colnames(clab)=c("Subtype","M","N","T","HER2","PR","ER")

#Define custom dist and hclust functions for use with heatmaps
mydist=function(c) {dist(c,method="euclidian")}
myclust=function(c) {hclust(c,method="average")}

#Create heatmap using custom heatmap.3 source code
source("heatmap.3.R")
pdf(file="heatmap_example.pdf")
main_title="Drug Response Predictions"
par(cex.main=1)
heatmap.3(prob_matrix, hclustfun=myclust, distfun=mydist, na.rm = TRUE, scale="none", dendrogram="both", margins=c(4,10), 
Rowv=TRUE, Colv=TRUE, ColSideColors=clab, RowSideColors=rlab, symbreaks=FALSE, key=TRUE, symkey=FALSE, 
density.info="none", trace="none", main=main_title, labCol=FALSE, labRow=drug_names, cexRow=1, col=rev(heat.colors(75)), 
NumColSideColors=7, KeyValueName="Prob. Response")
legend("topright",legend=c("Basal","LumA","LumB","Her2","Claudin","Normal","","Positive","Negative","NA","","Targeted","Chemo"), 
fill=c("red","blue","cyan","pink","yellow","green","white","black","white","grey","white","darkorchid","darkred"), border=FALSE, bty="n", y.intersp = 0.7, cex=0.7)
dev.off()

Heatmap with multiple color side bars

ADD COMMENTlink modified 12 months ago • written 2.1 years ago by Obi Griffith6.9k
2

Cool, thanks! FYI: I'm pretty sure you want to change the default values for the symbreaks and symkey args to from min(x < 0, na.rm=TRUE) to min(x, na.rm=TRUE) < 0, no?

ADD REPLYlink written 2.1 years ago by Steve Lianoglou3.7k

Yes. I think you are correct. I just copied that default from heatmap.2 code. I can't say that I've noticed a problem with this. I usually have only positive values and don't scale. But, it looks like the default behavior is not working as stated in the documentation (i.e., symbreaks/symkey "Defaults to TRUE if the data includes negative values, and to FALSE otherwise"). Currently it defaults to TRUE if ALL values are negative or if scale!="none" is TRUE. Could also be fixed by changing to "max(x < 0, na.rm=TRUE)". Fixed in my uploaded file.

ADD REPLYlink written 2.1 years ago by Obi Griffith6.9k

The HTML seems mangled now. The heatmap.3 code can be found here

<script src="&lt;a href=" 3853004"="">3853004"></script>

ADD REPLYlink written 12 months ago by Federico Giorgi200

Hi Obi, I just found heatmap.3 in package GMD. Is this (http://www.inside-r.org/packages/cran/GMD/docs/heatmap.3) related code or based on yours, or is it indeed heatmap.3b?

ADD REPLYlink written 6 months ago by Michael Dondrup27k

When I ran the heatmap.3 function to try to get a heatmap with multiple sidebars with the exactly the same scripts and dataset that Obi provided, it failed and showed the error message. The script and error message are showed below.

heatmap.3(prob_matrix, hclustfun=myclust, distfun=mydist, na.rm = TRUE, scale="none", dendrogram="both", margins=c(4,10), Rowv=TRUE, Colv=TRUE, ColSideColors=clab, RowSideColors=rlab, symbreaks=FALSE, key=TRUE, symkey=FALSE, density.info="none", trace="none", main=main_title, labCol=FALSE, labRow=drug_names, cexRow=1, col=rev(heat.colors(75)), NumColSideColors=7, KeyValueName="Prob. Response")

Error in heatmap.3(prob_matrix, hclustfun = myclust, distfun = mydist, : 'RowSideColors' must be a matrix of ncol(x) columns

Is there anyone who had the same problem as shown above? Something is wrong with the RowSideColors argument.

Thanks.

ADD REPLYlink modified 6 months ago • written 6 months ago by neurotemple0

Hm, works for me. I tried both codes from github. Note that you only need heatmap.3 if you require more than one row/column in ColSideColors/RowSideColors.

ADD REPLYlink written 6 months ago by Michael Dondrup27k

I do need multiple sidebars at the column side. I tried both codes from github, too. None of them works unfortunately. Is there any bug or compatibility problem between the heatmap.3 code and latest version of R (my one is R X64 3.0.1)? Thanks.

Jeff

ADD REPLYlink written 6 months ago by neurotemple0

right, but you didn't use the example data provided with the code. The error is possibly literally what R tells you: 'RowSideColors' must be a matrix of ncol(x) columns, and I guess that is not the case. You need the column annotations as a matrix with the same number of columns as the data matrix. So what does rlab look like?

ADD REPLYlink written 6 months ago by Michael Dondrup27k

I did exactly use the same example data provided with the code for testing. After executing rlab command, you can see the following matrix.

> rlab



  class

[1,] "darkorchid" "darkorchid"
[2,] "darkred" "darkred"
[3,] "darkorchid" "darkorchid"
[4,] "darkred" "darkred"
[5,] "darkorchid" "darkorchid"
[6,] "darkred" "darkred"
[7,] "darkred" "darkred"
[8,] "darkorchid" "darkorchid"
[9,] "darkorchid" "darkorchid" [10,] "darkred" "darkred"
[11,] "darkred" "darkred"
[12,] "darkred" "darkred"
[13,] "darkorchid" "darkorchid" [14,] "darkred" "darkred"
[15,] "darkorchid" "darkorchid" [16,] "darkred" "darkred"
[17,] "darkorchid" "darkorchid" [18,] "darkorchid" "darkorchid" [19,] "darkorchid" "darkorchid" [20,] "darkred" "darkred"

It is a 2-column-and-20-row matrix.

As you stated above, the column annotations should be a matrix with the same number of columns as the data matrix. The example matrix has 100 columns, do I have to make the column annotation (rlab) as a matrix with 100 columns? If this is the case, do you think the sidebar generated will be too wide?

ADD REPLYlink modified 6 months ago • written 6 months ago by neurotemple0

sorry I meant clab for ColSideColors. I think you have to make a 100 column, two row matrix to test, try clab = matrix(c("red","green","blue"), ncol=100, nrow=2). ofc you should have some sensible annotation data for your columns somewhere.

ADD REPLYlink written 6 months ago by Michael Dondrup27k
6
gravatar for David
11 months ago by
David670
David670 wrote:

There is a package for that called Heatplus http://www.bioconductor.org/packages/release/bioc/html/Heatplus.html

enter image description here

ADD COMMENTlink written 11 months ago by David670

Thanks for posting about this. I was aware of heatmap, heatmap.2 and heatmap.plus. The latter does add the ability for multiple color side bars but then you lose other nice features of heatmap.2 (e.g., the color key). Thus the original reason for my post. It looks like heatplus might solve this. Although, in the vignette I don't see an example that has both row and column color sidebars AND a color key.

ADD REPLYlink written 6 months ago by Obi Griffith6.9k
3
gravatar for Nachocab
18 months ago by
Nachocab40
Boston, MA
Nachocab40 wrote:

Here's a revision on @Obi Griffiths code that allows using a 1-dimensional data.frame for the annotations, and fixes the NA problem in the color key:

<script src="&lt;a href=" 3853004"="">3853004"></script>

Here's how you would call it:

mat <- matrix(1:100, byrow=T, nrow=10)
column_annotation <- sample(c("red", "blue", "green"), 10, replace=T)
column_annotation <- as.matrix(column_annotation)    
colnames(column_annotation) <- c("True")
heatmap.3(mat, ColSideColors=column_annotation)
ADD COMMENTlink modified 18 months ago • written 18 months ago by Nachocab40

Can you provide a code snippet? No matter how I try creating a 1-dimensional data.frame I get an error when trying to run your modified code. I assumed that something like "rlab=data.frame(Class=drugcolors)" would work. But that returns: "Error in heatmap.3(probmatrix, hclustfun = myclust, distfun = mydist, : 'RowSideColors' must be a character vector of length nrow(x)". If I try providing a character vector I get "Error in if (!is.character(RowSideColors) || dim(RowSideColors)[1] != : missing value where TRUE/FALSE needed". I also tried converting the 1-dimensional data.frame column to a character strings with (as.character) and also tried inputting a 1-dimensional matrix. But nothing worked. I must be missing something...

ADD REPLYlink modified 18 months ago • written 18 months ago by Obi Griffith6.9k

Nachocab. Still wondering if you can demonstrate how your code works with 1-dimensional data.

ADD REPLYlink written 18 months ago by Obi Griffith6.9k

Hi Obi, I'm sorry I missed your message. I just added a snippet to my answer (I think you might have been missing the as.matrix() step). Send me an email next time

ADD REPLYlink modified 18 months ago • written 18 months ago by Nachocab40

Hi Nachocab. Thanks for getting back to me. I did try as.matrix. It looks like it works for ColSideColors with a single column matrix of colors but not for RowSideColors with a single column (or single row) matrix of colors. Did you by chance update the code for one but not the other?

ADD REPLYlink modified 16 months ago • written 18 months ago by Obi Griffith6.9k
2
gravatar for Steve Lianoglou
11 months ago by
Steve Lianoglou3.7k
US
Steve Lianoglou3.7k wrote:

Revisiting this old(er) q/a tutorial as I just came across the aheatmap function in the NMF package, which has slipped under my radar up until now and thought it might be useful to others since it does similar mojo.

The authors also have a nice vignette which is linked from their main page that shows off some of what it can do.

One added extra bonus is that it lets you plot multiple heatmaps in one plot as it is compatible with, for example, the par(mfrow=c(1,2)) mojo.

ADD COMMENTlink written 11 months ago by Steve Lianoglou3.7k

very cool package!

ADD REPLYlink written 9 months ago by dli100
0
gravatar for spleenete
22 months ago by
spleenete0
spleenete0 wrote:

Thanks! That's really useful. BTW, could you provide a complete example to exactly reproduce your figure?

ADD COMMENTlink written 22 months ago by spleenete0

This should have been a comment. Not an answer. I have provided example R code. Unfortunately I am not able to provide a complete example because the data underlying this particular figure is very large and not available for public posting yet.

ADD REPLYlink written 22 months ago by Obi Griffith6.9k

I found some time and re-worked my answer above to provide a complete working example, now on random data, rather than data I couldn't release here.

ADD REPLYlink written 22 months ago by Obi Griffith6.9k
Please log in to add an answer.

Help
Access
  • RSS
  • Stats
  • API

Use of this site constitutes acceptance of our User Agreement and Privacy Policy.
Powered by Biostar version 2.0.0
Traffic: 619 users visited in the last hour