<!--
%\VignetteEngine{knitr}
%\VignetteIndexEntry{How to merge GatingSets}
-->

How to merg/standardize GatingSets
========================================================

Usage
------------------------------------------------------
```{r eval=FALSE}
groupByTree(x)
checkRedundantNodes(x)
dropRedundantNodes(x,toRemove)
dropRedundantChannels(gs, ...)
```

Arguments
------------------------------------------------------
**x**  
'GatingSet' objects or or list of groups (each group member is a list of 'GatingSet`)

**toRemove**
  list of the node sets to be removed. its length must equals to the length of argument **x**

**...** other arguments	

```{r echo=FALSE, message=FALSE, results='hide'}
library(flowWorkspace)
flowDataPath <- system.file("extdata", package = "flowWorkspaceData")
gs <- load_gs(file.path(flowDataPath,"gs_manual"))
gs1 <- clone(gs)
sampleNames(gs1) <- "1.fcs"

# simply the tree
nodes <- getNodes(gs1)
for(toRm in nodes[grepl("CCR", nodes)])
  Rm(toRm, gs1)

# remove two terminal nodes
gs2 <- clone(gs1)
sampleNames(gs2) <- "2.fcs"
Rm("DPT", gs2)
Rm("DNT", gs2)

# remove singlets gate
gs3 <- clone(gs2)
Rm("singlets", gs3)
add(gs3, getGate(gs2, "CD3+"), parent = "not debris")
for(tsub in c("CD4", "CD8"))
  {
    add(gs3, getGate(gs2, tsub), parent = "CD3+")
    for(toAdd in getChildren(gs2, tsub))
    {
        thisParent <- getParent(gs2[[1]], toAdd, path = "auto")
        add(gs3, getGate(gs2, toAdd), parent = thisParent)
    }
  }
sampleNames(gs3) <- "3.fcs"

# spin the branch to make it isomorphic
gs4 <- clone(gs3)
# rm cd4 branch first
Rm("CD4", gs4)
# add it back
add(gs4, getGate(gs3, "CD4"), parent = "CD3+")
# add all the chilren back
for(toAdd in getChildren(gs3, "CD4"))
{
    thisParent <- getParent(gs3[[1]], toAdd)
    add(gs4, getGate(gs3, toAdd), parent = thisParent)
}
sampleNames(gs4) <- "4.fcs"

gs5 <- clone(gs4)
# add another redundant node
add(gs5, getGate(gs, "CD4/CCR7+ 45RA+")[[1]], parent = "CD4")
add(gs5, getGate(gs, "CD4/CCR7+ 45RA-")[[1]], parent = "CD4")
sampleNames(gs5) <- "5.fcs"

library(knitr)
opts_chunk$set(fig.show = 'hold', fig.width = 4, fig.height = 4, results= 'asis')

```

## Remove the redudant leaf/terminal nodes
```{r echo=FALSE}
plot(gs1)
plot(gs2)
```

Leaf nodes **DNT** and **DPT** are redudant for the analysis and should be **removed** before merging.

## Hide the non-leaf nodes
```{r echo=FALSE}
plot(gs2)
plot(gs3)
```

**singlets** node is not present in the second tree. But we **can't** remove it because it will remove all its descendants. We can **hide** it instead.

```{r}
invisible(setNode(gs2, "singlets", FALSE))
plot(gs2)
plot(gs3)
```

Note that even gating trees look the same but **singlets** still physically exists so 
we must refer the populations by **relative path** (`path = "auto"`)  instead of **full path**.
```{r results='hold'}
getNodes(gs2)[5]
getNodes(gs3)[5]
```

```{r results='hold'}
getNodes(gs2, path = "auto")[5]
getNodes(gs3, path = "auto")[5]
```

## Isomorphism
```{r echo=FALSE}
#restore gs2
invisible(setNode(gs2, "singlets", TRUE))
```

```{r echo=FALSE}
plot(gs3)
plot(gs4)
```

These two trees are **not identical** due to the **different order** of **CD4** and **CD8**. However they are still mergable thanks to the **reference by gating path** instead of `by numeric indices`

## convenient wrapper for merging
To ease the process of merging large number of batches of experiments, here is some **internal wrappers** to make it **semi-automated**.

### Grouping by tree structures
```{r}
gslist <- list(gs1, gs2, gs3, gs4, gs5)
gs_groups <- groupByTree(gslist)
length(gs_groups)
```

This divides all the `GatingSet`s into different groups, each group shares the same tree structure. Here we have `4` groups, 
## Check if the discrepancy can be resolved by dropping leaf nodes
```{r error=TRUE}
res <- try(checkRedundantNodes(gs_groups), silent = TRUE)
print(res[[1]])
```

Apparently the non-leaf node (`singlets`) fails this check, and it is up to user to decide whether to hide this node or keep this group separate from further merging.Here we try to hide it.

```{r}
for(gp in gs_groups)
  plot(gp[[1]])
```

Based on the tree structure of each group (usually there aren't as many groups as `GatingSet` objects itself), we will hide `singlets` for `group 2` and `group 4`.

```{r}
for(i in c(2,4))
  for(gs in gs_groups[[i]])
    invisible(setNode(gs, "singlets", FALSE))
```

Now check again with `.checkRedundantNodes`
```{r}
toRm <- checkRedundantNodes(gs_groups)
toRm
```

Based on this, these groups can be consolidated by dropping 
* `CCR7+ 45RA+` and `CCR7+ 45RA-` from `group 1`.
* `DNT` and `DPT` from `group 2`.

To proceed the deletion of these nodes, `.dropRedundantNodes` can be used instead of doing it manually
```{r results='hide'}
dropRedundantNodes(gs_groups, toRm)
```

Now they can be merged into a single `GatingSetList`.
```{r}
GatingSetList(gslist)
```

Remove the redundant channels from `GatingSet`
------------------------------------------------------
Sometime there may be the extra `channels` in one data set that prevents it from being merged with other. If these channels are not used by any gates, then they can be safely removed.
```{r}
dropRedundantChannels(gs1)
```
