operator

library(ggalign)
set.seed(123)
small_mat <- matrix(rnorm(56), nrow = 8)
rownames(small_mat) <- paste0("row", seq_len(nrow(small_mat)))
colnames(small_mat) <- paste0("column", seq_len(ncol(small_mat)))

Operators

Addition operator

+: adds elements to the active plot in the active layout.

The + operator is straightforward and should be used as needed.

In quad_layout() (ggheatmap()/ggside()), four nested layouts are available for annotations: top, left, bottom, and right. If no active annotation is set, quad_layout() (ggheatmap()/ggside()) treat itself as the active layout. Since there is only one main plot in the quad_layout() (ggheatmap()/ggside()), the main plot is always treated as the active plot in this context.

# Initialize the heatmap; by default, no active annotation will be set.
# The active layout is the heatmap layout, and the active plot in the layout is
# the main plot.
ggheatmap(small_mat) +
    # Add elements to the main plot
    scale_fill_viridis_c() +
    # Change the active layout to the left annotation
    anno_left(size = 0.2) +
    # Add a dendrogram in the left annotation
    align_dendro() +
    # Change the active layout to the right annotation
    anno_right(size = 0.2) +
    # Add a dendrogram in the right annotation
    align_dendro()
#> → heatmap built with `geom_tile()`

In ggstack()/stack_layout(), a nested layout will only occur if you pass a quad_layout() into ggstack()/stack_layout(). If the active plot within the ggstack()/stack_layout() is quad_layout(), this quad_layout() is treated as the active layout, and the + operator will add elements to it, following the same principles as in quad_layout(). Otherwise, the ggstack()/stack_layout() itself is treated as the active layout, and the + operator will add elements directly to this plot.

stack_alignh(small_mat) +
    # the dendrogram will be added to the stack
    align_dendro() +
    # Add elements to the dendrogram
    geom_point() +
    # add a heamtap layout to the stack
    ggheatmap() +
    # the active layout is the heamtap layout
    # so following elements will be added to the heatmap layout
    theme(axis.text.x = element_text(angle = -60, hjust = 0)) +
    anno_right() +
    align_dendro()
#> → heatmap built with `geom_tile()`

logical AND operator

&: applies elements to all plots in the layout.

The & operator works similarly to patchwork, applying an element across all plots in a layout. Since & has lower precedence than +, it’s generally best to use it at the end of an expression or you should wrap it in parentheses when needed.

# Initialize the heatmap with color scales and annotations.
ggheatmap(small_mat) +
    scale_fill_viridis_c() +
    anno_left(size = 0.2) +
    # Add a dendrogram in the left annotation and split the dendrogram into 3 groups
    align_dendro(aes(color = branch), k = 3L) +
    anno_right(size = 0.2) +
    # Add a dendrogram in the right annotation and split the dendrogram into 3 groups
    align_dendro(aes(color = branch), k = 3L) &
    # Set color scale for all plots
    scale_color_brewer(palette = "Dark2")
#> → heatmap built with `geom_tile()`

Subtraction operator

The - operator is more powerful than the + operator, enabling flexible addition of elements to multiple plots. While its use might initially seem unintuitive, the reason behind this is that - shares the same precedence group as +, which allows it to seamlessly combine with +.

quad_layout()

If the active layout is the ggheatmap()/quad_layout() itself, the - operator behaves similarly to &. It applies the specified elements to all plots within the layout.

