--- title: "Layout Plot" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Layout Plot} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` The `ggalign` package offers several `align_*` functions that allow for precise control over plot layouts. In addition, there are two primary functions for adding plots: - `align_gg()`/`ggalign()`: Create a ggplot object and aligns the observation data. - `free_gg()`/`ggfree()`: Create a ggplot object without aligning the observation data. `align_gg()`/`ggalign()` can only be used with a `stack_layout()` that aligns observations (`stack_align()`), while `free_gg()`/`ggfree()` can also be added to a `stack_layout()` that does not align the observations (`stack_free()`). ```{r setup} library(ggalign) ``` ```{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))) ``` # `align_gg`/`ggalign` `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. By default, it will inherit from the layout. If a function, it will apply with the layout matrix. `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 quad layout annotation) and `aes(x = .data$.x)` for vertical stacking (including top and bottom quad layout 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()`. The data in the underlying `ggplot` object will contain following columns: - `.panel`: the panel for the aligned axis. It means `x-axis` for vertical stack layout (including top and bottom annotation), `y-axis` for horizontal stack layout (including left and right annotation). - `.x` or `.y`: the `x` or `y` coordinates. - `.names` and `.index`: A factor of the names (only applicable when names exists) and an integer of index of the original data. - `.row_names` and `.row_index`: the row names and an integer of row index of the original matrix (only applicable if `data` is a `matrix`). - `.column_names` and `.column_index`: the column names and column index of the original matrix (only applicable if `data` is a `matrix`). - `value`: the actual value (only applicable if `data` is a `matrix` or atomic vector). >It is recommended to use `.x`/`.y`, or `.names` as the `x`/`y` mapping. ```{r} ggheatmap(small_mat) + scale_fill_viridis_c(guide = "none") + anno_top() + ggalign(data = rowSums) + geom_point(aes(y = value)) ``` If `data = NULL`, the data in the underlying `ggplot` object contains following columns: - `.panel`: the panel for the axis used for alignment. - `.index`: the index of the original layout data. - `.x` or `.y`: the `x` or `y` coordinates You can use it to integrate additional elements, such as block annotation or customized panel title, into your layout. ```{r} ggheatmap(small_mat) + anno_top(size = unit(1, "cm")) + align_kmeans(centers = 3L) + ggalign(data = NULL) + plot_data(~ aggregate(.x ~ .panel, .x, FUN = median)) + geom_tile(aes(y = 1L, fill = .panel, color = .panel)) + geom_text(aes(y = 1L, label = .panel)) ``` ## Cross panel sumamry When used in a `ggheatmap()`, and the data is inherited from the `ggheatmap()`, 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 `ggalign()`). ```{r fig.dim = c(5, 10)} 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()) + anno_right() + align_group(split) + anno_top(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") ``` This approach replicates the functionality of [ComplexHeatmap::anno_summary()](https://jokergoo.github.io/ComplexHeatmap-reference/book/heatmap-annotations.html#summary-annotation), but is versatile enough to be used with any heatmap, not just single-column or single-row heatmaps. ```{r} ggheatmap(small_mat) + theme(axis.text.x = element_text(angle = -60, hjust = 0)) + anno_top() + align_dendro(aes(color = branch), k = 3L) + scale_color_brewer(palette = "Dark2") + anno_right(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. ```{r} ggheatmap(small_mat) + patch_titles(left = "left patch title", bottom = "bottom patch title") + theme(axis.text.x = element_text(angle = -60, hjust = 0)) + anno_top() + align_dendro(aes(color = branch), k = 3L) + scale_color_brewer(palette = "Dark2") + patch_titles(top = "top patch title") + anno_right(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") ``` # `free_gg`/`ggfree` The `free_gg()` function allows you to incorporate a ggplot object into your layout. Unlike `align_gg()`, which aligns every axis value precisely, `free_gg()` focuses on layout integration without enforcing strict axis alignment. `ggfree()` is an alias for `free_gg`. Internally, the function uses `fortify_data_frame()` to transform the input into a data frame. For matrices, it converts them into a long-formatted data frame. Note that `ggfree()` does not provide a default aesthetic mapping, which contrasts with `ggalign()`. You will need to manually provide the default mappings. All annotations in `ggheatmap()` are `stack_align()`. When used in a `stack_align()`, you typically do not want to inherit from the layout matrix and should input a data frame manually. The `data` argument must be explicitly provided, as it comes after `...`, but we rarely used it in a `stack_align()`. ```{r} ggheatmap(small_mat) + anno_top() + ggfree(aes(wt, mpg), data = mtcars) + geom_point() ``` It is more commonly used in a `stack_free()`, where you usually want to inherit from the layout data frame. All annotations in `ggside()` are `stack_free()`. ```{r} ggside(mpg, aes(displ, hwy, colour = class)) - geom_point(size = 2) + anno_top(size = 0.3) + ggfree() + geom_density(aes(displ, y = after_stat(density), colour = class), position = "stack") + anno_right(size = 0.3) + ggfree() + geom_density(aes(x = after_stat(density), hwy, colour = class), position = "stack" ) + theme(axis.text.x = element_text(angle = 90, vjust = .5)) ``` Alternatively, you can directly input the ggplot object. ```{r} ggheatmap(small_mat) + anno_top() + ggfree(data = ggplot(mtcars, aes(wt, mpg))) + geom_point() ``` You can also add the `ggplot` object directly without using `ggfree()`. However, doing so will limit control over the plot (like plot area `size`, and `active` components): ```{r} ggheatmap(small_mat) + anno_top() + ggplot(mtcars, aes(wt, mpg)) + geom_point() ``` # `ggwrap()` and `inset()` The `ggwrap()` function allows you to wrap objects that can be converted into a grob, turning them into a `ggplot` for plotting. Further you can still add ggplot elements like title, subtitle, tag, caption, and geoms using the same approach as with normal ggplots (using `ggtitle()`, `labs()`, `geom_*()`) as well as styling using `theme()`. This enables you to pass these wrapped objects into `ggfree()`. ```{r} library(grid) ggheatmap(small_mat) + anno_top() + # `ggwrap()` will create a `ggplot` object, we use `ggfree` to add it into the layout ggfree(data = ggwrap(rectGrob(gp = gpar(fill = "goldenrod")), align = "full")) ``` You can also integrate base plots, pheatmap, ComplexHeatmap, e.g. Additionally, you can add any graphics as a inset to a ggplot using the `inset()` function. Like `ggwrap()`, `inset()` can accept any object that can be converted to a grob. ```{r} ggheatmap(small_mat) + anno_top() + ggfree(data = ggwrap(rectGrob(gp = gpar(fill = "goldenrod")), align = "full")) + # we can then add any inset grobs (the same as ggwrap, it can take any objects # which can be converted to a `grob`) inset(rectGrob(gp = gpar(fill = "steelblue")), align = "panel") + inset(textGrob("Here are some text", gp = gpar(color = "black")), align = "panel" ) ``` # Session information ```{r} sessionInfo() ```