There are many packages that can generate heatmaps in R. To set apart, WHeatmap designs a set of languages and a layer system that allows positioning of heatmaps programmatically. This is a tutorial on the usage of wheatmap for generating complex heatmaps in a procedure way.
package can be installed from
We start with some data
library(wheatmap)
m <- cbind(matrix(rnorm(20),nrow=4), 5+matrix(rnorm(8),nrow=4))
m2 <- matrix(1:16,nrow=4)
dimnames(m) <- list(c('w','x','y','z'), c('a','b','c','d','e','f','g'))
row.data <- c(1,2,3,1)
col.data <- c(1:6,6)
m[,1:4]
## a b c d
## w -0.4583069 1.30476978 0.1667562 1.8657484
## x -1.8102042 0.58065885 -1.5304445 -0.9992026
## y 1.3886259 -0.34966502 -2.8594024 0.7886156
## z 0.8844454 -0.01050073 -0.9373540 0.4408559
We perform some clustering. Note that cc$mat
is the
matrix after clustering and keeps the row and column names so that one
can use them for reordering other color bars.
cc$row.clust$order
and cc$column.clust$order
also provide a integer reordering.
cc <- both.cluster(m)
row.data <- row.data[cc$row.clust$order]
col.data <- col.data[cc$column.clust$order]
cc$mat[,1:4]
## f g a e
## y 4.252222 6.695329 1.3886259 0.5897507
## z 5.091487 3.214268 0.8844454 0.4809978
## w 5.925792 5.745324 -0.4583069 -1.8758312
## x 3.226580 5.296304 -1.8102042 -1.0174012
The end result of our tutorial can be done by the “one”-liner
WHeatmap(cc$mat, name='h1') +
WColorBarV(row.data, LeftOf('h1'), 'c1') +
WColorBarH(col.data, TopOf('h1'), 'c2') +
WDendrogram(cc$row.clust, LeftOf('c1'), facing='right') +
WDendrogram(cc$column.clust, TopOf('c2'), facing='bottom') +
WColorBarV(1:4, RightOf('h1'), 'c3', continuous=TRUE) +
WHeatmap(m2, RightOf('c3'), 'h2') +
WColorBarH(rep(c(1,2,3),each=4),
Beneath(WColumnBind('h1', 'c3', 'h2')), 'c4',
cmp=CMPar(brewer.name='Set2'), continuous=FALSE) +
WHeatmap(matrix(rep(c(8:1,1:8),4),nrow=4),
Beneath('c4', h.aln=WColumnBind('h1','c3')), 'h3') +
WHeatmap(matrix(rep(1:10),ncol=2),LeftOf(WRowBind('c4.1.1','h3.1.1'))) +
WHeatmap(matrix(1:4,nrow=2), RightOf('h3', h.scale='h2'), 'h4') +
WHeatmap(matrix(1:24,nrow=3), Beneath('h3'), 'h5') +
WHeatmap(matrix(24:1,nrow=2),
Beneath('h5', h.aln=WColumnBind('h1','c3','h2')), 'h6') +
WLegendV('c1', BottomRightOf('h6.1.3', h.pad=0.01), 'l1') +
WLegendV('c2', TopOf('l1', pad = 0.1), 'l2') +
WLegendV('c3', RightOf('l1', pad=0.1), 'l3', n.text=3, label.fontsize = 10) +
WLabel('Rainbow colors', RightOf('l2', pad=0.08), rot=-90) +
WLabel('a little\nhouse', color='black',
WPosition(1,2,'h4',data.coord=TRUE, just=c('center','center'))) +
WRect('h3.1.1', c(2,5),c(2,3),col='yellow') +
WRect('h1',c(5,6),c(2,3),col='yellow')
We plot one heatmap first
Then we add top and left color bars
a <- a + WColorBarV(row.data, LeftOf('h1'), 'c1')
a <- a + WColorBarH(col.data, TopOf('h1'), 'c2')
a
Then the dendrograms
a <- a + WDendrogram(cc$row.clust, LeftOf('c1'), facing='right')
a <- a + WDendrogram(cc$column.clust, TopOf('c2'), facing='bottom')
a
Then another vertical color bar on the right. This one we want to have a continuous scale. Then another heatmap on the further right.
a <- a + WColorBarV(1:4, RightOf('h1'), 'c3', continuous=TRUE)
a <- a + WHeatmap(m2, RightOf('c3'), 'h2')
a
Now we can merge 3 items we plot and add a horizontal bar below. Note wheatmap automatically computes the split for you. It’s the users’ responsibility however, to make sure data are alignable.
a <- a + WColorBarH(rep(c(1,2,3),each=4),
Beneath(WColumnBind('h1', 'c3', 'h2')), 'c4',
cmp=CMPar(brewer.name='Set2'), continuous=FALSE)
a
We then add another matrix that span two objects under c4. And a vertial 2-column heatmap on the left that span 2 elements.
a <- a + WHeatmap(
matrix(rep(c(8:1,1:8),4),nrow=4),
Beneath('c4', h.aln=WColumnBind('h1','c3')), 'h3')
a <- a + WHeatmap(matrix(rep(1:10),ncol=2),
LeftOf(WRowBind('c4.1.1','h3.1.1')))
a
Another to the right of h3
a <- a + WHeatmap(
matrix(1:4,nrow=2), RightOf('h3', h.scale='h2'), 'h4')
a <- a + WHeatmap(
matrix(1:24,nrow=3), Beneath('h3'), 'h5')
a <- a + WHeatmap(
matrix(24:1,nrow=2),
Beneath('h5', h.aln=WColumnBind('h1','c3','h2')), 'h6')
a
Let’s add legend
a <- a + WLegendV('c1', BottomRightOf('h6.1.3', h.pad=0.01), 'l1')
a <- a + WLegendV('c2', TopOf('l1', pad = 0.1), 'l2')
a <- a + WLegendV('c3', RightOf('l1', pad=0.1), n.text=3)
a
And add some text labels using relative and arbitrary position
a <- a + WLabel('Rainbow colors', RightOf('l2', pad=0.08), rot=-90)
a <- a + WLabel('a little\nhouse', color='black', WPosition(1,2,'h4',data.coord=TRUE, just=c('center','center')))
a
And finally highlight some cells
We can view the internal layout by the providing the
layout.only=TRUE
option. This is useful to see the labeling
visually.
Each object has members with unique names. One can specify a name or have wheatmap generate a name. If an item is a group object by itself, it can also have members of its own. The names of members from different groups can be identical. When that’s the case, one needs to use the full path to refer to the object.
Wheatmap automatically de-cluttered the labels when there are too many. Below is an example of too many labels:
WHeatmap(cc$mat, name='h1',
yticklabels = TRUE, yticklabel.fontsize=20,
xticklabels = TRUE, xticklabel.side = 't', xticklabel.fontsize = 25)
The LeftOf, TopOf, RightOf and Beneath are for placing a new object by anchoring to the edge of an existing object.
The BottomRightOf, BottomLeftOf, TopLeftOf and TopRightOf are for placing a new object by anchoring to the corner of an existing object.