# Initialize the heatmap
ggheatmap(small_mat) +
    scale_fill_viridis_c() +
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    anno_right(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    # Remove any active annotation
    quad_active() -
    # Set color scale for all plots, since the active layout is the `ggheatmap()`/`quad_layout()`
    scale_color_brewer(palette = "Dark2")
#> → heatmap built with `geom_tile()`

If the active layout is the annotation stack, the - operator will only add the elements to all plots in the active annotation stack:

ggheatmap(small_mat) +
    scale_fill_viridis_c() +
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    align_dendro(aes(color = branch), k = 3L) -
    # Modify the the color scales of all plots in the left annotation
    scale_color_brewer(palette = "Dark2")
#> → heatmap built with `geom_tile()`

stack_layout()

If the active layout is the ggstack()/stack_layout() itself, - applies the elements to all plots in the layout except the nested ggheatmap()/quad_layout().

stack_alignv(small_mat) +
    align_dendro() +
    ggtitle("I'm from the parent stack") +
    ggheatmap() +
    # remove any active context
    stack_active() +
    align_dendro() +
    ggtitle("I'm from the parent stack") -
    # Modify the the color scales of all plots in the stack layout except the heatmap layout
    scale_color_brewer(palette = "Dark2") -
    # set the background of all plots in the stack layout except the heatmap layout
    theme(plot.background = element_rect(fill = "red"))
#> → heatmap built with `geom_tile()`

When the active layout is the nested ggheatmap()/quad_layout(), the - operator applies the elements to this nested layout, following the same principles as in the ggheatmap()/quad_layout().

Want apply elements for plots in both stack_layout() and the nested ggheatmap()/quad_layout() at the same time? refer to the following section.

with_quad

Along with the - operator, with_quad() can be used to modify the operated context of ggheatmap()/quad_layout().

This function accepts three arguments:

  1. x: The object to be applied using the - operator.
  2. position: A string containing one or more of "t", "l", "b", and "r" specifies the context for applying x.
  3. main: A single boolean value indicates whether x should also apply to the main plot within ggheatmap()/quad_layout(). Only used when position is not NULL.

quad_layout()

By default, if the active layout is the ggheatmap()/quad_layout() itself, with_quad() won’t do something special. But when the active context in ggheatmap()/quad_layout() is set to top or bottom, by wrapping object with with_quad(), the - operator will apply changes not only to that annotation but also to the opposite one (i.e., bottom if top is active, and vice versa). The same principle applies to the left and right annotation. In these cases, the object will also be applied to the main plot by default unless specified by main argument otherwise.

ggheatmap(small_mat) +
    scale_fill_viridis_c() +
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    # Change the active layout to the left annotation
    anno_top(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    anno_bottom(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) -
    # Modify the color scale of all plots in the bottom and the opposite annotation
    # in this way, the `main` argument by default would be `TRUE`
    with_quad(scale_color_brewer(palette = "Dark2", name = "Top and bottom"))
#> → heatmap built with `geom_tile()`

The position argument can be a string containing one or more of "t", "l", "b", and "r", indicating which annotation stack should be used as the context. When the position argument is manually set, the default value of the main argument will be FALSE.

ggheatmap(small_mat) +
    scale_fill_viridis_c() +
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    anno_top(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    anno_bottom(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) -
    # Modify the background of all plots in the left and top annotation
    with_quad(theme(plot.background = element_rect(fill = "red")), "tl")
#> → heatmap built with `geom_tile()`

Setting position to NULL removes any active annotation stack, meaning the object will apply to all plots in the layout, including annotation stacks:

ggheatmap(small_mat) +
    scale_fill_viridis_c() +
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    anno_top(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    anno_bottom(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) -
    # Modify the background of all plots
    with_quad(theme(plot.background = element_rect(fill = "red")), NULL)
#> → heatmap built with `geom_tile()`

stack_layout()

By default, when the active layout is the stack_layout() itself, by wrapping object with with_quad(), - operator will apply changes to all plots along the stack_layout(), which means if the stack layout is in horizontal, - operator will also add the element to the left and right annotation, if the stack layout is in vertical, - operator will also add element to the top and bottom annotation. In these cases, the object will also be applied to the main plot by default unless specified by main argument otherwise.

stack_alignv(small_mat) +
    align_dendro() +
    ggtitle("I'm from the parent stack") +
    ggheatmap() +
    anno_top() +
    align_dendro() +
    ggtitle("I'm from the nested heatmap") +
    # remove any active context
    stack_active() +
    align_dendro() +
    ggtitle("I'm from the parent stack") -
    # Modify the the color scales of all plots in the stack layout except the heatmap layout
    scale_color_brewer(palette = "Dark2") -
    # set the background of all plots in the stack layout (including plots in the heatmap layout)
    with_quad(theme(plot.background = element_rect(fill = "red")))
#> → heatmap built with `geom_tile()`

When the active layout is the nested ggheatmap()/quad_layout(), the - operator applies the elements to this nested layout, following the same principles as for ggheatmap()/quad_layout().

Session information

sessionInfo()
#> R version 4.4.0 (2024-04-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04 LTS
#> 
#> Matrix products: default
#> BLAS/LAPACK: /usr/lib/x86_64-linux-gnu/libmkl_rt.so;  LAPACK version 3.8.0
#> 
#> locale:
#>  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
#>  [4] LC_COLLATE=C           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: Asia/Shanghai
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] grid      stats     graphics  grDevices utils     datasets  methods  
#> [8] base     
#> 
#> other attached packages:
#> [1] ggalign_0.0.5 ggplot2_3.5.1
#> 
#> loaded via a namespace (and not attached):
#>  [1] gtable_0.3.5       jsonlite_1.8.8     dplyr_1.1.4        compiler_4.4.0    
#>  [5] highr_0.11         tidyselect_1.2.1   ggbeeswarm_0.7.2   jquerylib_0.1.4   
#>  [9] textshaping_0.4.0  systemfonts_1.1.0  scales_1.3.0       yaml_2.3.8        
#> [13] fastmap_1.2.0      R6_2.5.1           labeling_0.4.3     generics_0.1.3    
#> [17] knitr_1.47         tibble_3.2.1       bookdown_0.39      desc_1.4.3        
#> [21] munsell_0.5.1      RColorBrewer_1.1-3 bslib_0.7.0        pillar_1.9.0      
#> [25] rlang_1.1.4        utf8_1.2.4         cachem_1.1.0       xfun_0.45         
#> [29] sass_0.4.9         viridisLite_0.4.2  cli_3.6.3          withr_3.0.0       
#> [33] magrittr_2.0.3     digest_0.6.36      beeswarm_0.4.0     lifecycle_1.0.4   
#> [37] vipor_0.4.7        ggrastr_1.0.2      vctrs_0.6.5        evaluate_0.24.0   
#> [41] glue_1.7.0         farver_2.1.2       ragg_1.3.2         fansi_1.0.6       
#> [45] colorspace_2.1-0   rmarkdown_2.27     tools_4.4.0        pkgconfig_2.0.3   
#> [49] htmltools_0.5.8.1