Rust implementation of the SCENIC single-cell GRN pipeline (GRN + cisTarget + AUCell)
Project description
scenic-rs
A memory-efficient Rust implementation of the pySCENIC single-cell gene regulatory network (GRN) pipeline. Not associated with the lab, just built this as a quick project!
Benefits
- Implements the same algorithms as pySCENIC (GRNBoost2, GENIE3, AUCell, CTX trimming)
- Can use modern numpy/pandas in your environment
- Memory usage is constant with increased parallelism, allowing for faster execution without OOM
Requirements
Runtime (using scenic-rs)
- Python ≥ 3.9
numpy,pandasscanpy(optional) — only if you use it to load your data (Cell Ranger /.h5ad); scenic-rs itself just takes a numpy matrix + gene/TF names- For the
ctxstep only: the cisTarget ranking databases (*.genes_vs_motifs.rankings.feather) and the motif2TF annotations (.tbl), from resources.aertslab.org/cistarget
From source (optional — only for development; pip install uses prebuilt wheels)
- A recent stable Rust toolchain (
cargo/rustc) — ≥ 1.70 (tested on 1.86); install via rustup.rs. - maturin ≥ 1.0 (
pip install maturin), thenmaturin develop --release
Benchmarks / validation only (optional)
- A separate pySCENIC environment to compare against:
python3.10 -m venv ~/venvs/pyscenic_clean && ~/venvs/pyscenic_clean/bin/pip install "numpy<1.24" "pandas<2" pyscenic matplotlib+scipyfor the plotting and validation scripts
Install
pip install scenic-rs # prebuilt wheels: Linux / macOS / Windows, Python >=3.9
scenic-rs depends only on (unpinned) numpy and pandas, so it drops into an
existing environment — including a scanpy env — without forcing a downgrade.
conda — a ready-made environment that includes scanpy:
conda env create -f environment.yml # then: conda activate scenic-rs
Docker / Nextflow / Singularity — a version-pinned image is published per release for reproducible pipelines:
docker pull ghcr.io/nglaszik/scenic-rs:latest # or a pinned tag, e.g. :0.1.1
// In a Nextflow process, just point at the image:
process scenic {
container 'ghcr.io/nglaszik/scenic-rs:0.1.1'
// ... your script that `import scenic_rs`
}
Usage
scenic-rs takes a cells × genes float32 matrix plus the gene names and a TF
list — load these however you like (e.g. with scanpy). Raw counts; do your own
cell/gene QC first. From Cell Ranger output:
import numpy as np, scanpy as sc
adata = sc.read_10x_mtx("sample/outs/filtered_feature_bc_matrix") # or sc.read_10x_h5(".../filtered_feature_bc_matrix.h5")
adata.var_names_make_unique()
sc.pp.filter_genes(adata, min_cells=3) # basic QC (filter cells/genes as you see fit)
X = np.asarray(adata.X.todense() if hasattr(adata.X, "todense") else adata.X, dtype="float32")
gene_names = adata.var_names.tolist()
# ...or from an existing AnnData .h5ad:
# adata = sc.read_h5ad("counts.h5ad")
# X = np.asarray(adata.layers["counts"].todense(), dtype="float32"); gene_names = adata.var_names.tolist()
# TFs = a TF list (e.g. allTFs_hg38.txt from aertslab) intersected with the genes present
tf_names = [g for g in open("allTFs_hg38.txt").read().split() if g in set(gene_names)]
Then run the pipeline:
from scenic_rs import grnboost2, genie3, aucell, RankingDb, ctx
# 1. GRN: TF -> target importances (pandas DataFrame [TF, target, importance])
adj = grnboost2(X, gene_names, tf_names) # default — fast, OOB early stopping
# adj = genie3(X, gene_names, tf_names) # alternative — random forest, slower, ~same result (use one)
# 2. ctx: prune co-expression modules to motif-supported regulons
dbs = [RankingDb("hg38_...genes_vs_motifs.rankings.feather", "hg38")]
regulons = ctx(adj, X, gene_names, dbs, "motifs-...hgnc-...tbl") # -> [Regulon(...)]
# 3. AUCell: per-cell regulon activity
auc = aucell(X, gene_names, {r.name: r.genes for r in regulons})
adj matches pySCENIC's adjacencies format and ctx matches its regulon output,
so any step can also be swapped in individually alongside pySCENIC.
Validation & benchmarks (vs real pySCENIC)
- Running each step (grnboost2/genie3/aucell/ctx) in both scenic-rs and pySCENIC 0.12.1 / ctxcore 0.2.0
- Uses the same inputs (pbmc3k 2700 cells × 758 genes, 300 TFs), (hg38 cisTarget DB 5876 motifs × 27015 genes + motif2tf annotations)
- Equal cores — rayon threads = pySCENIC's Dask-worker count
- Backend startup counted on both sides
Correctness — scenic-rs reproduces pySCENIC's numbers
| step | concordance vs pySCENIC |
|---|---|
| GRN / GRNBoost2 | Spearman 0.74, top-1000 edge Jaccard 0.56 — at the stochastic ceiling |
| GRN / GENIE3 | Spearman 0.99, per-target median 0.99 |
| ctx / cisTarget | per-(module,motif) NES Spearman 1.00 (max diff 1.4e-13) |
| AUCell | Spearman 0.98, max abs diff 0.06 |
GRNBoost2 is stochastic — running the algorithm twice (different seed) only agrees ~0.73 per target.
Memory & speed
- Peak memory (PSS) is constant in scenic-rs as cores increase, but grows ~linearly in pySCENIC (per-worker copies). Ratios = pySCENIC / scenic-rs:
| step | memory: 16c → 96c | speed (equal cores) |
|---|---|---|
| GRN / GRNBoost2 | 13× → 26× less | 2.8× faster @96c |
| GRN / GENIE3 | 30× → 123× less | equivalent |
| ctx / cisTarget | 14× → 26× less | ~10× faster |
| AUCell | 18× → 51× less | ~170× faster |
At 96 cores pySCENIC peaks at ~11.7 GB (GRNBoost2), ~20.5 GB (GENIE3) and ~17 GB (ctx); scenic-rs stays at ~0.45 GB, ~0.17 GB and ~0.66 GB respectively.
Speedup on GRNBoost2 is likely due to Dask setup, relatively negligible on larger datasets.
Reproduce
Needs a pySCENIC env, e.g.
python3.10 -m venv ~/venvs/pyscenic_clean && ~/venvs/pyscenic_clean/bin/pip install "numpy<1.24" "pandas<2" pyscenic:
# correctness + cached adjacencies (GRN + AUCell)
python bench/benchmark_pyscenic.py --workers 16 --genie3
# memory/time scaling sweep across cores (GRNBoost2, GENIE3, AUCell)
python bench/mem_benchmark.py --sweep 16,48,96 --genie3
# ctx scaling sweep (real hg38 DB)
python bench/benchmark_ctx.py --sweep 16,48,96
# ctx per-step parity checks (math, DB, modules, regulons, NES concordance)
PYTHONPATH=python ~/venvs/pyscenic_clean/bin/python bench/validate_ctx_regulons.py
# render figures
python bench/plot_benchmark.py # concordance.png, grn_per_target.png
python bench/plot_mem_benchmark.py # mem_scaling.png, time_scaling.png (all steps)
License & attribution
GPL-3.0-or-later. scenic-rs is a Rust reimplementation of, and a derivative
work of, the GPL-3.0 projects pySCENIC
and ctxcore (aertslab, VIB-KU Leuven) —
their GRN/cisTarget/AUCell workflow and the recovery/NES/module/pruning logic. It is an
independent project, not affiliated with or endorsed by aertslab. See
NOTICE for details.
If you use scenic-rs, please cite the original SCENIC work:
- Aibar et al. (2017) SCENIC: single-cell regulatory network inference and clustering. Nature Methods.
- Van de Sande et al. (2020) A scalable SCENIC workflow for single-cell gene regulatory network analysis. Nature Protocols.
- Moerman et al. (2019) GRNBoost2 and Arboreto… Bioinformatics.
Project details
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 scenic_rs-0.3.0.tar.gz.
File metadata
- Download URL: scenic_rs-0.3.0.tar.gz
- Upload date:
- Size: 3.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e7bdb95629f04cd846a6accff4bfc1d680cd23bacea1f1f884106ee5ed5b05a
|
|
| MD5 |
3997b8aff001fc6dc5db977a58e9a609
|
|
| BLAKE2b-256 |
5e6cf79ec79e1586765cd1bb9299ff870b8f93ac03098c7ac22af3c576e2b844
|
File details
Details for the file scenic_rs-0.3.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: scenic_rs-0.3.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c0657c7fdf94247222d6bc52005f96b8444b3ae1a4c95237c2a1317fb5a2b59
|
|
| MD5 |
33af0d5c165a3feeecf12557b6457aac
|
|
| BLAKE2b-256 |
be476595bf4b14c975f2fba14a71959d7d9e2afcb536800c121dad4ebab1143e
|
File details
Details for the file scenic_rs-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: scenic_rs-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94829ed9766d55f6b44debe968d6ed2ecea71c3bf67bc67172c8f25887200286
|
|
| MD5 |
46e3b3ca930b68e5f47694127a5f62f6
|
|
| BLAKE2b-256 |
0cd709e2ed1985240428e2d20b39cec566af78573c9cb23696f4fdf4f605c91c
|
File details
Details for the file scenic_rs-0.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: scenic_rs-0.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
afb103ad24be58cf2bcf13ca15bc5093dd73154a628c54d58efd22d7e7b16553
|
|
| MD5 |
b9eeec67cb13187a706f8c93f0adde39
|
|
| BLAKE2b-256 |
b90bb25e4e5c5a7152554f97d4c28787c17ae13f2ef73390e2b09d05967185ac
|
File details
Details for the file scenic_rs-0.3.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: scenic_rs-0.3.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a9f33700d69a9ab637c652baf564ccfc8a361448a41a0a91f7ad808b9185b397
|
|
| MD5 |
f2a4970f396e992f224ef01f8f462692
|
|
| BLAKE2b-256 |
eb538c22cee6031d573bfcb17f2d9f7c16c674be782149fe789288b3440f28c3
|