stack_layout()
put plots horizontally or vertically. You
can also use the alias ggstack()
.
Input data
The data input can be a numeric or character vector, a matrix, and a data frame. Simple vector will be converted into a one column matrix.
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)))
By default, ggstack()
will create the layout, but no
plot will be drawn until you add a plot element:
ggstack(small_mat)
We can add any align_*()
function to customize the
layout or integrate plots into the stack.
ggstack(small_mat) + align_dendro()
ggstack(small_mat) +
align_kmeans(centers = 3L) +
ggalign(data = rowSums) +
geom_bar(aes(value, fill = .panel), orientation = "y", stat = "identity") +
facet_grid(switch = "y") +
theme(strip.text = element_text()) +
align_dendro(aes(color = branch))
By default, ggstack()
arranges the plots horizontally.
To change the direction to vertical, use the direction
argument:
ggstack(small_mat, "v") + align_dendro()
Note that vertical stack take the
x-axis
as the observations, but horizontal stack take they-axis
as the observations.
Data frame Input
Unlike heatmap_layout()
/ggheatmap()
, data
frames are not automatically converted into a matrix within
ggstack()
.
When using data frames, be cautious as many align_*()
functions only accept matrix. If the necessary data is not explicitly
provided to an align_*()
function, the data frame from
ggstack()
will be passed to the function and internally
converted into a matrix, which may result in missing values.
An exception is the align_gg()
/ggalign()
function, which can handle both matrix and data frames. When the input
is a matrix (or a simple vector), it will be transformed into a
long-format data frame. When the input is a data frame, only the
necessary panel and axis information will be added to the data
frame.
ggstack(mtcars) +
ggalign(aes(mpg)) +
geom_point()
Note align_gg()
/ggalign()
always applies a
default mapping for the parallel axes of the data index within the
layout. This mapping is aes(y = .data$.y)
for horizontal
stack and aes(x = .data$.x)
for vertical stack. So here we
only provide mapping for the x-axis
.
For more information on adding plots, refer to the vignette:
vignette("layout-plot")
.
Heatmap plot
Besides the align_*()
functions, we can also add the
heatmap_layout()
/ggheatmap()
into the stack
layout.
As mentioned earlier, vertical stacks use the x-axis
for
observations, while horizontal stacks use the y-axis
.
However, heatmap layouts always use the y-axis for observations. When a
heatmap layout is added to a vertical stack layout, the inherited data
is automatically converted to a matrix and transposed before use.
Once a heatmap layout is added, any further elements you add will be
applied to this heatmap layout. You can include align_*
elements or any ggplot2 components for the heatmap.
ggstack(small_mat) +
ggheatmap() +
scale_fill_viridis_c()
#> → heatmap built with `geom_tile()`
If you’d like to add elements to the stack layout rather than the
heatmap layout, you can easily switch from the heatmap layout to the
stack layout using stack_active()
.
ggstack(small_mat) +
ggheatmap() +
scale_fill_viridis_c() +
stack_active() +
ggalign(data = rowSums) +
geom_bar(aes(value), fill = "red", orientation = "y", stat = "identity")
#> → heatmap built with `geom_tile()`
One exception is the heatmap layout itself, which cannot be added to
another heatmap layout. Therefore, you can directly add a heatmap layout
to the stack layout without using stack_active()
.
ggstack(small_mat, "v") +
ggheatmap() +
ggheatmap() &
scale_fill_viridis_c()
#> → heatmap built with `geom_tile()`
#> → heatmap built with `geom_tile()`
Control sizes
A length of 3 sizes should be provided in ggstack()
when
putting a heatmap with flank annotation into the stack layout. For
vertical stacks, this means heatmaps with left or right annotations; for
horizontal stacks, this means heatmaps with top or bottom annotations.
The first size controls the relative width/height of the left or top
annotation, the second controls the relative size of the heatmap body
width/height, and the third controls the relative width/height of the
right or bottom annotation.
By default the three rows/columns will have equal sizes.
ggstack(small_mat, "v") +
ggheatmap() +
scale_fill_viridis_c() +
hmanno("l") +
align_dendro(aes(color = .panel), k = 3L) +
hmanno("r") +
ggalign(data = rowSums) +
geom_bar(aes(value, fill = .panel), orientation = "y", stat = "identity") +
ggheatmap()
#> → heatmap built with `geom_tile()`
#> → heatmap built with `geom_tile()`
# the left annotation, will have a relative size 1
# the heatmap body will have a relative width 2
# the right annotation will have a relative size 1
ggstack(small_mat, "v", sizes = c(1, 2, 1)) +
ggheatmap() +
scale_fill_viridis_c() +
hmanno("l") +
align_dendro(aes(color = .panel), k = 3L) +
hmanno("r") +
ggalign(data = rowSums) +
geom_bar(aes(value, fill = .panel), orientation = "y", stat = "identity") +
ggheatmap()
#> → heatmap built with `geom_tile()`
#> → heatmap built with `geom_tile()`
In this way, heatmap body width/height specified in
hmanno()
or ggheatmap()
won’t work.
ggstack(small_mat, "v") +
ggheatmap(.width = unit(2, "null")) + # not work
scale_fill_viridis_c() +
hmanno("l") +
align_dendro(aes(color = .panel), k = 3L) +
hmanno("r") +
ggalign(data = rowSums) +
geom_bar(aes(value, fill = .panel), orientation = "y", stat = "identity") +
ggheatmap(.width = unit(2, "null")) # not work
#> → heatmap built with `geom_tile()`
#> → heatmap built with `geom_tile()`
By default the flank annotation will fill the whole stack flank, but
we can still control the size of heatmap annotation in
hmanno()
.
ggstack(small_mat, "v") +
ggheatmap() +
scale_fill_viridis_c() +
# the left annotation will have a total size 2cm
hmanno("l", size = unit(2, "cm")) +
align_dendro(aes(color = .panel), k = 3L) +
hmanno("r") +
ggalign(data = rowSums) +
geom_bar(aes(value, fill = .panel), orientation = "y", stat = "identity") +
ggheatmap()
#> → heatmap built with `geom_tile()`
#> → heatmap built with `geom_tile()`
You can also use npc
unit.
ggstack(small_mat, "v") +
ggheatmap() +
scale_fill_viridis_c() +
# the left annotation will have a total width 1/2 npc
hmanno("l", size = unit(0.5, "npc")) +
align_dendro(aes(color = .panel), k = 3L) +
hmanno("r") +
ggalign(data = rowSums) +
geom_bar(aes(value, fill = .panel), orientation = "y", stat = "identity") +
ggheatmap()
#> → heatmap built with `geom_tile()`
#> → heatmap built with `geom_tile()`
Session information
sessionInfo()
#> R version 4.4.1 (2024-06-14)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 22.04.5 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.20.so; LAPACK version 3.10.0
#>
#> locale:
#> [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
#> [4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
#> [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
#> [10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] ggalign_0.0.4.9000 ggplot2_3.5.1
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.5 jsonlite_1.8.9 dplyr_1.1.4 compiler_4.4.1
#> [5] highr_0.11 tidyselect_1.2.1 jquerylib_0.1.4 systemfonts_1.1.0
#> [9] scales_1.3.0 textshaping_0.4.0 yaml_2.3.10 fastmap_1.2.0
#> [13] R6_2.5.1 labeling_0.4.3 generics_0.1.3 knitr_1.48
#> [17] tibble_3.2.1 desc_1.4.3 munsell_0.5.1 bslib_0.8.0
#> [21] pillar_1.9.0 rlang_1.1.4 utf8_1.2.4 cachem_1.1.0
#> [25] xfun_0.48 fs_1.6.4 sass_0.4.9 viridisLite_0.4.2
#> [29] cli_3.6.3 pkgdown_2.1.1 withr_3.0.1 magrittr_2.0.3
#> [33] digest_0.6.37 grid_4.4.1 lifecycle_1.0.4 vctrs_0.6.5
#> [37] evaluate_1.0.1 glue_1.8.0 farver_2.1.2 ragg_1.3.3
#> [41] fansi_1.0.6 colorspace_2.1-1 rmarkdown_2.28 tools_4.4.1
#> [45] pkgconfig_2.0.3 htmltools_0.5.8.1