Metadata-Version: 2.4
Name: denseclass
Version: 0.1.0
Author: linlian
Author-email: 21620151153308@stu.xmu.edu.cn
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Operating System :: POSIX :: Linux
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENCE.txt
Requires-Dist: numpy>=1.23
Requires-Dist: scipy>=1.9
Requires-Dist: pandas>=1.5
Requires-Dist: h5py>=3.7
Requires-Dist: torch>=2.0
Requires-Dist: tqdm>=4.64
Requires-Dist: toml>=0.10
Requires-Dist: scikit-learn>=1.1
Requires-Dist: matplotlib>=3.6
Requires-Dist: seaborn>=0.12
Requires-Dist: biopython>=1.80
Requires-Dist: numba>=0.57
Requires-Dist: plotnine>=0.12
Requires-Dist: ont-fast5-api>=4.1
Requires-Dist: ont-bonito>=0.7
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python

<div align="center">

# 🦠 **denseclass**

**Nanopore signal classification** — label every raw read by species, barcode or taxon,
straight from the current, with no basecalling step.

[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENCE.txt)

</div>

---

## 📖 Table of Contents

- [Overview](#-overview)
- [Installation](#-installation)
- [Quick start](#-quick-start)
- [Subcommands](#-subcommands)
- [Training modes](#-training-modes)
- [Examples](#-examples)
- [Relationship to densecall](#-relationship-to-densecall)
- [Development](#-development)

---

## 🧬 Overview

Reads are trimmed to their informative region (adapter/polyA detection for DNA,
poly(A)-tail trimming for RNA), encoded, and passed through a small 1-D CNN that
predicts one class per read. Training works either on **real** labelled reads or on
**signal simulated** from reference genomes, so you can build a classifier without
per-species reads for every class.

This package was split out of [DenseCall](https://github.com/n-damo/densecall) and
now stands alone — see [Relationship to densecall](#-relationship-to-densecall).

---

## 📦 Installation

```bash
git clone <this-repo>
cd denseclass
pip install -e .
```

`torch` is deliberately unpinned so the resolver picks a build matching your local
CUDA toolkit. For GPU basecalling-adjacent work, install the CUDA toolkit first and
verify `nvcc` is on `$PATH`:

```bash
conda install -c nvidia cuda-toolkit=12.8
```

---

## 🚀 Quick start

```bash
denseclass --help
denseclass label --help
```

---

## 🎯 Subcommands

| Subcommand | Purpose |
|:--|:--|
| `label` | Build `label_map.json` / `inverse_label_map.json` from a FASTA whose headers are the class names |
| `split` | Split a read→label pairs file into train / test sets |
| `gendata` | Convert POD5/FAST5 + labels into `train.hdf5` / `valid.hdf5` |
| `train` | Train the classification CNN (real or simulated data) |
| `predict` | Classify reads with a trained model |
| `precision` | One-class precision / recall / F1 / ROC evaluation |
| `evaluation` | Full multiclass panel (confusion matrix, PR/ROC, ...) |
| `comparison` | Side-by-side comparison of two models |

---

## 🧪 Training modes

| Mode | Description |
|:--|:--|
| **Real-data** | `gendata` extracts signal chunks from reads already labelled by species, then `train` (no `--simu`) fits the CNN directly. |
| **Simulation** | `train --simu <refs.fa> --preset <name>` synthesises chunks on the fly from a FASTA of reference genomes. Presets: `dna-r9-min`, `dna-r10-min`, `rna-r9-min`, `rna004-min`, ... |

The CNN architecture is set by a small TOML (`dna.toml` with `strides=[2,2,2,2,2]` for
DNA, `rna.toml` with `strides=[5,2,2,2,2]` for RNA) passed via `-config`. The
`label_map.json` / `inverse_label_map.json` pair must be produced first with
`denseclass label`.

---

## 🧪 Examples

### Barcode / species classification on real reads

```bash
# 1. build the label map
denseclass label species.fa

# 2. split read→label pairs
denseclass split readid_species.txt --train_file train_labels.txt --test_file test_labels.txt

# 3. extract training chunks
denseclass gendata train.pod5 \
  --label_path train_labels.txt --save_path ./ --seqlen 6000 --do-trim

# 4. train
denseclass train model_real \
  -config dna.toml --directory ./ --label-map label_map.json \
  --chunksize 6000 -f --new -y

# 5. predict
denseclass predict model_real test.pod5 inverse_label_map.json \
  --chunksize 6000 > result_real.txt

# 6. evaluate
denseclass evaluation result_real.txt test_labels.txt \
  -m label_map.json -o ./real
```

### Simulation-based training (no real per-species data)

```bash
denseclass label species.fa

denseclass train model_simu \
  -config dna.toml --directory ./ --label-map label_map.json \
  --chunksize 25000 -f --new --simu species.fa --preset dna-r10-min -y

denseclass predict model_simu reads_dir/ inverse_label_map.json \
  --chunksize 25000 > result_simu.txt

denseclass precision result_simu.txt test_labels.txt -m label_map.json
```

### RNA direct-read classification

RNA reads are reverse-complement mapped and sequenced after the poly(A) tail, so
`gendata` / `predict` take `--rna --tail`, and RNA models use `rna.toml`:

```bash
denseclass gendata train.pod5 \
  --label_path train_labels.txt --save_path ./ --rna --seqlen 50000 --tail

denseclass train model \
  -config rna.toml --directory ./ --label-map label_map.json \
  -f --new -y --chunksize 50000 --rna

denseclass predict model test.pod5 inverse_label_map.json \
  --rna --tail --chunksize 50000 > result_real.txt
```

---

## 🔗 Relationship to densecall

This package was previously `densecall classify`, wrapping `densecall/microbiome/`.
It is now standalone:

- **No `densecall` import anywhere.** The one helper that used to be shared
  (`convert_base_name`) is vendored in `denseclass/base_util.py`.
- **Separate dependency set and release cycle.** Install and upgrade it on its own.
- **The trained `model/` directory is a normal model directory** and can be used with
  the DenseCall basecalling `train` / `predict` tooling where applicable.

Migration is a command rename:

| Before | After |
|:--|:--|
| `densecall classify label` | `denseclass label` |
| `densecall classify gendata` | `denseclass gendata` |
| `densecall classify train` | `denseclass train` |
| `densecall classify predict` | `denseclass predict` |

All flags are unchanged.

---

## 🛠 Development

```bash
pytest tests/            # structural checks: imports, CLI tree, packaging
```

The test suite is purely structural — it verifies that every module imports, the
command tree builds and formats, and the packaging metadata is consistent. It needs
no signal data or checkpoints. End-to-end behaviour is exercised through the examples
above.

### Publishing

```bash
# 1. bump __version__ in denseclass/cli.py
python -m build
twine check dist/* && twine upload dist/*
```

---

## 📄 License

MIT — see [LICENCE.txt](LICENCE.txt).
