Bayesian RNA-seq transcript quantification tool
Project description
Bayesian RNA-seq quantification with joint mRNA, nascent RNA, and genomic DNA modeling
Overview
Rigel quantifies RNA-seq alignments while explicitly modeling three sources of signal in the same library:
- Mature RNA (mRNA)
- Nascent RNA (nRNA)
- Genomic DNA contamination (gDNA)
The implementation is built around a single-pass native BAM scan plus a
locus-level EM solver. A key architectural change in the current codebase is
that nRNA is no longer represented as one shadow per transcript. Instead,
Rigel builds a global table of unique nRNA spans keyed by (ref, strand, start, end) and shares each nRNA component across transcripts with the same
genomic span. This reduces redundant nRNA states in loci with many isoforms
that start and end at the same coordinates.
Key features
- Joint mRNA, nRNA, and gDNA quantification in one locus-level model
- Shared-span nRNA architecture with one component per unique genomic span
(ref, strand, start, end) - Single-pass C++ BAM scanner using htslib, with memory-bounded buffering and spill-to-disk support
- Automatic strand-model training from annotated spliced fragments; protocol auto-detection (
R1-sense/R1-antisense) - gDNA/RNA calibration via a bipartite region↔boundary belief-propagation sweep that deconvolves each genomic node's unspliced mass into the
(RNA₊, RNA₋, gDNA)simplex, library-agnostic - Empirical Bayes priors for nRNA fractions and gDNA rates; calibrated per-locus gDNA initialization
- MAP-EM and Variational Bayes EM (VBEM, default) solver modes with SQUAREM acceleration
- Discrete fragment assignment:
fractional,map, orsample(default) post-EM assignment modes - Parallel BAM scanning and parallel locus EM controlled through one
--threadssetting - Feather and TSV outputs plus optional annotated BAM output with per-fragment assignment tags
Installation
Bioconda
conda install -c conda-forge -c bioconda rigel
PyPI
pip install rigel-rnaseq
# with the optional HTML QC report ('rigel report'):
pip install 'rigel-rnaseq[report]'
The PyPI package name is rigel-rnaseq because rigel is already taken on
PyPI. The import name and CLI stay rigel.
The [report] extra pulls in vl-convert-python, which bundles the
Vega/Vega-Lite JavaScript runtime so reports are fully self-contained and render
offline. On conda, install it alongside with
conda install -c conda-forge vl-convert-python. Without it, rigel report
still builds a report — only the fragment-length charts are omitted.
From source
git clone https://github.com/mkiyer/rigel.git
cd rigel
mamba env create -f mamba_env.yaml
conda activate rigel
pip install --no-build-isolation -e .
Requirements
- Python 3.12+
- C++17-capable compiler
- Runtime dependencies:
numpy,pandas,pyarrow,pysam,pyyaml
On macOS, install Xcode Command Line Tools first:
xcode-select --install
Quick start
1. Build an index
rigel index \
--fasta genome.fa \
--gtf annotation.gtf \
-o index/
The FASTA must have a .fai index. If needed:
samtools faidx genome.fa
2. Quantify a BAM
rigel quant \
--bam sample.bam \
--index index/ \
-o results/
Input BAM requirements:
- Name-sorted or collated
NHtag present for multimapper handling- Splice-junction strand tag available for best strand-model training (
XSorts, or let Rigel auto-detect)
3. Inspect outputs
head results/quant.tsv
head results/gene_quant.tsv
head results/nrna_quant.tsv
head results/loci.tsv
cat results/summary.json
4. Build a QC report (optional)
rigel report results/ -o results/report.html
Produces a single self-contained HTML file (alignment fates, fragment
composition, strand model, fragment-length distributions, the mRNA/nRNA/gDNA
split, capture enrichment, a genome-wide gDNA-density track, and a searchable
gene table). It reads only the files rigel quant already wrote, so reports can
be built long after — and in bulk — without re-running quantification. Requires
the [report] extra (see Installation).
Output files
| File | Description |
|---|---|
quant.feather / quant.tsv |
Transcript-level abundance table (annotated mRNA + nRNA rows) with count, count_unambig, count_em, count_spliced, tpm, tpm_total_rna, effective lengths, and per-transcript QC columns |
gene_quant.feather / gene_quant.tsv |
Gene-level aggregates derived from transcript estimates |
nrna_quant.feather / nrna_quant.tsv |
nRNA-span-level abundance estimates (one row per unique genomic nRNA span) |
loci.feather / loci.tsv |
Per-locus EM summary |
summary.json |
Library protocol, strand specificity, per-category fragment-length summary statistics, the calibration scalars (gdna_density_global, rna_sense_frac, the gDNA/RNA strand overdispersions, n_regions), alignment counts, and global quantification totals (schema v2) |
fragment_lengths.feather |
Raw per-bin fragment-length histograms, tidy (category, length, count) |
calibration_track.feather / .bedgraph |
Per-region gDNA solution; the bedGraph is a genome-browser track (IGV / UCSC) |
gdna_density_kde.feather / gdna_density_nodes.feather |
Capture gDNA-density KDE diagnostic (written when the Phase-2 prior is fit) |
config.yaml |
Resolved run configuration (parameters, I/O paths). Rerun with rigel quant --config config.yaml |
report.html |
Optional self-contained QC report, built by rigel report (see step 4) |
locus_stats.feather |
Optional per-locus statistics, emitted only with --emit-locus-stats |
annotated.bam |
Optional annotated BAM with per-fragment assignment tags, written with --annotated-bam (a second BAM pass). Rigel guarantees a collated-in → collated-out contract: the output contains exactly the same records as the input (no drops, no duplications). |
tpm is normalized over annotated transcripts only; tpm_total_rna uses the
same numerator but normalizes over all RNA (annotated + synthetic nRNA spans),
so it is directly comparable to the nrna_quant TPM column.
The nrna values in transcript- and gene-level tables are derived from shared
nRNA-span counts that are pro-rated across transcripts sharing the same span.
How it works
Rigel runs one native BAM pass feeding three stages: scan, calibrate, and quantify.
Architecture
FASTA + GTF ──▶ Index Build (index.py) ──▶ Feather index files
│
BAM file ──────────────────────────────────────────┤
▼
┌──────────────────────────────────┐
│ Stage 1: BAM Scan & Training │
│ C++: BamScanner → Resolver │
│ Py: buffer.py, strand_model.py │
│ → FragmentBuffer + models + │
│ accumulator (AccumulatorPayload)│
└──────────────┬───────────────────┘
│ per-region/boundary mass
▼
┌──────────────────────────────────┐
│ Stage 2: gDNA/RNA Calibration │
│ Bipartite region↔boundary │
│ belief-propagation sweep │
│ Py: node_chain → bp_solver │
└──────────────┬───────────────────┘
│ per-locus Dirichlet prior
▼
┌──────────────────────────────────┐
│ Stage 3: Quantification │
│ score → route → build loci → │
│ per-locus EM │
│ C++: scoring, batch_locus_em │
│ Py: scan.py, locus.py, │
│ estimator.py │
└──────────────┬───────────────────┘
│ posterior counts
▼
┌──────────────────────────────────┐
│ Output: Feather / TSV / JSON │
│ Py: cli.py │
└──────────────────────────────────┘
BAM scan and model training
A native scanner reads the BAM once, resolves fragments against the indexed
annotation, classifies splice structure, trains strand and fragment-length
models, and writes resolved fragment data into a columnar buffer. In the same
pass it deposits fractional per-region and per-boundary fragment mass into a
C++ accumulator (four channels: unspliced ±, spliced sense/antisense),
producing the AccumulatorPayload that calibration consumes.
The main strand model is trained from annotated spliced fragments with
unambiguous gene assignment. Diagnostic exonic and intergenic strand models are
also retained for reporting, but gDNA itself is always scored with strand
probability 0.5.
gDNA/RNA calibration
Before per-locus EM, Rigel deconvolves each genomic node's unspliced
fragment mass into the 2-simplex (f_rna₊, f_rna₋, f_g) — sense-RNA /
antisense-RNA / gDNA. Calibration models only RNA-vs-gDNA; nascent-vs-mature
is separated downstream by the per-locus EM.
The deconvolution is a belief-propagation sweep over a bipartite
region↔boundary node chain. node_chain builds the chain from the accumulator
payload; bp_solver.node_sweep runs a single forward-backward pass (exact on
the chain, which is a forest of linear paths). Following the
count-zero-information principle, a fragment count carries no intrinsic
gDNA/RNA signal — a node's composition is set by exactly three sources:
- a strand likelihood — the Beta-Binomial tilt of the per-strand counts (the only intrinsic gDNA/RNA signal; the count enters only as overdispersed Fisher information);
- cross-node imputation — neighbour density messages at a belief-free Poisson disagreement variance, fit once; gDNA flows genomically, while per-strand RNA flows only where that strand is continuous across an edge (the transcript-structure gate);
- the global gDNA prior — the population baseline plus a trained Phase-2 gDNA-density KDE.
Calibration fits the library hyperparameters (gdna_density_global,
rna_sense_frac, and the gDNA/RNA strand Beta-Binomial overdispersions) plus
the per-region and per-boundary deconvolved gDNA/RNA mass. These are bridged
into two per-locus Dirichlet scalars (gdna_prior_count,
rna_prior_count) that set the gDNA-vs-RNA split feeding the EM. See
docs/calibration/CALIBRATION_ARCHITECTURE.md
for the full theory.
Locus-level EM
Ambiguous fragments are scored, routed into CSR form, and grouped into
connected components of overlapping transcripts. Each locus is an independent
subproblem with n_t + 1 components — one per transcript row (annotated
mRNA and synthetic nRNA spans alike, since unique nRNA spans are materialized
as ordinary transcript rows) plus one merged gDNA component.
The solver runs VBEM (default; digamma soft updates) or MAP-EM with SQUAREM
acceleration, parallelized across loci with OpenMP. The calibration prior
enters as the two per-locus Dirichlet scalars; the EM distributes RNA mass
among the compatible transcripts. Post-EM fragments are assigned using the
configured assignment mode (sample by default).
Documentation
| Document | Description |
|---|---|
| docs/MANUAL.md | CLI reference, parameter defaults, configuration rules, and output schema |
| docs/METHODS.md | Algorithmic description of the implemented model and priors |
| docs/PUBLISHING.md | Release workflow for PyPI and Bioconda |
| docs/parameters.md | Complete parameter reference with defaults and config dataclass mapping |
Citing Rigel
If you use Rigel in research, cite the repository for now:
Iyer MK. Rigel: Bayesian RNA-seq quantification with joint mRNA, nascent RNA, and genomic DNA modeling. 2026. https://github.com/mkiyer/rigel
License
Rigel is distributed under the GNU General Public License v3.0.
Development
pytest tests/ -v
pytest tests/ --cov=rigel --cov-report=term-missing
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rigel_rnaseq-0.7.1.tar.gz.
File metadata
- Download URL: rigel_rnaseq-0.7.1.tar.gz
- Upload date:
- Size: 5.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55f33b3324556940f91711b4cf572247168bd585a2c31c9f53e04f8c06ede25b
|
|
| MD5 |
08f0598f8a7de7479604b5b79fe8453c
|
|
| BLAKE2b-256 |
8e303a7b3e5bc46509ea7753bad2c07f3e6b2e99d7d5fdb641dd83c704ac6f67
|
Provenance
The following attestation bundles were made for rigel_rnaseq-0.7.1.tar.gz:
Publisher:
publish.yml on mkiyer/rigel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rigel_rnaseq-0.7.1.tar.gz -
Subject digest:
55f33b3324556940f91711b4cf572247168bd585a2c31c9f53e04f8c06ede25b - Sigstore transparency entry: 2152854447
- Sigstore integration time:
-
Permalink:
mkiyer/rigel@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/mkiyer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 7.6 MB
- Tags: CPython 3.12+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13a0b9593a5747f1555a91434adf0315fdcb8987da3fd23a38cb64887c9dfec8
|
|
| MD5 |
d7d795d7dcd98df62c3c8946f59d4d89
|
|
| BLAKE2b-256 |
1fd25839bd9a9a03534bd2260fbf1d0a06a91298f864ddf84c70e0feeea46660
|
Provenance
The following attestation bundles were made for rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on mkiyer/rigel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
13a0b9593a5747f1555a91434adf0315fdcb8987da3fd23a38cb64887c9dfec8 - Sigstore transparency entry: 2152855015
- Sigstore integration time:
-
Permalink:
mkiyer/rigel@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/mkiyer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 7.2 MB
- Tags: CPython 3.12+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4912bb35c66302dd1fc094eaca823329c5754069ed9a1ccc7e6c05c352d70a4
|
|
| MD5 |
e0f1d456795feac7c799bbe5c7ec5101
|
|
| BLAKE2b-256 |
37d182daa86670296d2f5cde47dfee48d47a34614f26bc5a8c40e17d4ad599f7
|
Provenance
The following attestation bundles were made for rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_aarch64.whl:
Publisher:
publish.yml on mkiyer/rigel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rigel_rnaseq-0.7.1-cp312-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
c4912bb35c66302dd1fc094eaca823329c5754069ed9a1ccc7e6c05c352d70a4 - Sigstore transparency entry: 2152854848
- Sigstore integration time:
-
Permalink:
mkiyer/rigel@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/mkiyer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file rigel_rnaseq-0.7.1-cp312-abi3-macosx_15_0_arm64.whl.
File metadata
- Download URL: rigel_rnaseq-0.7.1-cp312-abi3-macosx_15_0_arm64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.12+, macOS 15.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbd43fa2cb92c9666590520d82b5d1070bb985af81cb1a16f7c67337a6ab7494
|
|
| MD5 |
a032a4a4f81539c71c2e0139c8390e9c
|
|
| BLAKE2b-256 |
ac1705b69790da45f01d5fa4a004adf383ad18f5116493614a628744408e073d
|
Provenance
The following attestation bundles were made for rigel_rnaseq-0.7.1-cp312-abi3-macosx_15_0_arm64.whl:
Publisher:
publish.yml on mkiyer/rigel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rigel_rnaseq-0.7.1-cp312-abi3-macosx_15_0_arm64.whl -
Subject digest:
dbd43fa2cb92c9666590520d82b5d1070bb985af81cb1a16f7c67337a6ab7494 - Sigstore transparency entry: 2152854620
- Sigstore integration time:
-
Permalink:
mkiyer/rigel@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/mkiyer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff26d8e59b7e0290b9a01a920714eb006173aec5 -
Trigger Event:
push
-
Statement type: