Table of Contents

Heatmap Decoration

Author: Zuguang Gu ( z.gu@dkfz.de )

Date: 2018-08-30


Each components of the heatmap/heatmap list has a name (unique id). You can go to any viewport to add graphics in by specifying the heatmap/annotation name.

First generate a figure that almost contains all types of heatmap components.

library(ComplexHeatmap)

mat = matrix(rnorm(80, 2), 8, 10)
mat = rbind(mat, matrix(rnorm(40, -2), 4, 10))
rownames(mat) = paste0("R", 1:12)
colnames(mat) = paste0("C", 1:10)

ha_column1 = HeatmapAnnotation(points = anno_points(rnorm(10)))
ht1 = Heatmap(mat, name = "ht1", km = 2, row_title = "Heatmap 1", column_title = "Heatmap 1", 
    top_annotation = ha_column1)

ha_column2 = HeatmapAnnotation(df = data.frame(type = c(rep("a", 5), rep("b", 5))),
    col = list(type = c("a" = "red", "b" = "blue")))
ht2 = Heatmap(mat, name = "ht2", row_title = "Heatmap 2", column_title = "Heatmap 2",
    bottom_annotation = ha_column2)

plot of chunk access_components

The components (viewports) that have names are:

decorate_* functions

Basically, you can go to these components by seekViewport(), but to hide the details that is too low-level, ComplexHeatmap package provides decorate_* family functions which makes it easy to add graphics into different components.

Following code add annotation names, mark one grid in the heatmap and seperate the first column clusters with two rectangles.

ht_list = draw(ht_list, row_title = "Heatmap list", column_title = "Heatmap list", 
    heatmap_legend_side = "right", annotation_legend_side = "left")
decorate_annotation("points", {
    grid.text("points", unit(0, "npc") - unit(2, "mm"), 0.5, 
        default.units = "npc", just = "right")
})

decorate_heatmap_body("ht1", {
    grid.text("outlier", 1.5/10, 2.5/4, default.units = "npc")
    grid.lines(c(0.5, 0.5), c(0, 1), gp = gpar(lty = 2, lwd = 2))
}, slice = 2)

decorate_column_dend("ht1", {
    tree = column_dend(ht_list)$ht1
    ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]

    first_index = function(l) which(l)[1]
    last_index = function(l) { x = which(l); x[length(x)] }
    x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
    x2 = c(last_index(ind == 1), last_index(ind == 2))
    grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
        default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})

decorate_row_names("ht2", {
    grid.rect(gp = gpar(fill = "#FF000040"))
}, slice = 2)

decorate_row_title("ht1", {
    grid.rect(gp = gpar(fill = "#00FF0040"))
}, slice = 1)

decorate_annotation("points", {
    grid.lines(c(0, 1), unit(c(0, 0), "native"), gp = gpar(col = "red"))
})

plot of chunk components

For annotations which are created by anno_points(), anno_barplot() and anno_boxplot(), “native” unit can be used in the decoration code.

Add annotation names

By default, annotation names are not plotted along with the heatmap annotations. The reason is if annotation names is plotted, they will located in the area of other heatmap components which would makes the adjustment of the heatmap layout difficult. HeatmapAnnotation() provides a not-so-perfect solution for adding annotation names, however, since you can go to any component in the heatmap list by its name, actually it is not difficult to add annotation names manually.

Following code add annotation names on the both sides of the column annotations. The drawback is since there is no specific component designed for annotation names, if the annotation name is too long, it will be exceeding the figure region (but this problem can be solved by some tricks, see the Examples vignette).

df = data.frame(type1 = c(rep("a", 5), rep("b", 5)),
                type2 = c(rep("A", 3), rep("B", 7)))
ha = HeatmapAnnotation(df, col = list(type1 = c("a" = "red", "b" = "blue"),
                                      type2 = c("A" = "green", "B" = "orange")))
