Truecell — Python Single-Cell Genomics Toolkit
📖 Documentation — API reference, all eighteen tutorials, and how the port is checked against R Seurat.
Truecell is a Python port of the Seurat single-cell RNA-seq analysis framework, implementing Seurat's core data structures, preprocessing pipeline, dimensionality reduction, clustering, and marker detection — entirely in Python.
The package is spiritually and algorithmically faithful to Seurat v5 while providing a pure-Python, pip-installable alternative that integrates naturally with NumPy, SciPy, and AnnData ecosystems.
Features
- Truecell object — mirrors the R
SeuratS4 class with__slots__-based Python classes - Assay5 — sparse-matrix-backed multi-layer assay (counts, data, scale.data)
- Object slimming —
diet_truecell(Seurat'sDietSeurat) strips an object to chosen assays, layers, features, reductions and graphs for saving or sharing. Returns a new object and leaves the input alone, sharing the surviving layers rather than copying them. Note thatdimreducsandgraphsare keep-lists — calling it with no arguments removes every reduction and graph, which is Seurat's behaviour too; name what you want kept - Preprocessing —
normalize_data,find_variable_features(VST),scale_data,percentage_feature_set - SCTransform —
sctransform(regularized negative-binomial Pearson residuals;vst_flavor="v2"by default, as Seurat 5, or"v1"for the 2019 model) - Multi-sample SCT —
prep_sct_find_markers(Seurat'sPrepSCTFindMarkers). SCTransform corrects each object's counts to its own median sequencing depth, so merging two SCTransformed objects leaves the halves on different scales and a fold change across the merge partly measures how deeply each batch was sequenced. Run it once after the merge, before anyfind_markerson the SCT assay; it re-corrects every cell to the minimum median UMI across the models and is a no-op on a single-model object. Verified against Seurat 5.5.1: given R's own fitted models, 0 of 13,953,800 entries differ - Signature scoring —
add_module_score,cell_cycle_scoring(S/G2M + Phase) - Dimensionality reduction —
run_pca,run_spca(supervised, off a cell graph),run_ica,run_tsne,glm_pca(Poisson or negative binomial, straight on counts) - Batch correction / integration —
run_harmony(via harmonypy), CCA/RPCA anchors (find_integration_anchors+integrate_data), and theintegrate_layersdispatcher (method="harmony"|"cca"|"rpca") - Reference mapping —
find_transfer_anchors(project a query into a reference;pcaprojectorcca) +transfer_data(annotate the query with reference labels, or impute reference expression onto it);project_umap/map_queryplace the query in the reference's own UMAP in one call - Scale (sketching) —
sketch_datadraws a leverage-weighted subset of a huge dataset (rare states kept, not lost),leverage_scorecomputes the per-cell scores via a CountSketch (no full SVD), andproject_dataextends the sketch's PCA/UMAP/labels back to every cell - Scale (lazy on-disk matrices) —
LazyMatrixkeeps a matrix out-of-core as memory-mapped compressed-sparse-column arrays (BPCells-style);write_lazy_matrix/open_lazy_matrixpersist and map it, a slice reads only the touched cells off disk,col_blocksstreams a million cells at bounded RAM, and it drops straight into anAssay5layer — no new dependency - Cell hashing (demultiplexing) —
hto_demux(Seurat'sHTODemux) demultiplexes pooled samples from hashtag counts: CLR normalize → cluster intok = n_hashtags + 1groups (kfunc="clara", Seurat's k-medoids, or"kmeans") → per-hashtag negative-binomial background threshold → singlet / doublet / negative calls, written tometa_data(HTO_maxID,HTO_classification, …) plus ahash.IDidentity.multiseq_demux(Seurat'sMULTIseqDemux) is the MULTI-seq alternative — a Gaussian-KDE quantile threshold per barcode, with anautothreshsweep — writingMULTI_ID/MULTI_classification - Pooled CRISPR screens (Mixscape) —
calc_perturb_sig(Seurat'sCalcPerturbSig) subtracts each cell's nearest non-targeting controls to isolate its perturbation signature, thenrun_mixscape(Seurat'sRunMixscape) separates true knockouts from non-perturbed escapers per guide — gene-vs-NT DE, then an iterative 2-component Gaussian mixture over the perturbation score — writingmixscape_class("<gene> KO"/NP/NT, also the identity),mixscape_class.global, andmixscape_class_p_ko.mixscape_lda(Seurat'sMixscapeLDA) adds the supervised map on which each guide population forms its own cloud — per-guide DE-gene PCA subspaces, every cell projected onto each, then one linear discriminant analysis over the concatenation → anldareduction pluslda_assignments/LDAP_<class>. Two diagnostics complete the workflow:plot_perturb_score(Seurat'sPlotPerturbScore) overlays the NT control density against one guide's own along the perturbation score — the axis mixscape actually splits on, bimodal when the guide has a real effect — andmixscape_heatmap(Seurat'sMixscapeHeatmap) shows the DE genes underneath it with every cell ordered by its knockout probability - Nearest-neighbour graph —
find_neighbors(KNN + SNN).return_neighbor=True(Seurat'sreturn.neighbor) stores the raw KNN — indices and distances — as aNeighborunder<assay>.nninstead of building graphs, andcompute_snncontrols the SNN independently. Verified against Seurat 5.5.1 on pbmc3k: all 54,000 neighbour indices match, distances to 1.1e-13 - Multimodal WNN —
find_multi_modal_neighbors(full two-stage port: per-cell RNA/protein weights via exponential kernel + softmax, then a joint neighbour search building thewknn/wsnngraphs) - Clustering —
find_clustersruns Seurat's own modularity optimiser (Louvain, Louvain with multilevel refinement, smart local moving), translated from its C++ with the same restarts and random stream, so the same graph gives Seurat's partition label for label; Leiden via leidenalg - UMAP —
run_umap(via umap-learn; embeds a reduction or a precomputed graph) - PC significance —
jack_straw,score_jackstraw(JackStraw permutation test) - Differential expression —
find_markers,find_all_markersandfind_conserved_markers(cross-condition, Fisher-combined), with all nine of Seurat's tests:wilcox(tie-corrected, the default),t,bimod,LR,negbinom,poisson,masthurdle,deseq2, androc. Eight of them — every p-value test — reproduce Seurat's top 50 genes exactly on PBMC 3k, androcagrees within Seurat's own 3-dp AUC rounding.deseq2is Seurat'sDESeq2DETest, every cell a replicate, andsample_colmakes it a pseudobulk test.poissonandnegbinomare Seurat's twoGLMDETestfamilies and both run on the counts layer — prefernegbinom, since fixing the dispersion at 1 makespoissonanti-conservative on overdispersed UMI counts - Pseudobulk —
aggregate_expression(sum counts per group → matrix or one-cell-per-group object), pseudobulk DESeq2 viafind_markers(test_use="deseq2", sample_col=...) - Plotting —
dim_plot,feature_plot,vln_plot,dot_plot,elbow_plot,do_heatmap,dim_heatmap,feature_scatter,variable_feature_plot,ridge_plot,plot_perturb_score,mixscape_heatmap(matplotlib/seaborn) - AnnData interoperability —
truecell.compat.anndata.as_anndataandfrom_anndata, with spatial coordinates, FOVs and Visium images in the layout Scanpy and Squidpy read, plus recipes for SpatialData (AnnData, Scanpy and SpatialData) - Spatial (Xenium / Visium / CosMx / MERSCOPE) —
load_xenium/load_visium/load_cosmx/load_merscope,get_tissue_coordinates,nearest_neighbor_distance,local_neighborhood,build_niche_assay,find_spatially_variable_features(Moran's I + mark variogram),composition_test,image_dim_plot,image_feature_plot - Visium tissue images —
load_visiumreads the H&E PNG +scalefactors_json.jsoninto aVisiumV2image (Seurat v5's class):get_image(),scale_factors,radius(),scale_coordinates();spatial_dim_plot/spatial_feature_plotdraw spots over that image at their true diameter - PBMC 3k tutorial — end-to-end validated against the official Seurat tutorial
- PBMC 8k advanced tutorial — larger dataset + T/NK subclustering workflow
- CITE-seq multimodal tutorial — RNA + surface protein (ADT) with CLR normalization and WNN joint clustering
- Cell-hashing tutorial —
hto_demux+multiseq_demuxdemultiplexing, 99.81% call-concordant with R Seurat'sHTODemux - Mixscape tutorial — pooled-CRISPR
calc_perturb_sig+run_mixscape+mixscape_lda, 97.68% per-cell call-concordant with R Seurat on the THP-1 ECCITE-seq screen - Integration tutorial —
run_harmony/integrate_layerson the ifnb IFN-β benchmark; batch mixing lands within 0.001 of Seurat's for all three methods (Harmony 0.991, CCA 0.992, RPCA 0.917). The first tutorial to catch real defects: four RPCA-path bugs, all fixed — a crash on unequal batch sizes, a 4× under-integration,integrate_layerssilently running v4'sIntegrateDataalgorithm behind the v5IntegrateEmbeddingsAPI, and sklearn's randomized SVD driftingrun_pca's trailing components (RPCA's batch mixing rose from 0.222 to 0.867 as the first two were fixed) - Reference mapping tutorial —
find_transfer_anchors/transfer_data/map_queryon the panc8 cross-technology benchmark; label transfer is 98.87% per-cell concordant with R Seurat, both ~98.7% accurate against the held-out cell types - Cell-cycle & module-score tutorial —
cell_cycle_scoring/add_module_scoreon the proliferating THP-1 line; per-cell phase is 95.9% concordant with R Seurat, as often as two NumPy seeds agree with each other, and the S/G2M/module scores correlate at Pearson ≥ 0.997 (residual is the control-gene RNG) - Xenium spatial tutorial — spatial neighbourhood/niche analysis, verified to 8 s.f. against R Seurat
Installation
Truecell is published on PyPI — pip install truecell just works.
Requires Python 3.12 or newer, and CI tests 3.12 and 3.13. The floor follows
SPEC 0, the support window
numpy, scipy, pandas and scikit-learn themselves keep — three years past each
Python release — rather than CPython's longer EOL calendar. On 3.10 or 3.11,
pip resolves to 0.2.0, the last release that declared >=3.10.
Python 3.14 is not yet tested: harmonypy
ships manylinux wheels only through cp313, and the alternatives are a source
build needing BLAS or a resolver backtrack that pulls in torch. Everything else
in the dependency set already has 3.14 wheels, so this is one package away.
If truecell crashes (a segmentation fault, or a Jupyter kernel that dies), the
Troubleshooting page covers
the known causes, and truecell.show_versions() prints what a bug report needs.
Releases and
main. PyPI has the latest release, and this README followsmain.CHANGELOG.mdsays what shipped in each release, and lists what is onmainonly under Unreleased.
From PyPI — the released core
pip install truecell # core: object model, preprocessing, PCA, markers
pip install "truecell[analysis]" # + clustering, UMAP, plotting (matplotlib/seaborn)
pip install "truecell[anndata]" # + AnnData interoperability
pip install "truecell[integration]" # + Harmony batch correction (harmonypy)
pip install "truecell[deseq2]" # + find_markers(test_use="deseq2") (pydeseq2)
pip install "truecell[all]" # everything (all of the above + dev/test and docs tooling)
Or with uv:
uv pip install "truecell[analysis]"
From source — everything above
git clone https://github.com/GenomicAI/truecell.git
cd truecell
uv sync --all-extras --locked # editable install + tests/linting, at uv.lock's versions
source .venv/bin/activate # Windows: .venv\Scripts\activate
--locked installs the versions CI tests and the tutorial figures were drawn
with; resolving fresh can give a different scientific stack.
With pip instead of uv:
git clone https://github.com/GenomicAI/truecell.git
cd truecell
pip install -e ".[analysis]"
Quick Start
import scipy.sparse as sp
import numpy as np
from truecell import create_truecell_object
# Create a Truecell object from a counts matrix
counts = sp.random(2000, 500, density=0.2, format="csc")
sobj = create_truecell_object(counts, project="my_project", min_cells=3, min_features=200)
print(sobj)
# Truecell object — my_project
# 500 cells × 2000 features
# Active assay: 'RNA'
# Reductions: []
# Version: 5.4.0
# Access metadata
print(sobj.meta_data.head())
Tutorials
Eighteen end-to-end tutorials — from basic guided clustering through multimodal
CITE-seq, cell-hashing demultiplexing, pooled-CRISPR Mixscape, batch integration,
reference mapping, cell-cycle scoring, PC-significance testing, leverage-score
sketching and the object model itself to Xenium spatial — each pairing R Seurat
code side-by-side with the Python Truecell equivalent.
See tutorials/README.md for the full index.
| # | Tutorial | Dataset | Complexity |
|---|---|---|---|
| 1 | PBMC 3k — Guided Clustering | 3k PBMCs · 10x Genomics | Beginner |
| 2 | PBMC 8k — Advanced Subclustering | 8k PBMCs · GRCh38 | Intermediate |
| 3 | CBMC CITE-seq — Multimodal | 8,600 CBMCs · RNA + 13 proteins | Advanced |
| 4 | PBMC 3k — SCTransform | 3k PBMCs · 10x Genomics | Advanced |
| 5 | Xenium — Spatial (R vs Python) | 36k cells · 10x Xenium mouse brain | Spatial |
| 6 | Cell Hashing — Demultiplexing | 39,842 cells · 8 HTOs · GSE108313 | Advanced |
| 7 | Mixscape — Pooled CRISPR Screen | 20,729 cells · 25 guides · GSE153056 | Advanced |
| 8 | Batch Integration — Harmony/CCA/RPCA | 13,999 cells · CTRL/STIM · ifnb | Advanced |
| 9 | Reference Mapping — Label Transfer | 4,679 cells · celseq2→smartseq2 · panc8 | Advanced |
| 10 | Cell-cycle & Module Scoring | 20,729 cells · THP-1 · GSE153056 | Advanced |
| 11 | Dimensional-Reduction Extras | 2,700 PBMCs · 10x Genomics | Advanced |
| 12 | Leverage-Score Sketching | 13,999 cells · CTRL/STIM · ifnb | Advanced |
| 13 | The Object Model Itself | 2,700 PBMCs · 10x Genomics | Advanced |
| 14 | Spatial Statistics & the Spatial Container | 36,602 cells · 10x Xenium mouse brain | Advanced |
| 15 | The Differential-Expression Test Suite | 2,700 PBMCs · 10x Genomics | Advanced |
| 16 | Out of Core — LazyMatrix vs BPCells |
2,700 PBMCs · 10x Genomics | Advanced |
| 17 | Visium — the Spatial Container | 2,695 spots · 10x mouse brain | Spatial |
| 18 | Anchor Internals — CCA & RPCA | 2,400 cells · ifnb | Advanced |
# Tutorial 1 — PBMC 3k
python tutorials/pbmc3k_tutorial.py && python tutorials/generate_plots.py
# Tutorial 2 — PBMC 8k subclustering
python tutorials/pbmc8k_subclustering_tutorial.py && python tutorials/generate_advanced_plots.py
# Tutorial 3 — CITE-seq multimodal
python tutorials/cbmc_citeseq_tutorial.py && python tutorials/generate_multimodal_plots.py
# Tutorial 4 — SCTransform
python tutorials/pbmc3k_sctransform_tutorial.py && python tutorials/generate_sctransform_plots.py
# Tutorial 5 — Xenium spatial (auto-downloads ~20 MB)
python tutorials/generate_spatial_plots.py
# Tutorial 6 — Cell hashing demultiplexing (auto-downloads ~34 MB)
python tutorials/pbmc_hashing_tutorial.py && python tutorials/generate_hashing_plots.py
# Tutorial 7 — Mixscape pooled-CRISPR screen (auto-downloads ~66 MB)
python tutorials/thp1_mixscape_tutorial.py && python tutorials/generate_mixscape_plots.py
# Tutorial 8 — Batch integration (needs a one-time `Rscript tutorials/export_seuratdata.R ifnb`)
python tutorials/ifnb_integration_tutorial.py && python tutorials/generate_integration_plots.py
# Tutorial 9 — Reference mapping (needs a one-time `Rscript tutorials/export_seuratdata.R panc8`)
python tutorials/panc8_reference_mapping_tutorial.py && python tutorials/generate_refmap_plots.py
# Tutorial 10 — Cell-cycle & module scoring (downloads ~66 MB, shared with Mixscape)
python tutorials/thp1_cellcycle_tutorial.py && python tutorials/generate_cellcycle_plots.py
# Tutorial 13 — The object model (downloads ~24 MB, shared with Tutorial 1)
python tutorials/pbmc3k_objects_tutorial.py && python tutorials/generate_objects_plots.py
# Tutorial 14 — Spatial statistics & the container (downloads ~14 MB, shared with Tutorial 5)
python tutorials/xenium_svf_tutorial.py && python tutorials/generate_svf_plots.py
# Tutorial 15 — The DE test suite (downloads ~24 MB, shared with Tutorial 1)
python tutorials/pbmc3k_de_tutorial.py && python tutorials/generate_de_plots.py
API Reference
Object creation
from truecell import create_truecell_object
pbmc = create_truecell_object(
counts, # scipy.sparse CSC/CSR or numpy ndarray (genes × cells)
project="pbmc3k",
min_cells=3, # filter genes present in fewer than N cells
min_features=200, # filter cells with fewer than N detected genes
)
Preprocessing
from truecell.preprocessing import (
normalize_data,
find_variable_features,
scale_data,
percentage_feature_set,
)
percentage_feature_set(pbmc, pattern=r"^MT-", col_name="percent.mt")
normalize_data(pbmc, normalization_method="LogNormalize", scale_factor=10000)
find_variable_features(pbmc, selection_method="vst", nfeatures=2000)
scale_data(pbmc)
Dimensionality reduction & clustering
from truecell.reduction import run_pca
from truecell.neighbors import find_neighbors
from truecell.clustering import find_clusters
from truecell.umap import run_umap
run_pca(pbmc, n_pcs=50)
find_neighbors(pbmc, dims=range(10), k_param=20)
find_clusters(pbmc, resolution=0.5)
run_umap(pbmc, dims=range(10))
# Seurat's `return.neighbor`: keep the raw KNN — indices and distances — instead
# of building graphs. Stored as a `Neighbor` under "RNA.nn" (a dot; the graphs
# use an underscore). Indices are 0-based, where R's `Indices()` are 1-based.
find_neighbors(pbmc, dims=range(10), return_neighbor=True)
nn = pbmc.neighbors["RNA.nn"]
nn.indices() # (cells × k), the cell itself first
nn.distances() # (cells × k), 0.0 in column 0
Differential expression
from truecell import (
find_markers, find_all_markers, find_conserved_markers, aggregate_expression,
)
markers = find_markers(pbmc, ident_1=1)
all_markers = find_all_markers(pbmc, only_pos=True, logfc_threshold=0.25)
# Any of Seurat's nine tests. `negbinom` and `poisson` are its two GLM families
# and read the counts layer; prefer `negbinom` — holding the dispersion at 1
# makes `poisson` anti-conservative on overdispersed UMI counts.
markers = find_markers(pbmc, ident_1=1, test_use="poisson")
markers = find_markers(pbmc, ident_1=1, test_use="LR", latent_vars=["percent.mt"])
# Markers up in cluster 1 across every condition (Fisher-combined p per gene).
conserved = find_conserved_markers(pbmc, ident_1=1, grouping_var="condition")
# Pseudobulk counts summed per (cell type × donor) — input for sample-level DE.
pseudobulk = aggregate_expression(pbmc, group_by=["cell_type", "donor"])
# Pseudobulk DESeq2 between two conditions, one summed profile per donor (needs
# `pip install truecell[deseq2]`). pbmc.idents must hold the two conditions.
# Without sample_col every cell is a replicate, as in Seurat's FindMarkers.
de = find_markers(pbmc, ident_1="stim", ident_2="ctrl",
test_use="deseq2", sample_col="donor")
Multi-sample SCT, and slimming an object
import truecell
# Two samples SCTransformed separately, then merged. Each was corrected to its
# OWN median sequencing depth, so the two halves of the SCT counts layer are on
# different scales — a fold change across the merge would partly measure how
# deeply each batch was sequenced.
merged = ctrl.merge(stim, add_cell_ids=["ctrl", "stim"])
truecell.prep_sct_find_markers(merged) # once, before any find_markers
de = truecell.find_markers(merged, "0", "1", assay="SCT")
# Slim an object before saving or sharing it. `pbmc` here is the object from the
# blocks above, which already has a `pca` and its two graphs.
#
# NOTE: `dimreducs` and `graphs` are keep-LISTS — with neither named, every
# reduction and graph is dropped (this is Seurat's behaviour too). Name what you
# want to keep, or you will lose your embedding.
slim = truecell.diet_truecell(pbmc, layers="counts", dimreducs="pca")
# -> keeps the counts layer and `pca`; drops data, scale.data and both graphs
Plotting
All plotting functions return a matplotlib.figure.Figure — save or display as needed.
from truecell.plotting import (
dim_plot, # DimPlot — cells on UMAP/PCA coloured by ident
feature_plot, # FeaturePlot — gene expression on embedding
vln_plot, # VlnPlot — violin plots per cluster
elbow_plot, # ElbowPlot — stdev per PC
feature_scatter, # FeatureScatter — two features vs each other
variable_feature_plot, # VariableFeaturePlot — mean-variance HVG plot
dim_heatmap, # DimHeatmap — top loading genes per PC
do_heatmap, # DoHeatmap — expression heatmap sorted by cluster
ridge_plot, # RidgePlot — ridgeline plots per cluster
)
# Quick examples
fig = dim_plot(pbmc, reduction="umap", label=True)
fig = feature_plot(pbmc, ["LYZ", "MS4A1", "NKG7"], reduction="umap", ncol=3)
fig = vln_plot(pbmc, ["LYZ", "CD3D", "PPBP"], group_by=None)
fig = elbow_plot(pbmc, ndims=20)
fig = do_heatmap(pbmc, top_marker_genes)
fig.savefig("output.png", dpi=150, bbox_inches="tight")
| Truecell function | R Seurat equivalent |
|---|---|
dim_plot |
DimPlot |
feature_plot |
FeaturePlot |
vln_plot |
VlnPlot |
dot_plot |
DotPlot |
elbow_plot |
ElbowPlot |
feature_scatter |
FeatureScatter |
variable_feature_plot |
VariableFeaturePlot |
dim_heatmap |
DimHeatmap |
do_heatmap |
DoHeatmap |
ridge_plot |
RidgePlot |
Data Structures
Truecell
├── assays: dict[str, Assay5]
│ └── "RNA"
│ ├── layers["counts"] # raw integer counts (genes × cells)
│ ├── layers["data"] # log-normalized (genes × cells)
│ └── layers["scale.data"] # z-scored (genes × cells)
├── meta_data: pd.DataFrame # per-cell metadata
├── reductions: dict
│ ├── "pca": DimReduc # PCA embeddings + loadings
│ └── "umap": DimReduc # UMAP embeddings
├── graphs: dict
│ ├── "RNA_nn": Graph # KNN graph
│ └── "RNA_snn": Graph # SNN graph
└── commands: list[TruecellCommand] # audit log
Roadmap
See ROADMAP.md for the full
development plan, and CHANGELOG.md
for what has actually shipped. The two are not the same thing — these milestones are planning
labels rather than release versions — but as of 0.9.0 every row below through v0.9.0 is
released, not just landed on main. Milestones:
| Milestone | Focus |
|---|---|
| v0.2.0 | Batch correction — Harmony, CCA/RPCA anchors, IntegrateLayers dispatcher ✅ (released in 0.2.0) |
| v0.3.0 | Reference mapping — FindTransferAnchors, TransferData, MapQuery/ProjectUMAP ✅ (released in 0.9.0) |
| v0.4.0 | Multimodal WNN — FindMultiModalNeighbors, joint UMAP/clustering ✅ (released in 0.9.0 — see Tutorial 3) |
| v0.5.0 | Additional reductions — t-SNE, ICA, run_spca, glm_pca (Poisson + negative binomial) ✅ (released in 0.9.0) |
| v0.6.0 | Pseudobulk & advanced DE — AggregateExpression, FindConservedMarkers, DESeq2 (test_use="deseq2"), MAST (test_use="mast"), bimod (test_use="bimod") ✅ (released in 0.9.0) |
| v0.7.0 | Spatial — Xenium/Visium/CosMx/MERSCOPE loaders, niche/neighbourhood analysis, find_spatially_variable_features (Moran's I + markvariogram), image_* plots, VisiumV2 tissue images, spatial_* H&E plots ✅ (released in 0.9.0 — see Tutorial 5) |
| v0.8.0 | Scale — SketchData/ProjectData (leverage-score sketching) ✅; BPCells-style lazy on-disk matrices (LazyMatrix) ✅ (released in 0.9.0) |
| v0.9.0 | Specialized — HTODemux ✅ + MULTIseqDemux ✅ (cell hashing); Mixscape ✅ (CalcPerturbSig + RunMixscape + MixscapeLDA + PlotPerturbScore + MixscapeHeatmap, CRISPR screens) — released in 0.9.0 |
| v0.10.0 | Infrastructure — PyPI ✅, GitHub Actions CI ✅ (3.12–3.13 matrix, wheel build + clean-install verification, coverage), CHANGELOG.md ✅, mypy in CI ✅, the documentation site ✅ |
Running Tests
uv sync --all-extras --locked
uv run pytest tests/ -q
About 1,700 tests; CI runs them on Python 3.12 and 3.13.
A further smoke suite runs the tutorials end to end against real data. It is opt-in: it needs the cached datasets and takes minutes. CI runs the part that needs only PBMC 3k; the rest runs on a developer's machine before each release:
TRUECELL_TUTORIAL_SMOKE=1 pytest tests/test_tutorial_smoke.py -v
A green unit suite says nothing about the tutorials on its own.
Dependencies
| Package | Purpose |
|---|---|
| numpy, scipy, pandas | Core numerics and data frames |
| statsmodels | The LR, poisson and mast DE tests |
| scikit-learn | PCA |
| umap-learn | UMAP embedding |
| numba | Seurat's modularity optimiser (find_clusters) |
| python-igraph | Leiden clustering; find_clusters(optimizer="igraph") |
| leidenalg | Leiden clustering |
| packaging | Version handling |
Credits
Development assistance: This package was developed with the help of
Claude (Anthropic's AI assistant) — initially
claude-sonnet-4-6, and subsequently claude-opus-4-8 — which assisted in
porting the R Seurat codebase to Python, implementing the VST algorithm,
degree-2 LOESS, Louvain clustering, the anchor-based integration and transfer
machinery, and validating results against real R Seurat runs.
Human in the loop. All development was carried out under strong human-in-the-loop (HITL) supervision. Every change was directed, reviewed and accepted by the maintainer; nothing was merged unattended. That review is the reason the fidelity claims in this repository are worth reading — each one is pinned to a side-by-side run against R Seurat with the numbers recorded, and several were sent back and re-derived when the first answer did not hold up. Where a difference from Seurat remains, it was examined and is documented as either a deliberate choice or an open question, rather than quietly absorbed.
Original R Seurat package:
The algorithms and data structures in Truecell are direct Python translations of the
R Seurat package by the Satija Lab.
Please cite the original Seurat papers if you use Truecell in published work:
Hao Y, Stuart T, Kowalski MH, et al. (2024). Dictionary learning for integrative, multimodal and scalable single-cell analysis. Nature Biotechnology, 42, 293–304. https://doi.org/10.1038/s41587-023-01767-y
Hao Y, Hao S, Andersen-Nissen E, et al. (2021). Integrated analysis of multimodal single-cell data. Cell, 184(13), 3573–3587. https://doi.org/10.1016/j.cell.2021.04.048
Stuart T, Butler A, Hoffman P, et al. (2019). Comprehensive Integration of Single-Cell Data. Cell, 177(7), 1888–1902. https://doi.org/10.1016/j.cell.2019.05.031
Butler A, Hoffman P, Smibert P, Papalexi E, Satija R. (2018). Integrating single-cell transcriptomic data across different conditions, technologies, and species. Nature Biotechnology, 36, 411–420. https://doi.org/10.1038/nbt.4096
PBMC 3k dataset:
10x Genomics. (2016). 3k PBMCs from a Healthy Donor.
https://www.10xgenomics.com/resources/datasets/3-k-pb-mcs-from-a-healthy-donor-1-standard-1-1-0
License
MIT License — see LICENSE for details.
This software is an independent reimplementation for educational and research purposes. It is not affiliated with, endorsed by, or maintained by the Satija Lab or 10x Genomics.
Metadata
Release files for truecell 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| truecell-2.0.0.tar.gz | 1.0 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| truecell-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.3 MB
Release files / truecell-2.0.0.tar.gz
| Download URL | truecell-2.0.0.tar.gz |
|---|---|
| Size | 1.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
588316d3258854a726878ce8fc82078aa941c3db7d72e5eed93863ae6274f9b4
|
|
BLAKE2b-256 checksum How to use checksums |
52eee949ddcb536f3c5421763d563b61958213a062bb7ac487311b5ed44f299d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|
Release files / truecell-2.0.0-py3-none-any.whl
| Download URL | truecell-2.0.0-py3-none-any.whl |
|---|---|
| Size | 317.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
35a8e5ef0ca362886c896cca14e832d26a27f6c326b1c21179b881959e2e0870
|
|
BLAKE2b-256 checksum How to use checksums |
49d903c4c907b68ff117bcf6315e53fef872628a4cd08a1f29d8e133485c47b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|