# Making A List of Heatmaps

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

Date: 2017-04-24

A list of heatmaps can improve visualization of the correspondence between multiple data sources. In this vignette, we will discuss configurations for making a list of heatmaps and you can see more real-world examples in the Examples vignette as well as in the supplementaries of the ComplexHeatmap paper.

## Heatmap concatenation

You can arrange more than one heatmaps on the plot from left to right. Actually, one single heatmap is just a special case of the heatmap list of length one.

`Heatmap()` is actually a class constructor function for a single heatmap. If more than one heatmaps are to be combined, users can append one heatmap to the other by `+` operator.

    library(ComplexHeatmap)

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

    mat2 = matrix(rnorm(60, 2), 6, 10)
    mat2 = rbind(mat2, matrix(rnorm(60, -2), 6, 10))
    rownames(mat2) = paste0("R", 1:12)
    colnames(mat2) = paste0("C", 1:10)

    ht1 = Heatmap(mat1, name = "ht1")
    ht2 = Heatmap(mat2, name = "ht2")
    class(ht1)

    ## [1] "Heatmap"
    ## attr(,"package")
    ## [1] "ComplexHeatmap"

    class(ht2)

    ## [1] "Heatmap"
    ## attr(,"package")
    ## [1] "ComplexHeatmap"

    ht1 + ht2

Under default mode, dendrograms from the second heatmap will be removed and row orders will be same as the first one.

The returned value of addition of two heatmaps is a `HeatmapList` object. Directly calling `ht_list` object will call `draw()` method with default settings. With explicitly calling `draw()` method, you can have more controls e.g. on the legend and titles.

    ht_list = ht1 + ht2
    class(ht_list)

    ## [1] "HeatmapList"
    ## attr(,"package")
    ## [1] "ComplexHeatmap"

You can append any number of heatmaps to the heatmap list. Also you can append a heatmap list to a heatmap list.

    ht1 + ht1 + ht1
    ht1 + ht_list
    ht_list + ht1
    ht_list + ht_list

`NULL` can be added to the heatmap list. It would be convinient when users want to construct a heatmap list through a `for` loop.

    ht_list = NULL
    for(s in sth) {
        ht_list = ht_list + Heatmap(...)
    }

## Titles

A heatmap list also has titles which are independent to the heatmap titles.

    ht1 = Heatmap(mat1, name = "ht1", row_title = "Heatmap 1", column_title = "Heatmap 1")
    ht2 = Heatmap(mat2, name = "ht2", row_title = "Heatmap 2", column_title = "Heatmap 2")
    ht_list = ht1 + ht2

    draw(ht_list, row_title = "Two heatmaps, row title", row_title_gp = gpar(col = "red"),
        column_title = "Two heatmaps, column title", column_title_side = "bottom")

## Gaps between heatmaps

The gaps between heatmaps can be set by `gap` argument with a `unit` object.

    draw(ht_list, gap = unit(1, "cm"))

    draw(ht_list + ht_list, gap = unit(c(3, 6, 9, 0), "mm"))

    ## Warning in .local(object, ...): Heatmap/row annotaiton names are duplicated: ht1, ht2

## Size of heatmaps

The width for some (not all) heatmaps can be set to a fixed width.

    ht1 = Heatmap(mat1, name = "ht1", column_title = "Heatmap 1")
    ht2 = Heatmap(mat2, name = "ht2", column_title = "Heatmap 2", width = unit(5, "cm"))
    ht1 + ht2

or the width can be set as relative values. Please not in this case, `width` for all heatmaps should be set (relative width and fixed width can be mixed).

    ht1 = Heatmap(mat1, name = "ht1", column_title = "Heatmap 1", width = 2)
    ht2 = Heatmap(mat2, name = "ht2", column_title = "Heatmap 2", width = 1)
    ht1 + ht2

## Auto adjustment

