Per-cell TF activity inference with learned post-translational regulation detection from scRNA-seq
Project description
RegStatusNet
GRN-constrained structured latent space for per-cell transcription factor activity inference — with learned post-translational regulation detection
What it does
RegStatusNet infers per-cell transcription factor (TF) activity from scRNA-seq data alone. Unlike linear methods (VIPER, decoupleR), it:
- Assigns each latent dimension to a named TF (not an abstract factor)
- Enforces activator/repressor sign polarity from DoRothEA as a hard architectural constraint
- Learns a per-TF parameter α that identifies which TFs are post-translationally regulated — without any PTM supervision
- Scales to 100k+ cells with adversarial batch correction
Key result: α correctly assigns low values to 14/16 known PTM regulators (87.5% recall), including the NF-κB, JAK-STAT, FOXO, and TGF-β/SMAD families, independently confirmed by ATAC chromatin concordance (Spearman ρ=+0.468, p=5.3×10⁻³).
Quickstart (3 lines)
import regstatusnet as rsn
model = rsn.Predictor.from_pretrained("pbmc_multiome_v1") # downloads ~200 MB from Zenodo
z = model.transform(adata) # (cells, 91) TF activity matrix
The pretrained PBMC model (pbmc_multiome_v1) is hosted at Zenodo:
DOI: 10.5281/zenodo.20470333
Installation
pip install regstatusnet
Or clone for development:
git clone https://github.com/JiaenLin/RegStatusNet.git
cd RegStatusNet
pip install -e .
Full API
import regstatusnet as rsn
# Load from Zenodo (auto-downloads on first call)
model = rsn.Predictor.from_pretrained("pbmc_multiome_v1")
# Or from a local checkpoint
model = rsn.Predictor.from_pretrained("runs/my_model/best_model.pt")
# Run inference — auto gene alignment, handles missing genes
z = model.transform(adata, batch_size=512) # (cells, 91) numpy array
# With uncertainty and α
out = model.transform(adata, return_dict=True)
# out["z"] — (cells, 91) TF activity
# out["logvar"] — (cells, 91) uncertainty (log-variance)
# out["alpha"] — (91,) per-TF α values (model property, not cell-specific)
# Interpret α
print(model.alpha_table()) # DataFrame: TF, alpha, tier
print(model.tf_names[:5]) # ['AR', 'ATF1', 'ATF2', ...]
Pretrained model: pbmc_multiome_v1
| Property | Value |
|---|---|
| Training data | PBMC 10k Multiome (10x Genomics) |
| Cells | 11,620 |
| Cell types | 17 (CellTypist Immune_All_Low) |
| TFs | 91 (DoRothEA AB confidence) |
| GRN edges | 3,373 (95.4% activating) |
| Input genes | 3,257 (3,000 HVGs + 257 forced TF genes) |
Validated benchmarks:
- DoRothEA+viper: 78% of TFs r > 0.5, mean r = +0.641 (+0.44 above null)
- Perturb-seq specificity: top-5 hit rate 16.5% vs 5.5% chance (p=1.3×10⁻⁴)
- PTM recall: 87.5% (14/16 known PTM regulators assigned α < 0.05)
- ATAC chromatin validation: Spearman(α, ρ_atac) = +0.468, p=5.3×10⁻³
Use cases
| Notebook | Description |
|---|---|
docs/use_cases/pbmc_example.ipynb |
Quickstart: load model, run inference, visualise |
docs/use_cases/uc2_ifn_stimulation.ipynb |
Apply to IFN-β stimulation data (Kang 2018) |
docs/use_cases/uc3_ptm_discovery.ipynb |
Discover PTM-regulated TFs in your own PBMC data |
Train on your own data
Data requirements:
adata.X— raw integer counts (not log-normalized)adata.var_names— HGNC gene symbols (e.g.TP53, not Ensembl IDs)adata.obs— a column with cell-type labels (string)
Option A — one-liner (sensible defaults):
import regstatusnet as rsn
ckpt = rsn.train("my_tissue.h5ad", label_col="cell_type", output_dir="runs/my_model")
model = rsn.Predictor.from_pretrained(str(ckpt))
z = model.transform(adata) # (cells, n_tfs) TF activity
Option B — programmatic config (no YAML needed):
import regstatusnet as rsn
cfg = rsn.get_default_config()
cfg["training"]["n_epochs"] = 150
cfg["data"]["n_hvgs"] = 4000 # increase for diverse tissues (brain, lung)
cfg["grn"]["confidence"] = "ABC" # more TF-target edges
ckpt = rsn.train("brain.h5ad", config=cfg, output_dir="runs/brain_v1")
Option C — CLI (after pip install regstatusnet):
regstatusnet-train --h5ad my_tissue.h5ad --label_col cell_type --out runs/my_model
# More options
regstatusnet-train --h5ad brain.h5ad --out runs/brain_v1 \
--label_col leiden --n_epochs 150 --n_hvgs 4000 \
--confidence ABC
Output:
runs/my_model/
best_model.pt ← checkpoint with embedded gene names + config
history.csv ← per-epoch loss log
See docs/extending_to_new_tissues.md for tissue-specific hyperparameter guidance, GRN coverage checks, and validation against VIPER.
Reproduce paper figures
# Generate Figures 2–5 (requires Stage 4 analysis CSVs from HPC)
bash scripts/make_figures.sh
# Generate Supplementary Figures S1–S2 (self-contained, no data needed)
python scripts/plot_supplementary.py --out_dir figures
# Generate Figure 1 UMAP (requires checkpoint + h5ad)
python scripts/plot_figure1_umap.py \
--ckpt runs/stage2_multiome/best_model.pt \
--h5ad data/pbmc10k_multiome.h5ad
# Generate Figure 1 A–C schematic (PowerPoint)
python scripts/make_figure1_schematic.py
Docker
# Build image
docker-compose build
# CPU inference — mount your h5ad at /data and run a script
docker-compose run \
-v /path/to/your/data:/data \
regstatusnet python -c "
import regstatusnet as rsn
import scanpy as sc
adata = sc.read_h5ad('/data/your_pbmc.h5ad')
model = rsn.Predictor.from_pretrained('pbmc_multiome_v1')
z = model.transform(adata)
print('z shape:', z.shape)
"
# GPU inference — requires nvidia-container-toolkit
docker-compose run \
-v /path/to/your/data:/data \
regstatusnet-gpu python your_script.py
# Jupyter Lab (CPU) — open http://localhost:8888 after running
docker-compose up notebook
Environment variables (see .env.example):
REGSTATUSNET_CACHE— override checkpoint cache directoryREGSTATUSNET_REF_H5AD— path to reference h5ad (locally-trained models only)
Security note: The notebook service disables the Jupyter token for ease of use. This is safe for local development but do not expose port 8888 on a public network.
Citation
If you use RegStatusNet, please cite:
@software{lin2026regstatusnet,
title = {RegStatusNet: A GRN-constrained structured latent space identifies
post-translationally regulated transcription factors from scRNA-seq},
author = {Lin, Jiaen},
year = {2026},
doi = {10.5281/zenodo.20470333},
url = {https://github.com/JiaenLin/RegStatusNet}
}
License
MIT © 2026 Lin Jiaen
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 Distribution
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 regstatusnet-1.0.2.tar.gz.
File metadata
- Download URL: regstatusnet-1.0.2.tar.gz
- Upload date:
- Size: 210.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cec645329d9af5fb0d11cbaed0900c06b1c68d085f8347c26768e3132616d46e
|
|
| MD5 |
dc29c3d0dee7e776a8d85222956557d7
|
|
| BLAKE2b-256 |
9e0d213570339fafc47289ce9be7942ad0930f42c4086af71b04a01990f63bf6
|
File details
Details for the file regstatusnet-1.0.2-py3-none-any.whl.
File metadata
- Download URL: regstatusnet-1.0.2-py3-none-any.whl
- Upload date:
- Size: 207.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c00dcdc4582dfdc127d121a5089d7135e6244a01deecc00b40831598aa5c6d70
|
|
| MD5 |
5efe211487fec77c3157a8a51264511b
|
|
| BLAKE2b-256 |
e1fcf0756709bcd7a806dac9b3f91bd16f2e0567a67090d95e334c7aa37bd487
|