Table of Contents

Heatmap and Annotation Legends

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

Date: 2018-10-30


The legends for heatmaps are composed with a color bar, labels and titles. ComplexHeatmap automatically generates legends according to the input matrix and annotations, while also provide flexibility to customize and add new legends.

Basic settings

Legends for all heatmaps and row annotations are drawn together and legends for all column annotations are drawn together. The legends for heatmaps and legends for annotations are put in independent viewports.

library(ComplexHeatmap)
library(circlize)

set.seed(123)
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_column = HeatmapAnnotation(df = data.frame(type1 = c(rep("a", 5), rep("b", 5))),
    col = list(type1 = c("a" =  "red", "b" = "blue")))
ha_row = rowAnnotation(df = data.frame(type2 = c(rep("A", 6), rep("B", 6))),
    col = list(type2 = c("A" =  "green", "B" = "orange")), width = unit(1, "cm"))

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha_column)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2")
ht_list = ht1 + ht2 + ha_row

draw(ht_list)

plot of chunk legend_default

Side of legends can be set by heatmap_legend_side and annotation_legend_side.

draw(ht_list, heatmap_legend_side = "left", annotation_legend_side = "bottom")

plot of chunk legend_side

show_heatmap_legend and show_annotation_legend set visibility of legends.

draw(ht_list, show_heatmap_legend = FALSE, show_annotation_legend = FALSE)

plot of chunk legend_show

You can choose to only show some of the heatmap legends by setting show_heatmap_legend to a logical value when constructing single heatmaps. Also HeatmapAnnotation() (or the shortcut function columnAnnotation() and rowAnnotation()) provides show_legend argument to control visibility of annotation legends.

ha_column = HeatmapAnnotation(df = data.frame(type1 = c(rep("a", 5), rep("b", 5))),
    col = list(type1 = c("a" =  "red", "b" = "blue")), show_legend = FALSE)
ha_row = rowAnnotation(df = data.frame(type2 = c(rep("A", 6), rep("B", 6))),
    col = list(type2 = c("A" =  "green", "B" = "orange")), show_legend = FALSE, width = unit(1, "cm"))

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha_column)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", show_heatmap_legend = FALSE)
ht1 + ht2 + ha_row

plot of chunk legend_show_part

Customization of legends

Legend itself can be flexibly customized. Parameters for making the legend can be set by heatmap_legend_param (for heatmap) or annotation_legend_param (for annotations). The parameters that can be set are as follows:

Following example changes the default graphic parameters for labels and titles:

df = data.frame(type = c(rep("a", 5), rep("b", 5)))
ha = HeatmapAnnotation(df = df, col = list(type = c("a" =  "red", "b" = "blue")),
    annotation_legend_param = list(type = list(title = "TYPE", title_gp = gpar(fontsize = 14),
                                               labels_gp = gpar(fontsize = 8))))
ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2",
    heatmap_legend_param = list(title = "Heatmap2", title_gp = gpar(fontsize = 8),
        labels_gp = gpar(fontsize = 14)))
ht1 + ht2

plot of chunk heatmap_list_advanced

You can specify break values and break labels (both for character values and numeric values) by at and labels in corresponding heatmap_legend_param and annotation_legend_param. Note at can also be character break values.

ha = HeatmapAnnotation(df = df, col = list(type = c("a" =  "red", "b" = "blue")),
    annotation_legend_param = list(type = list(title = "TYPE", title_gp = gpar(fontsize = 14),
        labels_gp = gpar(fontsize = 8), at = c("a", "b"), labels = c("A", "B"))))
ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha,
    heatmap_legend_param = list(at = c(-3, 0, 3), labels = c("-three", "zero", "+three")))
ht1 + ht2

plot of chunk self_define_heatmap_legend

If you have many levels in your annotation or matrix, you can put all levels into an array by specifying nrow or ncol:

ha_chr = rowAnnotation(chr = sample(paste0("chr", 1:20), nrow(mat), replace = TRUE),
    annotation_legend_param = list(chr = list(ncol = 2, title = "chromosome", title_position = "topcenter")),
    width = unit(5, "mm"))
ht1 = Heatmap(mat, name = "ht1")
ht1 + ha_chr

plot of chunk unnamed-chunk-1

Or put at bottom of the heatmap:

ha_chr = rowAnnotation(chr = sample(paste0("chr", 1:20), nrow(mat), replace = TRUE),
    annotation_legend_param = list(chr = list(nrow = 2, title = "chr", title_position = "leftcenter")),
    width = unit(5, "mm"))
ht1 = Heatmap(mat, name = "ht1", show_heatmap_legend = FALSE)
draw(ht1 + ha_chr, heatmap_legend_side = "bottom")

plot of chunk unnamed-chunk-2 If you want to order a discrete legend by column instead of row, use the direction argument:

ha_chr = rowAnnotation(chr = sample(paste0("chr", 1:20), nrow(mat), replace = TRUE),
    annotation_legend_param = list(chr = list(nrow = 2, title = "chr", title_position = "leftcenter", legend_direction = "vertical")),
    width = unit(5, "mm"))
ht1 = Heatmap(mat, name = "ht1", show_heatmap_legend = FALSE)
draw(ht1 + ha_chr, heatmap_legend_side = "bottom")

plot of chunk unnamed-chunk-3