There are some automatic adjustment if more than one heatmaps are plotted. There should be a main heatmap which by default is the first one. Some settings for the remaining heatmaps will be modified to the settings in the main heatmap. The adjustment are:

- row clusters are removed.
- row titles are removed.
- if the main heatmap is split by rows, all remaining heatmaps will also be split by same levels as the main one.

The main heatmap can be specified by `main_heatmap` argument. The value can be a numeric index or the name of the heatmap (of course, you need to set the heatmap name when you create the `Heatmap` object).

    ht1 = Heatmap(mat1, name = "ht1", column_title = "Heatmap 1", km = 2)
    ht2 = Heatmap(mat2, name = "ht2", column_title = "Heatmap 2")
    ht1 + ht2

    # note we changed the order of `ht1` and `ht2`
    draw(ht2 + ht1)

    # here although `ht1` is the second heatmap, we specify `ht1` to be
    # the main heatmap by explicitely setting `main_heatmap` argument
    draw(ht2 + ht1, main_heatmap = "ht1")

If there is no row clustering in the main heatmap, all other heatmaps have no row clustering neither.

    ht1 = Heatmap(mat1, name = "ht1", column_title = "Heatmap 1", cluster_rows = FALSE)
    ht2 = Heatmap(mat2, name = "ht2", column_title = "Heatmap 2")
    ht1 + ht2

## Change graphic parameters simultaneously

`ht_global_opt()` can set graphic parameters for dimension names and titles as global settings.

    ht_global_opt(heatmap_row_names_gp = gpar(fontface = "italic"),
                  heatmap_column_names_gp = gpar(fontsize = 14))
    ht1 = Heatmap(mat1, name = "ht1", column_title = "Heatmap 1")
    ht2 = Heatmap(mat2, name = "ht2", column_title = "Heatmap 2")
    ht1 + ht2

    ht_global_opt(RESET = TRUE)

Following are global settings supported by `ht_global_opt()`. By this function, you can also control settings for the legends.

    names(ht_global_opt())

    ##  [1] "heatmap_row_names_gp"             "heatmap_column_names_gp"
    ##  [3] "heatmap_row_title_gp"             "heatmap_column_title_gp"
    ##  [5] "heatmap_legend_title_gp"          "heatmap_legend_title_position"
    ##  [7] "heatmap_legend_labels_gp"         "heatmap_legend_grid_height"
    ##  [9] "heatmap_legend_grid_width"        "heatmap_legend_grid_border"
    ## [11] "annotation_legend_title_gp"       "annotation_legend_title_position"
    ## [13] "annotation_legend_labels_gp"      "annotation_legend_grid_height"
    ## [15] "annotation_legend_grid_width"     "annotation_legend_grid_border"
    ## [17] "fast_hclust"

## Retrieve orders and dendrograms

`row_order`, `column_order`, `row_dend` and `column_dend` can be used to retrieve corresponding information from the heatmaps. The usage is straightforward by following example:

    ht_list = ht1 + ht2
    row_order(ht_list)

    ## [[1]]
    ##  [1]  8  3  4  1  5  7  2  6  9 11 10 12

    column_order(ht_list)

    ## $ht1
    ##  [1]  5  1  3  2  7  9  6 10  8  4
    ##
    ## $ht2
    ##  [1]  9  4  6  7  8  1  5 10  3  2

    row_dend(ht_list)

    ## [[1]]
    ## 'dendrogram' with 2 branches and 12 members total, at height 16.14288

    column_dend(ht_list)

    ## $ht1
    ## 'dendrogram' with 2 branches and 10 members total, at height 8.069474
    ##
    ## $ht2
    ## 'dendrogram' with 2 branches and 10 members total, at height 6.883646

If `ht_list` has not been drawn yet, calling these four functions would be a little bit slow if the matrix are huge. But if `ht_list` is already drawn which means clustering is already applied to the matrix, it will be fast to retrieve these information.

    ht_list = draw(ht1 + ht2)
    row_order(ht_list)
    column_order(ht_list)
    row_dend(ht_list)
    column_dend(ht_list)

