---
title: "Detecting and removing contaminants"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Detecting and removing contaminants}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

```{r setup}
library(tidypq)
library(MiscMetabar)
```

## The detect-then-filter design

tidypq splits contamination handling into two steps:

1. **Detect.** Each `identify_contam_*_pq()` function flags suspect taxa using a
   different signal, and returns a `contam_tbl` -- a tibble with one row per
   flagged taxon, a `method` column, and method-specific *evidence* columns. A
   detector never modifies the phyloseq object.
2. **Filter.** The single verb `filter_contam_pq()` consumes any `contam_tbl`
   (or several, combined) and removes the flagged taxa.

| Detector | Signal | Needs |
|---|---|---|
| `identify_contam_blocklist_pq()` | genus on a known-contaminant blocklist | `tax_table` |
| `identify_contam_corr_pq()` | abundance correlates negatively with depth | counts |
| `identify_contam_primer_pq()` | representative sequence embeds a primer | `refseq`, Biostrings |
| `identify_contam_chimera_pq()` | chimeric sequence (dada2 or vsearch) | `refseq`, dada2/vsearch |
| `identify_contam_negcontrol_pq()` | occurrence pattern in negative controls | control samples |

"Contaminant" here is a broad umbrella: technical artefacts (chimeras, primer
read-through), reagent/lab contaminants, and cross-sample contaminants are all
sub-types flagged by one detector or another.

## A first detector

The blocklist detector needs only a taxonomy table. `data_fungi` is fungal, so
the default bacterial blocklist matches nothing; we extend it with a genus
present in the data for illustration.

```{r}
flagged <- identify_contam_blocklist_pq(data_fungi, extra_genera = "Mortierella")
flagged
```

A `contam_tbl` always starts with `taxon` and `method`; the remaining columns
are the evidence specific to that detector.

```{r}
names(flagged)
```

## Removing flagged taxa

`filter_contam_pq()` removes the flagged taxa by name and returns the cleaned
phyloseq object. When nothing is flagged it returns the object unchanged.

```{r}
data_clean <- filter_contam_pq(data_fungi, flagged)
data_clean
```

## Combining detectors

Because every detector returns the same object, their outputs compose with
`rbind()` -- evidence columns missing from one detector are filled with `NA`,
and `filter_contam_pq()` removes the union of the flagged taxa.

```{r}
blocklist <- identify_contam_blocklist_pq(
  data_fungi,
  extra_genera = "Mortierella",
  verbose = FALSE
)

# A second (here, hand-built) contam_tbl standing in for another detector
manual <- new_contam_tbl(tibble::tibble(
  taxon = taxa_names(data_fungi)[1:2],
  method = "manual"
))

combined <- rbind(blocklist, manual)
combined

data_clean <- filter_contam_pq(data_fungi, combined)
```

## Diagnostics

A lightweight overview of how many taxa each method flagged is available through
the `plot()` / `autoplot()` method on a `contam_tbl`. Publication-grade
contamination figures live in the companion `ggplotpq` package and consume the
same `contam_tbl`.

```{r, fig.width = 6, fig.height = 3}
plot(combined)
```

## Negative-control classification

When the design includes negative/blank controls, `identify_contam_negcontrol_pq()`
classifies the taxa seen in those controls into sub-types. Only `artifact` and
`lab_contaminant` are flagged by default; add `sample_contaminant` to
`flag_categories` to be more aggressive.

```{r}
pq <- mutate_samdata_pq(
  data_fungi,
  is_control = sample_sums(.) < sort(sample_sums(.))[4]
)

nc <- identify_contam_negcontrol_pq(pq, is_control)
nc
```

## Abundance-, sequence-, and chimera-based detectors

The remaining detectors follow the identical pattern; they are shown here
without evaluation because they need extra data or packages.

```{r, eval = FALSE}
# Correlation of relative abundance with sequencing depth (GRIMER-inspired)
corr <- identify_contam_corr_pq(data_fungi, contam_threshold = -0.5)

# Taxa whose representative sequence embeds a primer (needs Biostrings + refseq)
primers <- c(fwd = "CCCTACGGGGTGCASCAG", rev = "GGACTACVSGGGTATCTAAT")
prim <- identify_contam_primer_pq(data_fungi, primers)

# Chimeras, de novo (dada2) or reference-based (vsearch)
chim <- identify_contam_chimera_pq(data_fungi, method = "dada2")

# One filter call removes everything flagged
data_clean <- filter_contam_pq(
  data_fungi,
  rbind(corr, prim, chim)
)
```

## Control-based decontamination (a different tool)

`decontam_control_samples_pq()` and `decontam_control_taxa_pq()` are *not*
detectors and do not produce a `contam_tbl`. Instead of flagging whole taxa,
they estimate a background level from a control set and **zero out individual
occurrences** at or below it -- a per-cell correction. The control reference is
either negative/blank control *samples* or spike-in control *taxa*.

```{r, eval = FALSE}
# Background estimated from control SAMPLES, per taxon
pq <- mutate_samdata_pq(data_fungi, is_control = sample_sums(.) < 500)
decontam_control_samples_pq(pq, is_control)

# Background estimated from control TAXA (e.g. spike-ins), per sample
decontam_control_taxa_pq(data_fungi, Genus == "Tintelnotia")
```