Discrete color bar for can be used for continuous values, if you specify color_bar to discrete. For the simple annotation which contains continuous values, color_bar can also be set to discrete.

ha = HeatmapAnnotation(df = data.frame(value = runif(10)),
    col = list(value = colorRamp2(c(0, 1), c("white", "blue"))),
    annotation_legend_param = list(color_bar = "discrete", at = c(0, 0.5, 1)))
Heatmap(mat, name = "ht1", top_annotation = ha, heatmap_legend_param = list(color_bar = "discrete"))

plot of chunk unnamed-chunk-4

Some users prefer to put the legend at the bottom of heatmaps.

ht = Heatmap(mat, name = "ht1", heatmap_legend_param = list(legend_direction = "horizontal",
    legend_width = unit(5, "cm"), title_position = "lefttop"))
draw(ht, heatmap_legend_side = "bottom")

plot of chunk unnamed-chunk-5

Similarly, the height of the legend can be adjusted by legend_height if the legend is vertical.

Heatmap(mat, name = "ht1", heatmap_legend_param = list(legend_height = unit(5, "cm")))

plot of chunk unnamed-chunk-6

If you want to change default settings for all heatmaps/annotations, you can set it globally by ht_global_opt().

ht_global_opt(heatmap_legend_title_gp = gpar(fontsize = 16), annotation_legend_labels_gp = gpar(fontface = "italic"))
ha = HeatmapAnnotation(df = data.frame(value = runif(10)),
    col = list(value = colorRamp2(c(0, 1), c("white", "blue"))))
ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", heatmap_legend_param = list(title_gp = gpar(fontsize = 8)))
ht1 + ht2

plot of chunk unnamed-chunk-7

ht_global_opt(RESET = TRUE)

Add new legends

ComplexHeatmap only generates legends for heatmaps and simple annotations. Self-defined legends can be passed by heatmap_legend_list and annotation_legend_list as a list of grob objects.

grid package provides legendGrob() to construct a legend grob with certain style but styles are still limited. For advanced users, they can construct a legend grob totally from ground by frameGrob() and placeGrob().

ha = HeatmapAnnotation(points = anno_points(rnorm(10)))
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", top_annotation = ha, show_heatmap_legend = FALSE)
lgd = legendGrob(c("dots"), pch = 16)
draw(ht1 + ht2, annotation_legend_list = list(lgd))

plot of chunk self_defined_annotation_legend

From version 1.9.7, ComplexHeatmap package provides a Legend() function which can produce legends in grob formats (actually all legends in the package are implemented by Legend() function). In following example, we have several column annotations which contains points and we also want to show legends for these non-heatmap graphics.

ha = HeatmapAnnotation(points = anno_points(rnorm(10), gp = gpar(col = rep(2:3, each = 5))))
ht = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", top_annotation = ha)
lgd = Legend(at = c("class1", "class2"), title = "points", type = "points", legend_gp = gpar(col = 2:3))
draw(ht, annotation_legend_list = list(lgd))

plot of chunk unnamed-chunk-8

Also check this blog link for more demonstrations.

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] dendextend_1.9.0      dendsort_0.3.3        cluster_2.0.7-1       IRanges_2.16.0       
##  [5] S4Vectors_0.20.0      BiocGenerics_0.28.0   HilbertCurve_1.12.0   circlize_0.4.4       
##  [9] ComplexHeatmap_1.20.0 knitr_1.20            markdown_0.8         
## 
## loaded via a namespace (and not attached):
##  [1] mclust_5.4.1           Rcpp_0.12.19           mvtnorm_1.0-8          lattice_0.20-35       
##  [5] png_0.1-7              class_7.3-14           assertthat_0.2.0       mime_0.6              
##  [9] R6_2.3.0               GenomeInfoDb_1.18.0    plyr_1.8.4             evaluate_0.12         
## [13] ggplot2_3.1.0          highr_0.7              pillar_1.3.0           GlobalOptions_0.1.0   
## [17] zlibbioc_1.28.0        rlang_0.3.0.1          lazyeval_0.2.1         diptest_0.75-7        
## [21] kernlab_0.9-27         whisker_0.3-2          GetoptLong_0.1.7       stringr_1.3.1         
## [25] RCurl_1.95-4.11        munsell_0.5.0          compiler_3.5.1         pkgconfig_2.0.2       
## [29] shape_1.4.4            nnet_7.3-12            tidyselect_0.2.5       gridExtra_2.3         
## [33] tibble_1.4.2           GenomeInfoDbData_1.2.0 viridisLite_0.3.0      crayon_1.3.4          
## [37] dplyr_0.7.7            MASS_7.3-51            bitops_1.0-6           gtable_0.2.0          
## [41] magrittr_1.5           scales_1.0.0           stringi_1.2.4          XVector_0.22.0        
## [45] viridis_0.5.1          flexmix_2.3-14         bindrcpp_0.2.2         robustbase_0.93-3     
## [49] fastcluster_1.1.25     HilbertVis_1.40.0      rjson_0.2.20           RColorBrewer_1.1-2    
## [53] tools_3.5.1            fpc_2.1-11.1           glue_1.3.0             trimcluster_0.1-2.1   
## [57] DEoptimR_1.0-8         purrr_0.2.5            colorspace_1.3-2       GenomicRanges_1.34.0  
## [61] prabclus_2.2-6         bindr_0.1.1            modeltools_0.2-22