--- title: "Heatmap Layout" output: bookdown::html_document2: base_format: rmarkdown::html_vignette number_sections: no fig_caption: yes fig_width: 7 fig_height: 5 params: mode: !r if (endsWith(as.character(desc::desc_get_version()), '9000')) 'devel' else 'release' release: "https://yunuuuu.github.io/ggalign" devel: "https://yunuuuu.github.io/ggalign/dev" vignette: > %\VignetteIndexEntry{Heatmap Layout} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} pkgdown: as_is: true --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r echo=FALSE} mode <- params$mode url <- params[[mode]] ``` The `heatmap_layout()`/`ggheatmap()` function provides a powerful way to create customizable heatmaps in R using `ggplot2`. This vignette will guide you through its usage. # input data The data input can be a numeric or character vector, a data frame, and any other data which can be converted into a matrix by `fortify_matrix()`. ```{r setup_data} set.seed(123) small_mat <- matrix(rnorm(81), nrow = 9) rownames(small_mat) <- paste0("row", seq_len(nrow(small_mat))) colnames(small_mat) <- paste0("column", seq_len(ncol(small_mat))) ``` ```{r matrix} library(ggalign) ggheatmap(small_mat) ``` # heatmap body For `ggplot2` usage, the matrix input will be converted into a long formated data frame when drawing. The default mapping will use `aes(.data$.x, .data$.y)`, but can be controlled using `mapping` argument. The data in the underlying ggplot object contains following columns: - `.xpanel` and `.ypanel`: the column and row panel - `.x` and `.y`: the `x` and `y` coordinates - `.row_names` and `.column_names`: A factor of the row and column names of the original matrix (only applicable when names exist). - `.row_index` and `.column_index`: the row and column index of the original matrix. - `value`: the actual matrix value. You can treat the `ggheatmap()`/`heatmap_layout()` object as a standard `ggplot2` object with default mapping and data. This means you can add `ggplot2` layers or elements just like in any `ggplot` object. ```{r} ggheatmap(small_mat) + geom_point() + scale_fill_viridis_c() ``` By default, `ggheatmap()`/`heatmap_layout()` adds a heatmap layer. If the matrix has more than 20,000 cells (`nrow * ncol > 20000`), it uses `geom_raster()` for performance efficiency; for smaller matrices, `geom_tile()` is used. You can explicitly choose the layer by providing a single string (`"raster"` or `"tile"`) in the `filling` argument. ```{r} ggheatmap(small_mat, filling = "raster") ``` ```{r} ggheatmap(small_mat, filling = "tile") ``` If you set `filling = NULL`, a blank heatmap will be drawn, allowing for customized filling geoms. In this way, you must set `fill` mapping manually. ```{r} ggheatmap(small_mat, filling = NULL) + geom_tile(aes(fill = value), color = "black", width = 0.9, height = 0.9) ``` A heatmap pie charts: ```{r} set.seed(123) ggheatmap(matrix(runif(360L), nrow = 20L), filling = NULL) + geom_pie(aes(angle = value * 360, fill = value)) ``` If you want more complex customization of pie charts, try using `ggforce::geom_arc_bar()` instead. You can use external packages like [ggrastr](https://github.com/VPetukhov/ggrastr) or [ggfx](https://ggfx.data-imaginist.com/reference/with_raster.html) to rasterize the heatmap body. Additionally, [ggfx](https://ggfx.data-imaginist.com/reference/with_raster.html) offers many image filters that can be applied to ggplot2 layers. ```{r eval=rlang::is_installed("ragg")} ggheatmap(small_mat, filling = FALSE) + ggrastr::rasterise(geom_tile(aes(fill = value)), dev = "ragg") ``` You can rasterize all plots in the layout directly with `ggrastr::rasterise()`. This method works for both `ggheatmap()`/`quad_layout()` and `ggstack()` objects. ```{r eval=rlang::is_installed("ragg")} ggrastr::rasterise(ggheatmap(small_mat), dev = "ragg") ``` # heatmap annotations A heatmap typically has two observation axes (rows and columns), which can be reordered or supplemented with additional information. In `ggheatmap()`, annotations are handled by a `stack_layout()` object, specifically `stack_align()`, which aligns the observations. This object can hold multiple plots and can be positioned at the top, left, bottom, or right of the heatmap. Note that `ggalign` use the concept of `"number of observations"` in the [vctrs](https://vctrs.r-lib.org/reference/vec_size.html) package or `NROW()` function. When aligning the observations, you must ensure the number of observations is equal. For column annotations, the layout matrix will be transposed before use. This is necessary because column annotations use heatmap columns as observations, but we need rows. ## `quad_anno()` By default, `heatmap_layout()`/`ggheatmap()` do not initialize an active context, which means that all additions are directed within the heatmap body. You can use `quad_anno()` to set the active context, directing all subsequent additions to the specified annotation position. The `quad_anno()` function has the following aliases: - `anno_top`: A special case of `quad_anno` with `position = "top"`. - `anno_left`: A special case of `quad_anno` with `position = "left"`. - `anno_bottom`: A special case of `quad_anno` with `position = "bottom"`. - `anno_right`: A special case of `quad_anno` with `position = "right"`. The annotations allows for custom layout adjustments and the addition of various plot types. In the following example, `align_kmeans()` is used to group the columns into three panels. It doesn't matter if this is added to the top or bottom since it won't add a plot area: ```{r} ggheatmap(small_mat) + # we set the active context to the top annotation anno_top() + # we split the observations into 3 groups by kmeans align_kmeans(3L) ``` We can add any `align_*()` function to the annotation. For more details on `align_*()` functions, refer to [layout-customize](`r sprintf("%s/articles/layout-customize.html", url)`) and [layout-plot](`r sprintf("%s/articles/layout-plot.html", url)`). ```{r} ggheatmap(small_mat) + # in the heatmap body, we set the axis text theme theme(axis.text.x = element_text(angle = -60, hjust = 0)) + # we set the active context to the right annotation anno_right() + # in the right annotation, we add a dendrogram align_dendro(k = 3L) + # in the dendrogram, we add a point layer geom_point(aes(color = factor(branch))) ``` In this example: - `anno_right()` change the active context to the right of the heatmap. - `align_dendro(k = 3L)` adds a dendrogram to this right-side annotation context and sets itself as the active plot in the annotation stack. - `geom_point(aes(color = factor(branch)))` is then added to this active plot within the annotation stack, here, it means the `align_dendro()` plot. ## `quad_active()` To remove the active context and redirect additions back to the heatmap body, you can use `quad_active()`. ```{r} ggheatmap(small_mat) + # we set the active context to the top annotation anno_top() + # we split the observations into 3 groups by kmeans align_kmeans(3L) + # remove any active annotation quad_active() + # set fill color scale for the heatmap body scale_fill_viridis_c() ``` ## `quad_switch()`/`hmanno()` We also provide `quad_switch()`/`hmanno()` (heatmap annotation) which integrates `quad_active()` and `quad_anno()` into one function for ease of use. Feel free to use any of these functions to streamline your annotation process. ```{r} ggheatmap(small_mat) + # we set the active context to the top annotation quad_switch("t") + # we split the observations into 3 groups by kmeans align_kmeans(3L) + # remove any active annotation quad_switch() + # set fill color scale for the heatmap body scale_fill_viridis_c() ``` ```{r} ggheatmap(small_mat) + # we set the active context to the top annotation hmanno("t") + # we split the observations into 3 groups by kmeans align_kmeans(3L) + # remove any active annotation hmanno() + # set fill color scale for the heatmap body scale_fill_viridis_c() ``` You may wonder about the prefix `quad_`. The `ggheatmap()` function is a specialized version of `quad_layout()`, designed to simplify the creation of heatmap plots by integrating essential elements for a standard heatmap layout. Both `quad_anno()` and `quad_active()` are functions designed for `quad_layout()`. # Plot Size ## Heatmap Body Size You can specify the relative sizes of the heatmap body using the `width` and `height` arguments in the `ggheatmap()` function. ```{r} ggheatmap(small_mat, height = 2) + scale_fill_viridis_c() + anno_top() + align_dendro() ``` Alternatively, the `quad_active()` function allows you to control the heatmap body sizes. ```{r} ggheatmap(small_mat) + quad_active(height = 2) + scale_fill_viridis_c() + anno_top() + align_dendro() ``` ## Annotation Stack Size The `quad_anno()` function allows you to control the total annotation stack size. The `size` argument controls the relative width (for left and right annotations) or height (for top and bottom annotations) of the whole annotation stack. ```{r} ggheatmap(small_mat) + scale_fill_viridis_c() + anno_top(size = 1) + align_dendro() ``` You can also specify it as an absolute size using `unit()`: ```{r} ggheatmap(small_mat) + scale_fill_viridis_c() + anno_top(size = unit(30, "mm")) + align_dendro() ``` ## Single Plot Size All `align_*()`/`ggfree()` functions that add plots in the annotation stack have a `size` argument to control the relative `width` (for left and right annotations) or `height` (for top and bottom annotations) of the single plot in the annotation stack. ```{r} ggheatmap(small_mat) + scale_fill_viridis_c() + anno_left(size = 0.2) + ggalign(data = rowSums, aes(x = value), size = unit(10, "mm")) + geom_bar( aes(y = .y, fill = factor(.y)), stat = "identity", orientation = "y" ) + scale_fill_brewer(palette = "Set1", guide = "none") ``` # Session information ```{r} sessionInfo() ```