Metadata-Version: 2.4
Name: sniffcell
Version: 0.9.8a1
Summary: SniffCell annotates structural variants using long-read methylation evidence and ctDMR signals.
Home-page: https://github.com/Fu-Yilei/SniffCell
Author: Yilei Fu
Author-email: yilei.fu@bcm.edu
License: Apache-2.0
Project-URL: Bug Tracker, https://github.com/Fu-Yilei/SniffCell/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pysam>=0.21.0
Requires-Dist: numpy>=2.2.0
Requires-Dist: pandas>=2.3.0
Requires-Dist: scipy
Requires-Dist: tqdm
Requires-Dist: scikit-learn
Requires-Dist: matplotlib
Provides-Extra: discover
Requires-Dist: tdb; extra == "discover"
Requires-Dist: seaborn>=0.13; extra == "discover"
Provides-Extra: discover-plots
Requires-Dist: seaborn>=0.13; extra == "discover-plots"
Provides-Extra: igvreport
Requires-Dist: igv-reports; extra == "igvreport"
Provides-Extra: full
Requires-Dist: tdb; extra == "full"
Requires-Dist: seaborn>=0.13; extra == "full"
Requires-Dist: igv-reports; extra == "full"
Dynamic: license-file

# SniffCell — 5hmC-compatible branch