Heatmap(mat, name = "ht", top_annotation = ha)
for(an in colnames(df)) {
    decorate_annotation(an, {
        # annotation names on the right
        grid.text(an, unit(1, "npc") + unit(2, "mm"), 0.5, default.units = "npc", just = "left")
        # annotation names on the left
        grid.text(an, unit(0, "npc") - unit(2, "mm"), 0.5, default.units = "npc", just = "right")
    })
}

plot of chunk annotation_title

Visualize distributions

With heatmap decorations, actually you can design new graphics based on heatmaps. Following is an example:

To visualize distribution of columns in a matrix or in a list, sometimes we use boxplot or beanplot. Here we can also use colors to map to the density values and visualize distribution of values in each column (or each list element) through a heatmap. Sometimes it can give you a more clear image of your data.

Here the package has a densityHeatmap() function, the usage is quite straightforward:

matrix = matrix(rnorm(100), 10); colnames(matrix) = letters[1:10]
ha = HeatmapAnnotation(df = data.frame(anno = rep(c("A", "B"), each = 5)),
    col = list(anno = c("A" = "green", "B" = "orange")),
    points = anno_points(runif(10)))
densityHeatmap(matrix, anno = ha)

plot of chunk density

Session info

sessionInfo()
## R version 3.5.1 Patched (2018-07-12 r74967)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 16.04.5 LTS
## 
## Matrix products: default
## BLAS: /home/biocbuild/bbs-3.8-bioc/R/lib/libRblas.so
## LAPACK: /home/biocbuild/bbs-3.8-bioc/R/lib/libRlapack.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
##  [4] LC_COLLATE=C               LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
## [10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
##  [1] stats4    parallel  grid      stats     graphics  grDevices utils     datasets  methods  
## [10] base     
## 
## other attached packages:
##  [1] GetoptLong_0.1.7      dendextend_1.8.0      dendsort_0.3.3        cluster_2.0.7-1      
##  [5] HilbertCurve_1.11.1   GenomicRanges_1.33.13 GenomeInfoDb_1.17.1   IRanges_2.15.17      
##  [9] S4Vectors_0.19.19     BiocGenerics_0.27.1   circlize_0.4.4        ComplexHeatmap_1.19.2
## [13] knitr_1.20            markdown_0.8         
## 
## loaded via a namespace (and not attached):
##  [1] mclust_5.4.1           Rcpp_0.12.18           mvtnorm_1.0-8          lattice_0.20-35       
##  [5] png_0.1-7              class_7.3-14           assertthat_0.2.0       mime_0.5              
##  [9] R6_2.2.2               plyr_1.8.4             evaluate_0.11          ggplot2_3.0.0         
## [13] highr_0.7              pillar_1.3.0           GlobalOptions_0.1.0    zlibbioc_1.27.0       
## [17] rlang_0.2.2            lazyeval_0.2.1         diptest_0.75-7         kernlab_0.9-27        
## [21] whisker_0.3-2          stringr_1.3.1          RCurl_1.95-4.11        munsell_0.5.0         
## [25] compiler_3.5.1         pkgconfig_2.0.2        shape_1.4.4            nnet_7.3-12           
## [29] tidyselect_0.2.4       gridExtra_2.3          tibble_1.4.2           GenomeInfoDbData_1.1.0
## [33] viridisLite_0.3.0      crayon_1.3.4           dplyr_0.7.6            MASS_7.3-50           
## [37] bitops_1.0-6           gtable_0.2.0           magrittr_1.5           scales_1.0.0          
## [41] stringi_1.2.4          XVector_0.21.3         viridis_0.5.1          flexmix_2.3-14        
## [45] bindrcpp_0.2.2         robustbase_0.93-2      fastcluster_1.1.25     HilbertVis_1.39.1     
## [49] rjson_0.2.20           RColorBrewer_1.1-2     tools_3.5.1            fpc_2.1-11.1          
## [53] glue_1.3.0             trimcluster_0.1-2.1    DEoptimR_1.0-8         purrr_0.2.5           
## [57] colorspace_1.3-2       prabclus_2.2-6         bindr_0.1.1            modeltools_0.2-22