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

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

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

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

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.

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

## 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.
```{r}
# Initialize the heatmap
ggheatmap(small_mat) +
    # initialize the left annotation
    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")
```

## 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. 
```{r}
# Initialize the heatmap
ggheatmap(small_mat) +
    # initialize the left annotation
    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")
```

If the active layout is the annotation stack, the `-` operator will only add
the elements to all plots in the active annotation stack: 
```{r}
ggheatmap(small_mat) +
    # initialize the left annotation
    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")
```

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

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()`
The `with_quad()` function modifies the application context of elements in
`ggheatmap()`/`quad_layout()`. It controls how objects like themes, scales, or
other plot modifications apply to specific annotation stacks or the main plot
without altering the currently active layout or plot.

This function accepts three arguments:

 1. **x**: An object which can be added to the ggplot, including
    **plot options** (see `vignette("plot-options")` for details).
 2. **position**: A string containing one or more of 
    `r ggalign:::oxford_and(ggalign:::.tlbr)` 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()`
Default Behavior by wrapping object with `with_quad()`:

  - When `ggheatmap()`/`quad_layout()` has no active annotation stack, objects
  added via `+` or `-` operate normally without `with_quad()`. 
  - When the active annotation stack is set, `with_quad()` ensures the applied
  object also modifies: 
    * The main plot (by default).
    * Opposite annotation stacks when using `-`.

By wrapping object with `with_quad()`, the `+` operator will apply the object
not only to the active plot in the annotation stack, but also to the main plot
unless specified by `main` argument otherwise.
```{r}
ggheatmap(small_mat) +
    # initialize the left annotation
    anno_left(size = 0.2) +
    align_dendro() +
    # apply the object not only to the active plot in the annotation stack, but
    # also to the main plot
    with_quad(theme(plot.background = element_rect(fill = "red")))
```

By wrapping object with `with_quad()`, the `-` operator will apply the object
not only to that annotation stack but also to the opposite one (i.e., bottom if
top is active, and vice versa). In these cases, the object will also be applied
to the main plot by default unless specified by `main` argument otherwise.
```{r}
ggheatmap(small_mat) +
    # initialize the left annotation
    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 theme of all plots in the bottom and the opposite annotation
    # in this way, the `main` argument by default would be `TRUE`
    with_quad(theme(plot.background = element_rect(fill = "red")))
```

The `position` argument can be a string containing one or more of 
`r ggalign:::oxford_and(ggalign:::.tlbr)`, 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`.

```{r}
ggheatmap(small_mat) +
    # initialize the left annotation
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    # initialize the top annotation
    anno_top(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    # initialize the bottom annotation
    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")
```

Setting `position` to `NULL` change the context to the
`ggheatmap()`/`quad_layout()` itself.
```{r}
ggheatmap(small_mat) +
    # initialize the left annotation
    anno_left(size = 0.2) +
    align_dendro() +
    # we apply the theme to the main plot only
    with_quad(theme(plot.background = element_rect(fill = "red")), NULL)
```

```{r}
ggheatmap(small_mat) +
    # initialize the left annotation
    anno_left(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    # initialize the top annotation
    anno_top(size = 0.2) +
    align_dendro(aes(color = branch), k = 3L) +
    # initialize the bottom annotation
    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)
```

## `stack_layout()`
When the active layout is the `stack_layout()` itself, by default, 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.
```{r}
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")))
```

`+` operator won't do anything special for when the active layout is the
`stack_layout()` itself.

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