## Heatmap list with row annotations

Row annotations can be added to the heatmap list, please see Heatmap Annotation for more explanations.

## Modify row orders/clustering in main heatmap

From version 1.11.1, settings for row order/clustering for the main heatmap can be directly set in `draw()` method. This makes it convinient to switch main heatmaps without modifying settings in individual heatmaps. Actually settings specified in `draw()` will overwrite corresponding settings in the main heatmap.

    split = rep(c("a", "b"), each = 6)
    ht_list = Heatmap(mat1, name = "mat1", cluster_rows = FALSE, column_title = "mat1") +
              Heatmap(mat2, name = "mat2", cluster_rows = FALSE, column_title = "mat2")
    draw(ht_list, main_heatmap = "mat1", split = split)

    draw(ht_list, main_heatmap = "mat2", km = 2, cluster_rows = TRUE)

    draw(ht_list, cluster_rows = TRUE, main_heatmap = "mat1", show_row_dend =TRUE)

    draw(ht_list, cluster_rows = TRUE, main_heatmap = "mat2", show_row_dend =TRUE)

## Session info

    sessionInfo()

    ## R version 3.4.0 (2017-04-21)
    ## Platform: x86_64-w64-mingw32/x64 (64-bit)
    ## Running under: Windows Server 2012 R2 x64 (build 9600)
    ##
    ## Matrix products: default
    ##
    ## locale:
    ## [1] LC_COLLATE=C                           LC_CTYPE=English_United States.1252
    ## [3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C
    ## [5] LC_TIME=English_United States.1252
    ##
    ## attached base packages:
    ##  [1] stats4    parallel  grid      stats     graphics  grDevices utils     datasets  methods
    ## [10] base
    ##
    ## other attached packages:
    ##  [1] dendextend_1.5.2      dendsort_0.3.3        cluster_2.0.6         HilbertCurve_1.6.0
    ##  [5] GenomicRanges_1.28.0  GenomeInfoDb_1.12.0   IRanges_2.10.0        S4Vectors_0.14.0
    ##  [9] BiocGenerics_0.22.0   circlize_0.3.10       ComplexHeatmap_1.14.0 knitr_1.15.1
    ## [13] markdown_0.8
    ##
    ## loaded via a namespace (and not attached):
    ##  [1] fastcluster_1.1.22      shape_1.4.2             modeltools_0.2-21       GetoptLong_0.1.6
    ##  [5] kernlab_0.9-25          lattice_0.20-35         colorspace_1.3-2        viridisLite_0.2.0
    ##  [9] prabclus_2.2-6          RColorBrewer_1.1-2      fpc_2.1-10              GenomeInfoDbData_0.99.0
    ## [13] plyr_1.8.4              robustbase_0.92-7       stringr_1.2.0           zlibbioc_1.22.0
    ## [17] munsell_0.4.3           gtable_0.2.0            GlobalOptions_0.0.11    mvtnorm_1.0-6
    ## [21] evaluate_0.10           flexmix_2.3-13          class_7.3-14            highr_0.6
    ## [25] DEoptimR_1.0-8          trimcluster_0.1-2       Rcpp_0.12.10            scales_0.4.1
    ## [29] diptest_0.75-7          XVector_0.16.0          mime_0.5                gridExtra_2.2.1
    ## [33] rjson_0.2.15            ggplot2_2.2.1           png_0.1-7               stringi_1.1.5
    ## [37] tools_3.4.0             bitops_1.0-6            HilbertVis_1.34.0       magrittr_1.5
    ## [41] lazyeval_0.2.0          RCurl_1.95-4.8          tibble_1.3.0            whisker_0.3-2
    ## [45] MASS_7.3-47             viridis_0.4.0           mclust_5.2.3            nnet_7.3-12
    ## [49] compiler_3.4.0