vignettes/s6.heatmap_decoration.Rmd
5ab2cb81
 <!--
 %\VignetteEngine{knitr}
60bf2b85
 %\VignetteIndexEntry{6. Heatmap Decoration}
5ab2cb81
 -->
 
 Heatmap Decoration
 ========================================
 
 **Author**: Zuguang Gu ( z.gu@dkfz.de )
 
 **Date**: `r Sys.Date()`
 
 -------------------------------------------------------------
 
 ```{r global_settings, echo = FALSE, message = FALSE}
 library(markdown)
 options(markdown.HTML.options = c(options('markdown.HTML.options')[[1]], "toc"))
 
 library(knitr)
 knitr::opts_chunk$set(
     error = FALSE,
     tidy  = FALSE,
     message = FALSE,
     fig.align = "center",
     fig.width = 5,
     fig.height = 5)
 options(markdown.HTML.stylesheet = "custom.css")
 
 options(width = 100)
 ```
 
 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.
 
 ```{r access_components, fig.width = 10, fig.height = 7, echo = 1:13}
 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)
 
 ht_list = ht1 + ht2 + rowAnnotation(bar = row_anno_barplot(rowMeans(mat)))
 draw(ht_list, row_title = "Heatmap list", column_title = "Heatmap list", 
     heatmap_legend_side = "right", annotation_legend_side = "left")
 
 library(GetoptLong)
 seekViewport("global"); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport("global_column_title"); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport("global_row_title"); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport("main_heatmap_list"); grid.rect(gp = gpar(fill = NA, col = "red"))
 for(heatmap_name in c("ht1", "ht2")) {
     seekViewport(qq("heatmap_@{heatmap_name}")); grid.rect(gp = gpar(fill = NA, col = "red"))
     for(i in 1:2) {
         seekViewport(qq("@{heatmap_name}_heatmap_body_@{i}")); grid.rect(gp = gpar(fill = NA, col = "red"))
         seekViewport(qq("@{heatmap_name}_row_names_@{i}")); grid.rect(gp = gpar(fill = NA, col = "red"))
     }
         
     seekViewport(qq("@{heatmap_name}_column_title")); grid.rect(gp = gpar(fill = NA, col = "red"))
455d2853
     seekViewport(qq("@{heatmap_name}_dend_column")); grid.rect(gp = gpar(fill = NA, col = "red"))
5ab2cb81
     seekViewport(qq("@{heatmap_name}_column_names")); grid.rect(gp = gpar(fill = NA, col = "red"))
     seekViewport(qq("legend_@{heatmap_name}")); grid.rect(gp = gpar(fill = NA, col = "red"))
 }
455d2853
 seekViewport(qq("ht1_dend_row_2")); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport(qq("ht1_dend_row_1")); grid.rect(gp = gpar(fill = NA, col = "red"))
5ab2cb81
 seekViewport(qq("ht1_row_title_1")); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport(qq("ht1_row_title_2")); grid.rect(gp = gpar(fill = NA, col = "red"))
 
 
 for(annotation_name in c("points", "type")) {
     seekViewport(qq("annotation_@{annotation_name}")); grid.rect(gp = gpar(fill = NA, col = "red"))
 }
 seekViewport(qq("annotation_bar_1")); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport(qq("annotation_bar_2")); grid.rect(gp = gpar(fill = NA, col = "red"))
 
 seekViewport(qq("legend_type")); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport(qq("legend_ht1")); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport(qq("legend_ht2")); grid.rect(gp = gpar(fill = NA, col = "red"))
 
 seekViewport("heatmap_legend"); grid.rect(gp = gpar(fill = NA, col = "red"))
 seekViewport("annotation_legend"); grid.rect(gp = gpar(fill = NA, col = "red"))
 ```
 
 The components (viewports) that have names are:
 
 - `global`: the viewport which contains the whole figure.
 - `global_column_title`: the viewport which contains column title for the heatmap list.
 - `global_row_title`: the viewport which contains row title for the heatmap list.
 - `main_heatmap_list`: the viewport which contains a list of heatmaps and row annotations.
 - `heatmap_@{heatmap_name}`: the viewport which contains a single heatmap
 - `annotation_@{annotation_name}`: the viewport which contains an annotation on columns.
 - `annotation_@{annotation_name}_@{i}`: for row annotations
 - `@{heatmap_name}_heatmap_body_@{i}`: the heatmap body.
 - `@{heatmap_name}_column_title`: column title for a single heatmap.
 - `@{heatmap_name}_row_title_@{i}`: since a heatmap body may be splitted into several parts. `@{i}` is the index of the row slice.
455d2853
 - `@{heatmap_name}_dend_row_@{i}`: dendrogram for ith row slice.
 - `@{heatmap_name}_dend_column`: dendrogram on columns
5ab2cb81
 - `@{heatmap_name}_row_names_@{i}`: the viewport which contains row names.
 - `@{heatmap_name}_column_names`: the viewport which contains column names.
 - `heatmap_legend`: the viewport which contains all heatmap legends.
 - `legend_@{heatmap_name}`: the viewport which contains a single heatmap legend.
 - `annotation_legend`: the viewport which contains all annotation legends.
 - `legend_@{annotation_name}`: the viewport which contains a single annotation legend.
 
 ## decorate_* functions
 
e0b7d4e2
 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.
5ab2cb81
 
 Following code add annotation names, mark one grid in the heatmap and seperate the first column clusters with two rectangles.
 
 ```{r components, fig.width = 10, fig.height = 7}
63a2fcf7
 ht_list = draw(ht_list, row_title = "Heatmap list", column_title = "Heatmap list", 
5ab2cb81
     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)
 
7b914edf
 decorate_column_dend("ht1", {
63a2fcf7
     tree = column_dend(ht_list)$ht1
60bf2b85
     ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]
5ab2cb81
 
     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))
7b914edf
 })
5ab2cb81
 
7b914edf
 decorate_row_names("ht2", {
5ab2cb81
     grid.rect(gp = gpar(fill = "#FF000040"))
7b914edf
 }, slice = 2)
5ab2cb81
 
7b914edf
 decorate_row_title("ht1", {
5ab2cb81
     grid.rect(gp = gpar(fill = "#00FF0040"))
7b914edf
 }, slice = 1)
69869b05
 
 decorate_annotation("points", {
     grid.lines(c(0, 1), unit(c(0, 0), "native"), gp = gpar(col = "red"))
 })
5ab2cb81
 ```
 
69869b05
 For annotations which are created by `anno_points()`, `anno_barplot()` and `anno_boxplot()`, "native" unit
 can be used in the decoration code.
 
5ab2cb81
 ## 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
f6325167
 would makes the adjustment of the heatmap layout difficult. `HeatmapAnnotation()` provides a 
 not-so-perfect [solution](s4.heatmap_annotation.html#toc_11) for adding annotation names, however, since you can go to any component 
5ab2cb81
 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,
e0b7d4e2
 it will be exceeding the figure region (but this problem can be solved by some tricks, see the 
 [**Examples**](s9.examples.html) vignette).
5ab2cb81
 
 ```{r annotation_title}
 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")
     })
 }
 ```
 
 ## 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:
 
 ```{r, density}
 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)
 ```
 
 ## Session info
 
 ```{r}
 sessionInfo()
 ```