---
title: "Stack Layout"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Stack Layout}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
    collapse = TRUE,
    comment = "#>"
)
```

`stack_layout()` put plots horizontally or vertically. You can also use the
alias `ggstack()`.

```{r setup}
library(ggalign)
```

## 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.

```{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)))
```

By default, `ggstack()` will create the layout, but no plot will be drawn until
you add a plot element:
```{r}
ggstack(small_mat)
```

We can add any `align_*()` function to customize the layout or integrate plots
into the stack. 
```{r}
ggstack(small_mat) + align_dendro()
```

```{r}
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: 
```{r}
ggstack(small_mat, "v") + align_dendro()
```

>Note that vertical stack take the `x-axis` as the observations, but horizontal
stack take the `y-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.

```{r}
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.

```{r}
ggstack(small_mat) +
    ggheatmap()
```

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. 
```{r}
ggstack(small_mat, direction = "v") +
    ggheatmap()
```

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. 

```{r}
ggstack(small_mat) +
    ggheatmap() +
    scale_fill_viridis_c()
```

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()`. 
```{r}
ggstack(small_mat) +
    ggheatmap() +
    scale_fill_viridis_c() +
    stack_active() +
    ggalign(data = rowSums) +
    geom_bar(aes(value), fill = "red", orientation = "y", stat = "identity")
```

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()`. 
```{r}
ggstack(small_mat, "v") +
    ggheatmap() +
    ggheatmap() &
    scale_fill_viridis_c()
```

## 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.
```{r}
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()
```

```{r}
# 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()
```

In this way, heatmap body width/height specified in `hmanno()` or `ggheatmap()`
won't work.
```{r}
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
```

By default the flank annotation will fill the whole stack flank, but we can
still control the size of heatmap annotation in `hmanno()`. 
```{r}
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()
```

You can also use `npc` unit.
```{r}
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()
```

## Session information
```{r}
sessionInfo()
```