[![PyPI version](https://img.shields.io/pypi/v/sniffcell.svg)](https://pypi.org/project/sniffcell/)
[![Python](https://img.shields.io/badge/python-%3E%3D3.10-3776AB?logo=python&logoColor=white)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Issues](https://img.shields.io/badge/Issues-GitHub-red?logo=github)](https://github.com/Fu-Yilei/SniffCell/issues)

SniffCell links somatic structural variants (SVs) and tandem-repeat (TR)
expansions/contractions to the cell type they occurred in, using long-read DNA
methylation. It calls cell-type-specific differentially methylated regions
(ctDMRs) from a reference methylation atlas, discovers SVs and TRs directly
from long-read BAMs, extracts read-level methylation, and assigns each
variant's supporting reads to the cell population whose methylation profile
they match.

This branch supports separate 5mC and 5hmC atlas signals for cell-type
deconvolution.

## Which Package Should I Use?

Use **`sniffcell`** when you are discovering variants from a BAM (no existing
callset yet):

- ctDMR discovery from an atlas (`find`)
- cell-type deconvolution and BAM splitting (`deconv`)
- cell-type-aware SV, tandem-repeat, and SNV discovery (`discover`)
- methylation-based annotation of the discovered variants (`anno`, `svanno`)
- visualization, IGV screenshots, differential methylation tests, and HTML reports

Use **`sniffcell-lite`** when you already have a variant callset with each
variant's supporting reads identified (e.g. from Sniffles/kanpig or another
caller) and just want fast ctDMR-based cell-type annotation, without running
the full deconvolution/discovery pipeline:

- `sniffcell-lite find`
- `sniffcell-lite anno`

`sniffcell-lite` is published as a separate PyPI package and does not replace
the full `sniffcell` package:

```bash
pip install sniffcell-lite
sniffcell-lite --help
```

The lite package is maintained in the separate
[`Fu-Yilei/SniffCell-lite`](https://github.com/Fu-Yilei/SniffCell-lite)
repository.

## Install SniffCell

**5hmC alpha: v0.9.8a1.** Install the prerelease explicitly:

```bash
pip install 'sniffcell==0.9.8a1'
```

See the [release notes](https://github.com/Fu-Yilei/SniffCell/releases/tag/v0.9.8a1)
and the **[benchmark blog, bar plots, and implementation details](https://github.com/Fu-Yilei/SniffCell-analysis/blob/5hmc/analyses/06_06_heldout_validation/BLOG_UPDATE.md)**.
The blog evaluates a three-donor atlas with bcontrol1 held out; the downloadable
atlas uses all four donors. This is an early-testing release.

To install the branch directly instead:

```bash
pip install "git+https://github.com/Fu-Yilei/SniffCell.git@5hmC_compatitible_atlas"
```

For the full external-tool environment:

```bash
micromamba env create -f environment.yml
micromamba activate sniffcell
pip install "git+https://github.com/Fu-Yilei/SniffCell.git@5hmC_compatitible_atlas"
```

Maintainers can follow [the prerelease procedure](docs/5hmc-prerelease.md). Only release tags trigger package publication.

## Methylation Atlases

Download the processed methylation atlas inputs and precomputed cell-type-specific
differentially methylated regions (ctDMRs) from
[Zenodo](https://zenodo.org/records/22003085). For the legacy NumPy `find` interface, place
`all_celltypes_blocks.npy`, `all_celltypes_blocks.index.gz`,
`index_to_major_celltypes.json`, and `all_celltypes.txt` in the `atlas/` directory.
Precomputed ctDMR tables are available for brain/cerebellum, PBMC, lung, liver,
pancreas, kidney, breast, and colon, and can be supplied directly to `deconv`
or `anno` with `-b` instead of running `find`.

To discuss tissue-specific atlases, additional tissues or cell types, or custom
atlas support, please [open a GitHub issue](https://github.com/Fu-Yilei/SniffCell/issues)
or [email us](mailto:yilei.fu@bcm.edu).

**Underlying 5hmC data:** Raw 5hmC inputs used in the paper remain subject to
access restrictions. The derived four-donor scoring catalog is available in
[the 5hmC atlas directory](atlases/5hmc/README.md). For access inquiries and guidance on achieving better
performance with the 5hmC-compatible workflow, please
[email us](mailto:yilei.fu@bcm.edu).

The [held-out benchmark and implementation update](https://github.com/Fu-Yilei/SniffCell-analysis/blob/5hmc/analyses/06_06_heldout_validation/BLOG_UPDATE.md) reports precision and recall on identical FANS reads.

## Example Workflows

### SniffCell: discover and annotate SVs/TRs from a BAM

1. Call ctDMRs from an atlas:

```bash
sniffcell find \
  --mdb combined_loyfer_ont.mmdb \
  --assay dual \
  -cf atlas/celltypes.json \
  -ck brain_cereb_ont \
  -o brain_dual_ctdmr.tsv \
  --diff_threshold 0.40
```

`--assay dual` calls separate 5mC and 5hmC views and records the assay in the
`modification` column; it does not collapse the two signals. The older
`--npy/--index/--meta` interface remains available as a legacy compatibility
path.

See the [custom MDB atlas Wiki tutorial](https://github.com/Fu-Yilei/SniffCell/wiki/Build-a-Custom-MDB-Atlas-from-bedMethyl)
for the complete bedMethyl-to-ctDMR workflow. Use an atlas with separate 5mC
and 5hmC assays and matching cell-type metadata; replace the example MDB and
metadata paths with your own inputs. See the access note above for the 5hmC
signal used in the paper.

2. Split the BAM into cell-type groups using those ctDMRs:

```bash
sniffcell deconv \
  -i sample.bam \
  -r ref.fa \
  -b brain_dual_ctdmr.tsv \
  -o deconv_out \
  --bam-modification auto \
  --split_bam_groups "Neuron=Neuron;Oligodendrocyte=Oligodendrocyte" \
  -t 8
```

With `--bam-modification auto` (the default), each ctDMR uses the channel named
in its `modification` column: BAM `C+m` calls for `5mC`, `C+h` calls for
`5hmC`, and both for legacy `modifiedC` rows. Use an explicit `5mC`, `5hmC`,
or `modifiedC` value only to override every catalog row for a control analysis.
Catalogs without a `modification` column retain the previous combined-modified-C
behavior.

3. Discover SVs and tandem repeats from the two cell-type-split BAMs:

```bash
sniffcell discover tools run \
  --deconv-dir deconv_out \
  --reference ref.fa \
  --tr-bed tr_catalog.bed \
  --sex female \
  --run-id run1 \
  --threads 8
```

This runs Sniffles/Kanpig/Truvari (SVs), TRGT or Medaka (tandem repeats), and
optionally Clair3 (SNVs) on the two split BAMs, then harmonizes everything
into `deconv_out/deconv_requested_group_splits/discover/run1/harmonized_variants.tsv`.
Tool binaries are resolved from `PATH` by default, or pass explicit
`--sniffles-bin`/`--trgt-bin`/etc. flags; run `sniffcell discover tools check`
to preflight-check dependencies first.

4. Annotate the discovered SVs/TRs with cell-type methylation evidence:

```bash
sniffcell anno \
  -i sample.bam \
  -v deconv_out/deconv_requested_group_splits/discover/run1/harmonized_variants.tsv \
  -r ref.fa \
  -b brain_dual_ctdmr.tsv \
  -o anno_out \
  -t 8
```

5. Build an HTML review report:

```bash
sniffcell report --anno_output anno_out
```

Open `anno_out/report/index.html` to review high-confidence calls and figures.

### SniffCell Lite: annotate an existing callset

If you already have a variant and know its supporting read names, skip
deconvolution and discovery entirely:

```bash
sniffcell-lite find -ck "Colon, Ascending" -o colon_ascending.ctdmr.tsv

sniffcell-lite anno \
  -i sample.bam \
  -r ref.fa \
  --variant-name variant_001 \
  --variant-location chr1:100000-101000 \
  --supporting-reads readA,readB,readC \
  --catalog colon_ascending.ctdmr.tsv \
  -o anno_out
```

`sniffcell-lite anno` also supports a `--batch variants.tsv` mode for
annotating many variants at once. See the
[SniffCell Lite README](https://github.com/Fu-Yilei/SniffCell-lite)
for details.

## Main Commands

| Command | Purpose |
|---------|---------|
| `sniffcell find` | Call ctDMRs from a methylation atlas |
| `sniffcell anno` | Extract BAM methylation and assign SVs/TRs to cell types |
| `sniffcell svanno` | Re-score SVs from a saved read-classification table |
| `sniffcell deconv` | Classify all reads and optionally split BAMs by group |
| `sniffcell discover` | Run cell-type-aware SV / TR / SNV discovery |
| `sniffcell viz` | Render per-SV methylation figures |
| `sniffcell igvviz` | Generate IGV batch screenshots |
| `sniffcell report` | Filter calls and build an HTML review report |
| `sniffcell dmsv` | Test methylation differences around SVs |

## Inputs

| Input | Format | Used by |
|-------|--------|---------|
| Long-read alignment | BAM with `MM` / `ML` modification tags | `anno`, `deconv`, `discover`, `dmsv`, `viz` |
| Variants | VCF / VCF.GZ, harmonized TSV from `discover`, or a variant + supporting-read names (`sniffcell-lite`) | `anno`, `dmsv`, `viz`, `report` |
| Reference genome | FASTA plus index | `anno`, `deconv`, `discover`, `dmsv`, `viz` |
| ctDMR table | TSV from `sniffcell find` | `anno`, `deconv`, `viz` |
| Methylation atlas | MDB atlas with separate assay views, or legacy NumPy matrix, CpG index, and metadata | `find` |

## Outputs

A `find -> deconv -> discover -> anno -> report` run produces:

```text
brain_dual_ctdmr.tsv
deconv_out/
  deconv_summary.tsv
  deconv_reads_classification.tsv
  deconv_requested_group_splits/
    <group>.bam
    discover/run1/
      harmonized_variants.tsv
      run_summary.json
anno_out/
  reads_classification.tsv
  blocks_classification.tsv
  sv_assignment.tsv
  sv_assignment_readable.tsv
  sv_assignment_readable_long.tsv
  anno_run_manifest.json
  report/
    index.html
    high_confidence_sv.tsv
    figures/
```

A `sniffcell-lite find -> anno` run produces:

```text
colon_ascending.ctdmr.tsv
colon_ascending.ctdmr.tsv.igv.bed
anno_out/
  variant_assignment.tsv
  variant_assignment_readable.tsv
  reads_classification.tsv
  anno_compact_manifest.json
```

### Discovery VCF exports

`sniffcell discover tools run` automatically exports matching caller records
beside `harmonized_variants.tsv`, when the corresponding source VCFs exist:

```text
harmonized_variants.sv.vcf.gz
harmonized_variants.tr.<group>.vcf.gz
harmonized_variants.snv.<group>.vcf.gz
```

Each VCF is coordinate-sorted, BGZF-compressed, and tabix-indexed. SV records
come from the joint Sniffles/Truvari/Kanpig postprocessing VCF; TR records come
from each group's TRGT VCF; SNV records come from each group's Clair3 pileup
VCF used for comparison. Original caller alleles, genotypes, quality, and
filters are retained. These are subsets, not copies of the full callsets.

Additional INFO fields describe the SniffCell evidence:

| INFO field | Meaning |
|------------|---------|
| `SC_ID`, `SC_ROW` | Harmonized variant ID and one-based data-row number |
| `SC_CLASS`, `SC_SUBTYPE` | Variant class and change subtype |
| `SC_CATEGORY` | `group_a_only`, `group_b_only`, `shared`, or `unknown` |
| `SC_GROUP_A`, `SC_GROUP_B` | Actual comparison-group labels |
| `SC_TARGET_GROUP` | Group carrying the candidate change; absent for shared/unknown calls |
| `SC_SUPPORT_A`, `SC_SUPPORT_B` | Support counts from the harmonized TSV |
| `SC_CHANGE_BP` | SniffCell change size; for TRs, a between-group difference |

String values are percent-encoded so composite cell-type labels remain intact.
These annotations identify **split-BAM group-specific candidates**, not
methylation-confirmed assignments from `anno`. Zero support does not establish
reference genotype or coverage. For TRs, annotations describe a locus-level
change, not necessarily a particular TRGT ALT allele; `SC_CHANGE_BP` is not
reference-relative `SVLEN`. Multiple harmonized changes at one locus yield
separate annotated copies, distinguished by `SC_ROW`.

Missing source records are not reconstructed. Export paths, counts, and
unmatched data-row numbers are recorded in `harmonized_variants_manifest.json`,
with warnings for missing matches. Medaka-only TR runs currently have no TRGT
VCF export. An opposite-group SNV record may be absent even when the target
group has a matching call. These VCFs preserve caller genotypes rather than
inferring somatic genotypes; they are not somatic truth sets.

## Documentation

For command-line options, run `sniffcell --help` or
`sniffcell <command> --help` (for example, `sniffcell anno --help`).

Full documentation is in the [GitHub Wiki](https://github.com/Fu-Yilei/SniffCell/wiki):

| Page | Contents |
|------|----------|
| [Installation](https://github.com/Fu-Yilei/SniffCell/wiki/Installation) | PyPI, conda, Docker, and tool setup |
| [SniffCell Lite](https://github.com/Fu-Yilei/SniffCell/wiki/SniffCell-Lite) | Annotating an existing callset with `sniffcell-lite` |
| [Find Workflow](https://github.com/Fu-Yilei/SniffCell/wiki/Find-Workflow) | ctDMR discovery parameters |
| [Methods](https://github.com/Fu-Yilei/SniffCell/wiki/Methods-Deconv-Discover-Anno) | Technical methods for core commands |
| [CLI Reference](https://github.com/Fu-Yilei/SniffCell/wiki/CLI-Reference) | Command-line options |
| [Test Examples](https://github.com/Fu-Yilei/SniffCell/wiki/Test-Examples) | Validation and QA examples |
| [SH3RF3 dual SV/TR example](https://github.com/Fu-Yilei/SniffCell/wiki/SH3RF3-Dual-SV-TR-Example) | Native-GRCh38 regional BAM example from atlas through report |

## Citation

If you use SniffCell in your research, please cite:

> **[Cell-type-resolved somatic variant discovery from bulk long-read sequencing](https://www.medrxiv.org/content/10.64898/2026.09.01.26361966v1)**
> Yilei Fu et al. *medRxiv preprint (2026).* DOI: 10.64898/2026.09.01.26361966.

## License

Apache License 2.0. See [LICENSE](LICENSE) for details.
