Layout Plot

The ggalign package offers several align_* functions that allow you to precisely control plot layout and integrate additional plots. Currently, there are two primary align_* functions for adding plots:

library(ggalign)
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)))

align_gg

align_gg() is similar to ggplot in that it initializes a ggplot data and mapping. Same with other align_* functions. align_gg() allowing you to provide data in various formats, including matrices, data frames, or simple vectors. This data can be also inherited from the layout.

align_gg() always applies a default mapping for the axis of the data index in the layout. This mapping is aes(y = .data$.y) for horizontal stacking (including left and right heatmap annotation) and aes(x = .data$.x) for vertical stacking (including top and bottom heatmap annotation). For more information, refer to the “ggplot2 Specification” section in the align_gg() documentation.

You can also use the ggalign() function, which is an alias for align_gg().

ggheatmap(small_mat) +
    scale_fill_viridis_c(guide = "none") +
    hmanno("t") +
    ggalign(data = rowSums) +
    geom_point(aes(y = value))

Plot data

align_gg()/ggalign() requires the specific data format for its operations. If you need to transform or filter data for individual geoms, you can use the data argument within each geom. However, if you have multiple geoms and want a consistent transformation applied across all, you can utilize the plot_data argument in the align_gg()/ggalign() function. This allows you to transform the default data for all subsequent geoms.

ggheatmap(small_mat) +
    scale_fill_viridis_c(guide = "none") +
    hmanno("t") +
    align_kmeans(3L) +
    ggalign(plot_data = function(data) subset(data, .panel == 1L)) +
    geom_bar(aes(y = value, fill = .row_names), stat = "identity")

Cross panel sumamry

When used in a heatmap layout, and the data is inherited from the heatmap data, a special column .extra_panel will be added, which is the panel information for column (left or right annotation) or row (top or bottom annotation). This is useful if you want to create summary plot using another axis panel. In such cases, it’s often necessary to disable the automatic setting of limits (limits = FALSE in align_gg()).

set.seed(1L)
v <- stats::rnorm(50L)
split <- sample(letters[1:2], 50L, replace = TRUE)
ggheatmap(v) +
    scale_fill_viridis_c() +
    theme(strip.text = element_text(), strip.background = element_rect()) +
    hmanno("r") +
    align_group(split) +
    hmanno("t", size = 0.5) +
    ggalign(limits = FALSE) +
    geom_boxplot(aes(.extra_panel, value, fill = .extra_panel),
        # here, we use `print()` to show the underlying data
        data = function(data) {
            print(head(data))
            data
        }
    ) +
    scale_fill_brewer(palette = "Dark2", name = "branch")

#>   .column_index .row_index      value .extra_panel .panel .x
#> 1             1          1 -0.6264538            b      1  1
#> 2             2          1  0.1836433            b      1  1
#> 3             3          1 -0.8356286            b      1  1
#> 4             4          1  1.5952808            a      1  1
#> 5             5          1  0.3295078            a      1  1
#> 6             6          1 -0.8204684            a      1  1

This approach replicates the functionality of ComplexHeatmap::anno_summary(), but is versatile enough to be used with any heatmap, not just single-column or single-row heatmaps.

ggheatmap(small_mat) +
    theme(axis.text.x = element_text(angle = -60, hjust = 0)) +
    hmanno("t") +
    align_dendro(aes(color = branch), k = 3L) +
    scale_color_brewer(palette = "Dark2") +
    hmanno("r", size = 0.5) +
    ggalign(limits = FALSE) +
    geom_boxplot(aes(y = .extra_panel, x = value, fill = factor(.extra_panel))) +
    scale_fill_brewer(palette = "Dark2", name = "branch")

Plot titles

ggplot2 only allow add titles in the top or add caption in the bottom. The ggalign package extends this capability, allowing you to place titles around any border of the plot using the patch_titles() function.

ggheatmap(small_mat) +
    patch_titles(left = "left patch title", bottom = "bottom patch title") +
    theme(axis.text.x = element_text(angle = -60, hjust = 0)) +
    hmanno("t") +
    align_dendro(aes(color = branch), k = 3L) +
    scale_color_brewer(palette = "Dark2") +
    patch_titles(top = "top patch title") +
    hmanno("r", size = 0.5) +
    ggalign(limits = FALSE) +
    geom_boxplot(aes(y = .extra_panel, x = value, fill = factor(.extra_panel))) +
    scale_fill_brewer(palette = "Dark2", name = "branch") +
    patch_titles(right = "right patch title")

align_panel

The align_panel() function is similar to align_gg(), but it operates specifically with layout panel data, removing all axis labels and ticks. The ggpanel() function is an alias for align_panel().

The data in the underlying ggplot object contains following columns:

You can use align_panel() to integrate additional elements, such as block annotation or customized panel title, into your layout.

ggheatmap(small_mat) +
    hmanno("t", size = unit(1, "cm")) +
    align_kmeans(centers = 3L) +
    ggpanel() +
    geom_tile(aes(y = 1L, fill = .panel, color = .panel),
        width = 1L, height = 1L
    ) +
    geom_text(aes(y = 1L, label = .panel),
        data = function(data) {
            aggregate(.x ~ .panel, data, FUN = median)
        }
    )

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] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] ggalign_0.0.4 ggplot2_3.5.1
#> 
#> loaded via a namespace (and not attached):
#>  [1] sass_0.4.9         utf8_1.2.4         generics_0.1.3     digest_0.6.36     
#>  [5] magrittr_2.0.3     evaluate_0.24.0    grid_4.4.0         RColorBrewer_1.1-3
#>  [9] bookdown_0.39      iterators_1.0.14   fastmap_1.2.0      foreach_1.5.2     
#> [13] jsonlite_1.8.8     ggrastr_1.0.2      seriation_1.5.6    fansi_1.0.6       
#> [17] viridisLite_0.4.2  scales_1.3.0       codetools_0.2-20   textshaping_0.4.0 
#> [21] jquerylib_0.1.4    cli_3.6.3          registry_0.5-1     rlang_1.1.4       
#> [25] munsell_0.5.1      withr_3.0.0        cachem_1.1.0       yaml_2.3.8        
#> [29] ggbeeswarm_0.7.2   tools_4.4.0        dplyr_1.1.4        colorspace_2.1-0  
#> [33] vctrs_0.6.5        TSP_1.2-4          ca_0.71.1          R6_2.5.1          
#> [37] lifecycle_1.0.4    vipor_0.4.7        ragg_1.3.2         pkgconfig_2.0.3   
#> [41] beeswarm_0.4.0     pillar_1.9.0       bslib_0.7.0        gtable_0.3.5      
#> [45] data.table_1.15.4  glue_1.7.0         systemfonts_1.1.0  xfun_0.45         
#> [49] tibble_3.2.1       tidyselect_1.2.1   highr_0.11         knitr_1.47        
#> [53] farver_2.1.2       htmltools_0.5.8.1  rmarkdown_2.27     labeling_0.4.3    
#> [57] compiler_4.4.0