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.
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()
.
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.
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.
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.
ggheatmap(small_mat, filling = NULL) +
geom_tile(aes(fill = value), color = "black", width = 0.9, height = 0.9)
A heatmap pie charts:
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.
When working with large heatmaps, it’s often beneficial to rasterize
the heatmap body layer. You can achieve this by using the
raster_magick()
function. By default, the res
will match the resolution of the current device, but specifying a
different value can reduce the resolution of the rasterized heatmap
body.
For raster image post-processing, similar to the approach in
ComplexHeatmap
, you can leverage the
raster_magick()
function. This function uses the
magick
package to apply custom image resizing with filters.
Based on a rough testing, rasterization becomes advantageous for
heatmaps with more than 5000 x 5000
cells compared to using
pure geom_raster()
.
ggheatmap(small_mat, filling = NULL) +
# Use `magick::filter_types()` to check available `filter` arguments
raster_magick(geom_raster(aes(fill = value)),
magick = function(image) {
magick::image_resize(image,
# we resize to the 50% of width
geometry = "50%x", filter = "Lanczos"
)
}
)
Note: When using magick::image_resize()
, you should
specify the geometry
argument to resize the image. If only
the filter
is specified, it will only distort the image
data (though subtle). For more information on image resizing, refer to
ImageMagick’s resize
documentation.
You can rasterize all plots in the layout directly with
raster_magick()
. This method works for both
ggheatmap()
/quad_layout()
and
ggstack()
/stack_layout()
objects.
Additionally, You can use external packages like ggrastr or ggfx to rasterize the heatmap body.
ggheatmap(small_mat, filling = FALSE) +
ggrastr::rasterise(geom_tile(aes(fill = value)), dev = "ragg")
You can also rasterize all plots in the layout directly with
ggrastr::rasterise()
. This method works for both
ggheatmap()
/quad_layout()
and
ggstack()
/stack_layout()
objects. Indeed, the
core code of raster_magick()
was adopted from
ggrastr::rasterise()
.
Furthermore, ggfx offers many image filters that can be applied to ggplot2 layers.
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 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:
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)
#> → heatmap built with `geom_tile()`
We can add any align_*()
function to the annotation. For
more details on align_*()
functions, refer to
vignette("layout-customize")
and
vignette("layout-plot")
.
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)))
#> → heatmap built with `geom_tile()`
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()
.
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()
#> → heatmap built with `geom_tile()`
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.
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()
#> → heatmap built with `geom_tile()`
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()
#> → heatmap built with `geom_tile()`
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()
.
You can specify the relative sizes of the heatmap body using the
width
and height
arguments in the
ggheatmap()
function.
ggheatmap(small_mat, height = 2) +
anno_top() +
align_dendro()
#> → heatmap built with `geom_tile()`
Alternatively, the quad_active()
function allows you to
control the heatmap body sizes.
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.
You can also specify it as an absolute size using
unit()
:
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.
sessionInfo()
#> R version 4.4.2 (2024-10-31)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] ggalign_0.0.5.9000 ggplot2_3.5.1 bookdown_0.41
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 jsonlite_1.8.9 compiler_4.4.2 Rcpp_1.0.13-1
#> [5] ggbeeswarm_0.7.2 magick_2.8.5 jquerylib_0.1.4 textshaping_0.4.0
#> [9] systemfonts_1.1.0 scales_1.3.0 yaml_2.3.10 fastmap_1.2.0
#> [13] R6_2.5.1 labeling_0.4.3 knitr_1.49 tibble_3.2.1
#> [17] maketools_1.3.1 munsell_0.5.1 RColorBrewer_1.1-3 bslib_0.8.0
#> [21] pillar_1.9.0 rlang_1.1.4 utf8_1.2.4 cachem_1.1.0
#> [25] xfun_0.49 sass_0.4.9 sys_3.4.3 viridisLite_0.4.2
#> [29] cli_3.6.3 withr_3.0.2 magrittr_2.0.3 digest_0.6.37
#> [33] grid_4.4.2 beeswarm_0.4.0 lifecycle_1.0.4 vipor_0.4.7
#> [37] ggrastr_1.0.2 vctrs_0.6.5 evaluate_1.0.1 glue_1.8.0
#> [41] farver_2.1.2 ragg_1.3.3 buildtools_1.0.0 fansi_1.0.6
#> [45] colorspace_2.1-1 rmarkdown_2.29 tools_4.4.2 pkgconfig_2.0.3
#> [49] htmltools_0.5.8.1