---
title: "Storing and Fine-Tuning APackOfTheClones Runs"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Storing and Fine-Tuning APackOfTheClones Runs}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
data: 'Compiled: `r format(Sys.Date(), "%B %d, %Y")`'
---

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

knitr::opts_chunk$set(echo = FALSE)
options(repos = c(CRAN = "http://cran.rstudio.com"))

# utility functions
head <- function(df) {
  knitr::kable(utils::head(df))
}

quiet_load_all_CRAN <- function(...) {
  for (pkg in list(...)) {
    if (require(pkg, quietly = TRUE, character.only = TRUE)) next
    invisible(install.packages(
      pkg, quiet = TRUE, verbose = FALSE, character.only = TRUE
    ))
    suppressPackageStartupMessages(invisible(
      require(pkg, quietly = TRUE, character.only = TRUE)
    ))
  }
}

# load packages
quiet_load_all_CRAN("ggplot2", "cowplot", "Seurat")
```

```{r setup}
suppressPackageStartupMessages(library(APackOfTheClones))
```

## Introduction

As demonstrated in `vignette("APackOfTheClones")`, after processing the seurat & clonotype data properly with `scRepertoire`, `vizAPOTC` provides a direct way to produce the ball-packing clonal expansion visualization, though for select users it may be somewhat clunky, if certain parameters need to be readjusted constantly. In this vignette, more details about how APackOfTheClones runs can be stored and re-adjusted will be covered - mainly through `RunAPOTC`, `APOTCPlot`, and `AdjustAPOTC`. Ensure to read the aforementioned vignette before this one.

<details>

  <summary>
  **As a reminder, here's how to set up the seurat object and clonotype data**
  </summary>

```{r, setup_seurat, eval = FALSE}
library(scRepertoire)

pbmc <- scRepertoire::combineExpression(
  scRepertoire::combineTCR(
    get(data("contig_list", package = "scRepertoire")),
    samples = c("P17B", "P17L", "P18B", "P18L", "P19B", "P19L", "P20B", "P20L"),
    removeNA = FALSE,
    removeMulti = FALSE,
    filterMulti = FALSE
  ),
  pbmc,
  cloneCall = "gene",
  proportion = TRUE
)

print(pbmc)
```

```{r, actual_print_pbmc, eval = TRUE, echo = TRUE, include = FALSE}
# TODO use a nicer looking dataset
pbmc <- get(data("combined_pbmc"))
print(pbmc)
```

</details>

### Overview

All of `vizAPOTC`'s arguments are actually derived from `RunAPOTC` and `APOTCPlot`. The former is responsible for storing data of the S4 class `ApotcData` in the seurat object under a named list in `@misc$APackOfTheClones` under some character run ID, and the latter allows the visualization of these data objects with some customization. `AdjustAPOTC` has many arguments for adjusting the data associated with some APackOfTheClones run stored by `RunAPOTC`, including adjusting cluster positions, colors, repulsion, etc. which can be visualized again with `APOTCPlot`.

## Managing APackOfTheClones run data

`RunAPOTC` has approximate the first half of `vizAPOTC`'s arguments until `max_repulsion_iter`, meaning it has all the data subsetting, circle size scaling, and cluster repulsion capabilities covered in the previous vignette. The most essential difference is the presence of the argument `run_id`, which corresponds to an id for the `ApotcData` object. If left blank, one will be automatically generated in the following format:

> `reduction_base;clonecall;keyword_arguments;extra_filter`

where if keyword arguments and extra_filter are underscore (`_`) characters if there was no input for the `...` and `extra_filter` parameters.

```{r, eval = FALSE}
# Here is the function ran with its default parameters
pbmc <- RunAPOTC(pbmc)

#> Initializing APOTC run...
#> * Setting `clone_scale_factor` to 0.3
#> * id for this run: umap;CTstrict;_;_
#>
#> Packing clones into clusters
#> [==================================================] 100%
#> 
#> repulsing all clusters | max iterations = 20
#> [==================================================] 100%
#>
#> Completed successfully, time elapsed: 0.155 seconds
#>
```

```{r, runapotc_default, include = FALSE}
pbmc <- RunAPOTC(pbmc, verbose = FALSE)
```

From the verbal queues, one can see how the `run_id` was set. Here's it ran again but with more optional arguments and a custom `run_id`:

```{r, runapotc2}
pbmc <- RunAPOTC(
    pbmc, run_id = "sample17", orig.ident = c("P17B", "P17L"), verbose = FALSE
)
```

### Utilities for Managing APackOfTheClones Runs

It is to note that the data abstraction here with a `run_id` is intentional, and users should not manually touch any of the `ApotcData` objects with the seurat object unless they are extremely familiar with the latest internal implementation. Instead, here is a collection of functions that may be useful:

- `getApotcDataIds(pbmc)` gets all current `run_id`'s, if any.
- `getLastApotcDataId(pbmc)` gets the latest `run_id`, if any.
- `containsApotcRun(pbmc, run_id = "foo")` returns whether a `run_id` exists in the seurat object.
- `deleteApotcData(pbmc, run_id = "foo")` deletes *all data* associated with a certain `run_id`.

## APOTCPlot

To visualize stored APackOfTheClones runs, `APOTCPlot` takes in a seurat object and the `run_id`. If no `run_id` is provided, it defaults to using the latest run. All other parameters are same as in the second half of `vizAPOTC`. Although it is noteworthy that if the user had always relied on auto-generated `run_id`'s then `APOTCPlot` also has these subsetting arguments:

```{r, apotcplot_subset_params, eval = FALSE}
reduction_base = NULL,
clonecall = NULL,
...,
extra_filter = NULL,
```

And putting in identical arguments to generate the original `ApotcData` would work too, but this approach is less recommended as its a lot more (unnecessarily) verbose. Here is `APOTCPlot` in action:

```{r, apotcplot}
# Here, plots for samples 17, 18, and 19 as seen in the previous vignette are made, where
# `orig.ident` is a custom column in the example data with levels corresponding to sample ids:
# ("P17B" "P17L" "P18B" "P18L" "P19B" "P19L" "P20B" "P20L"). 

pbmc <- RunAPOTC(
  pbmc, run_id = "P17", orig.ident = c("P17B", "P17L"), verbose = FALSE
)

pbmc <- RunAPOTC(
  pbmc, run_id = "P18", orig.ident = c("P18B", "P18L"), verbose = FALSE
)

pbmc <- RunAPOTC(
  pbmc, run_id = "P19", orig.ident = c("P19B", "P19L"), verbose = FALSE
)

cowplot::plot_grid(
  vizAPOTC(pbmc, verbose = FALSE),
  APOTCPlot(pbmc, run_id = "P17"),
  APOTCPlot(pbmc, run_id = "P18"),
  APOTCPlot(pbmc), # run_id omitted as sample 19 was the latest run
  labels = c("all", "17", "18", "19")
)
```

## AdjustAPOTC

This function's parameters help modify certain attributes about APackOfTheClones runs, and has the exact same first six parameters as `APOTCPlot` for managing which run to modify. It also possesses the same four repulsion arguments in `vizAPOTC` and `RunAPOTC` if a run is to be repulsed again. See the function level documentation for the following parameters that can modify cluster locations, colors, and the adjustment of the `clone_scale_factor` and `rad_scale_factor`.
