Releases: GenomicAI/truecell
Release list
truecell 1.1.0
Fourteen pull requests since 1.0.0. Backwards compatible — nothing removed or
renamed — so the additions are safe, and the reasons to upgrade are the
corrections.
Fixed — these are live in 1.0.0 today
| The categorical palette repeated colours, so two clusters could render identically | #86 |
vln_plot drew the wrong violin three ways — bandwidth, trim, and points |
#89 |
aggregate_expression(return_object=True) left raw sums in data where Seurat log-normalizes (14 against 6.98) |
#93 |
_get_expression_matrix returned the wrong layer when asked for scale.data, and labelled the right one with the wrong features |
#93 |
| The pbmc3k annotated UMAP captioned the platelet cluster "DC" | #98 |
feature_plot alone rasterised its points, and did so unconditionally |
#86 |
If you run pseudobulk, read a violin, or trust a cluster colour, 1.0.0 is giving
you something wrong.
Added
average_expression, mirroring Seurat'sAverageExpression— the
back-transformed per-group mean, distinct fromaggregate_expression's sums.find_clustersaccepts several resolutions and writes a
{graph}_res.{r}column per resolution, asFindClustersdoes. Choosing a
resolution means comparing a few.split_byondim_plot,feature_plotandvln_plot.- A theme layer —
set_theme,theme_context,get_theme,reset_theme. ridge_plotwarns when an explicitfigsizecannot fit the groups.
Performance
find_markers computes its min_pct and logfc_threshold masks on the sparse
matrix and densifies only the survivors, instead of building a dense
genes × cells array per group first. Marker tables are byte-identical:
| dataset (clusters) | time | peak memory |
|---|---|---|
| ifnb (15) | 25.37s → 8.03s | 9420 MB → 3580 MB |
| pbmc8k (9) | 12.71s → 6.32s | 9253 MB → 2406 MB |
| thp1 (7) | 45.52s → 23.87s | 10620 MB → 9428 MB |
A cross-language benchmark suite against R Seurat landed alongside it —
tutorials/benchmark/PERFORMANCE.md.
Verification
add_module_scoreis now verified against Seurat as an equality, not a
correlation. Atnbin=1withctrl= pool size,sample(n, n)is a
permutation, so the control set is forced and the two tools agree to
6.66e-15 across 20,729 cells — against 1.8e-01 between two R seeds.- The guided tutorial scans four resolutions, each scored against Seurat.
Cluster counts match exactly at 0.4, 0.8 and 1.2; the 8-vs-9 split is specific
to 0.5. - CI now runs the PBMC 3k tutorials against real data, with a skip counted
as a failure. The1.0.0mislabelling above shipped under a guard that was
correct and had never executed. - Float64 round-trips fixed across every tutorial's R↔Python handoff.
Install
pip install --upgrade truecell
Full detail in CHANGELOG.md.
truecell 1.0.0 — the rename release
shanuz is now truecell. Same codebase, renamed and re-verified — the API is the one 0.9.0 shipped. The version moves to 1.0.0 rather than continuing the 0.x line because neither neighbouring number was free on PyPI: shanuz 0.9.0 is the last release under the old name, and truecell 0.9.0 was published from the same code before the rename settled. It is not a maturity claim.
pip install truecell⚠️ Breaking: there is no compatibility shim
import shanuz will not work, and the top-level class is Truecell, not Shanuz. Every import, skill directory, documentation page and logo asset moved with the name.
shanuz stays on PyPI at 0.9.0 and is not being withdrawn, but it will receive no further releases.
The GitHub repository was renamed in place rather than forked, so stars, forks, issues and pull requests carried over and the old URL redirects — including for git clone and pip install git+…. Existing clones keep working through that redirect, though git remote set-url is worth running.
Fixed
The sdist shipped the tutorial data — and a different amount of it every time. docs/tutorials is a symlink to tutorials/, hatchling follows it, and the tutorials write their intermediates into the directory they live in: BPCells stores, .lazy matrices, R handoff CSVs. .gitignore covers all of those, but an sdist is not built from git, so they were packaged anyway.
The published shanuz 0.9.0 sdist is 23.5 MB against a 0.24 MB wheel for that reason, and a build on a machine that had just run the tutorials produced 63 MB — same version number, different tarball, depending on the disk it was built from. That non-reproducibility was the actual defect; the size was the symptom.
[tool.hatch.build.targets.sdist] now lists its contents explicitly. The sdist is 532 KB. The wheel is unaffected — it was always scoped by packages = ["truecell"]. tests/test_packaging.py builds an sdist and looks inside it, rather than asserting on configuration that would pass just as happily against a broken artifact.
Most figures on the docs site 404'd. MkDocs re-anchors relative paths written in Markdown onto the built page, which under use_directory_urls sits a directory deeper than its source — but it passes raw HTML through untouched, and the vignettes write most figures as <img> inside HTML tables so the R and Python plots sit side by side. 110 of the site's 133 figures were broken, and the ten vignettes built entirely from those tables showed no images at all. A build hook now applies the same rewrite to raw <img src>. The existing figure-existence test only understood Markdown image syntax, so it was blind to 126 of the 149 references it was meant to guard; it now reads both.
The API reference claimed the whole API is exported from the top level. True for eleven of thirteen pages, false for two: 66 of the 73 public generics live only on truecell.generics, so truecell.features(obj) — the call that sentence invites — raises AttributeError.
tutorials/README.md documented only 10 of the 18 tutorials. The eight added in Waves 2 and 3 had no written section. All eight added.
Added
A logo, generated by tools/make_logo.py rather than drawn. The mark is a point cloud whose density traces a lowercase c, for cell — building a picture out of dots is the nod to Georges Seurat, the pointillist the R package is named for. The c is two arcs meeting at the waist in two colours: the two implementations, one shape. It is also the letter the wordmark's own c draws, so the mark is a letter of the name enlarged rather than an ornament beside it.
Ships as a mark, horizontal lockup, wordmark, hex sticker, a simplified single-stroke glyph for sizes below ~48px where the dots silt up, and favicons — each in a light-ground and dark-ground variant.
Agent skills for LLM-assisted work (skills/). Ten skills in the Claude Agent Skills format — plain Markdown with YAML frontmatter, so they work as context for any model. Aimed at the mistakes a model actually makes against this API rather than re-describing the docs: that analysis functions mutate in place and return None (so obj = normalize_data(obj) leaves you holding None), that dims is 0-based, that matrices are features × cells, that the generics are not top-level, and which differences from Seurat are deliberate and must not be "fixed".
Verifying these artifacts
The attached wheel and sdist were rebuilt from the v1.0.0 tag and are byte-identical to the files on PyPI:
| Artifact | SHA-256 |
|---|---|
truecell-1.0.0-py3-none-any.whl |
58c56e96b09651785a9228295fdd2ba7214bed12d7365fde7622cebd2288a652 |
truecell-1.0.0.tar.gz |
867490a00fdc80eeabf49170cc718f01e5827942ae47a90d900e21c181f14d35 |
📦 PyPI · 📖 Documentation · 📓 Tutorials · 📝 Full changelog
shanuz v0.9.0 — reference mapping, spatial, scale, and five more milestones
Six milestones' worth of work that had been sitting on main since 0.2.0, released in one jump: reference mapping, extra reductions, pseudobulk DE, spatial, scale, and the specialized assays — plus a breaking anchor/integration fix and the tutorial fidelity infrastructure (measured bands, staleness guards) that followed it. All of it was on main; as of this release, all of it is on PyPI.
Version jumps 0.2.0 → 0.9.0 to match the ROADMAP milestone number this release closes — a one-time coincidence, not a new versioning policy. See CHANGELOG.md for the complete, itemized list.
Highlights
Reference mapping, integration, anchors
find_transfer_anchors/map_query/transfer_data— label transfer via anchor projection.- Anchor scoring and filtering brought in line with Seurat's
FindWeightsC/FindIntegrationAnchors: four-neighbour-table scoring,TopDimFeaturesfiltering, constant-feature dropping, exact-SVD PCA loadings. - Breaking:
integrate_layers(method="cca"|"rpca")was running the wrong algorithm; RPCA now corrects onto the larger batch and closes most of its anchor-recall gap vs Seurat.
Extra reductions
run_ica,run_tsne,run_spca,glm_pca.run_pcamoved off sklearn's randomized SVD to an exact SVD, fixing drift in downstream reductions.
Pseudobulk DE
- DESeq2-backed pseudobulk differential expression (
find_markers(test_use="deseq2", ...)). negbinomno longer runs a likelihood-ratio test against a moment-estimated dispersion.
Spatial
- Visium loading defaults fixed: in-tissue filtering, lowres image,
"slice1"image key regardless of which optional imaging package is installed. Centroidsnow carries a radius;Segmentationpolygons are closed; Moran's I uses Seurat's actual weight scheme.
Scale / out-of-core
LazyMatrix, a BPCells-comparable on-disk backend — five functions that used to densify an entire on-disk layer on read now stream it; object construction no longer forces materialization before analysis runs.
Specialized assays, cell hashing, Mixscape
- Layered v5
Assaysplit/JoinLayersround-trips correctly;fetch_dataaddresses embedding columns and reads the right layer; the command log andorig.identare populated. - Cell hashing (
hto_demux,multiseq_demux) and Mixscape, verified against cross-species ground truth (99.81% call-concordant).
Also in this release
- A documentation site: MkDocs + Material + mkdocstrings, published to genomicai.github.io/shanuz, generated from the same docstrings that carry the fidelity notes.
find_neighbors/find_clusters/run_umapgraph fixes (directed KNN kept, SNN diagonal preserved,group_singletons) that closed a clustering divergence on integrated data.leverage_scoreandsketch_datafixed to match Seurat's sketching path.jack_strawnull distribution rebuilt against a refit-per-replicate basis, matchingScoreJackStraw.
Install
pip install shanuz # core
pip install "shanuz[analysis]" # + clustering, UMAP/t-SNE, plotting, more DE tests
pip install "shanuz[all]" # everything, incl. dev toolingNotes
- Python 3.12–3.13 (SPEC 0); 3.14 is blocked only by
harmonypy's missing cp314 wheel. - 970 tests passing, 18 tutorials each checked side-by-side against real Seurat 5.5.1.
Tutorial R Seurat ↔ Shanuz side-by-side comparisons
Documentation-only release. No library code changed — the installable shanuz package remains 0.2.0 on PyPI and is byte-identical to the 0.2.0 wheel. This tags a batch of tutorial improvements only.
What changed
Every tutorial now presents a genuine left-R (Seurat) / right-Python (Shanuz) side-by-side comparison. Two tutorials were previously pure ports whose "R (Seurat)" column held only code (no R figures), which read as an "R-only" page; others had one-sided or orphaned figures.
New R reproduction scripts
Each mirrors its Python tutorial's exact pipeline and writes r_* figures titled "R Seurat – …":
| Script | Tutorial |
|---|---|
tutorials/pbmc8k_subclustering_verify.R |
Advanced PBMC 8k clustering + subclustering |
tutorials/cbmc_citeseq_verify.R |
Multimodal CITE-seq (RNA + ADT) |
tutorials/pbmc3k_verify.R |
PBMC 3k (the RidgePlot the vignette omits) |
tutorials/pbmc3k_sctransform_verify.R |
SCTransform (cell-type UMAP + SCT-vs-standard) |
Balance & cleanup
- 23 new R Seurat figures across the advanced, multimodal, sctransform, and pbmc3k tutorials.
- All 6 tutorials verified two-sided — R-side figure count equals Shanuz count everywhere.
- Surfaced two orphaned xenium figures (QC violin, clusters-in-space) and removed redundant duplicate QC-scatter panels. Zero orphaned figures repo-wide.
Notable finding
Seurat's CLR normalization (margin=2) has a different absolute scale than Shanuz's, so the CITE-seq annotation thresholds are re-calibrated to Seurat's per-cluster CLR values (documented in cbmc_citeseq_verify.R); both resolve the same 9 lineages.
Full changelog: v0.2.0...tutorials-2026.07.06
v0.2.0 — Harmony batch integration + WNN multimodal analysis
First feature release since 0.1.x. Adds batch-effect correction, weighted multimodal integration, and two more dimensionality reductions — all validated against the published wheel (156 tests + all 9 tutorial scripts).
Highlights
Batch correction / integration (v0.2.0)
run_harmony(...)— Harmony batch correction viaharmonypy; stores aDimReduc("harmony")usable downstream (find_neighbors(reduction="harmony"), etc.). Verified to lower per-batch silhouette while preserving cell-type separation.integrate_layers(...)— Seurat v5 dispatch API (method="harmony";cca/rpcaraiseNotImplementedError, on the roadmap).- New
[integration]extra:pip install "shanuz[integration]"(pullsharmonypy).
Multimodal WNN (v0.4.0)
find_multi_modal_neighbors(...)— Weighted Nearest Neighbor analysis (Hao et al. 2021). Learns per-cell modality weights, builds jointwknn/wsnngraphs, and writes<assay>.weightcolumns.run_umap(graph=...)— embed a precomputed graph (e.g.wsnn) directly, sofind_clusters/run_umapwork on the joint WNN graph.
Additional reductions (v0.5.0)
run_ica(embeddings + loadings) andrun_tsne.
Tutorials & docs
- CBMC CITE-seq tutorial extended with a WNN section (
run_wnn, Step 8). - README links made absolute so they render on the PyPI page; test count updated (156).
Install
pip install "shanuz[integration]" # + Harmony
pip install "shanuz[all]" # everythingNotes
- WNN uses the roadmap-sanctioned scale-invariant weight approximation (validated by structure recovery, not bit-exact R parity).
- Deferred to future cycles: CCA/RPCA +
IntegrateData, v0.3.0 reference mapping, DESeq2 pseudobulk, SketchData/BPCells.
PyPI: https://pypi.org/project/shanuz/0.2.0/
Full diff: v0.1.2...v0.2.0
Shanuz v0.1.1
Spatial transcriptomics (Xenium / Visium / CosMx)
This release adds a spatial analysis layer to shanuz — Seurat-parity loaders and
neighbourhood/niche analysis, validated end-to-end against R Seurat.
Added
- Loaders:
load_xenium,load_visium,load_cosmx— each returns aShanuz
object with expression and populated per-FOV centroids (.images).
load_xeniumkeeps onlyGene Expressionfeatures by default (matching
LoadXenium's assay split;keep_controls=Trueto retain controls). - Spatial-aware
from_anndata— rebuilds.imagesfromobsm['spatial']+
obs['fov']instead of misfiling it as a bogus PCA-style reduction. - Neighbourhood / niche analysis:
get_tissue_coordinates,spatial_knn,
nearest_neighbor_distance,local_neighborhood,build_niche_assay
(Seurat v5'sBuildNicheAssay),composition_test(directional Fisher/BH
enrichment across a categorical split). - Spatial plots:
image_dim_plot/image_feature_plot— matplotlib
centroid scatter, immune to theggplot24.xImageDimPlotblank-render bug. add_module_score(search=True)— case/punctuation-insensitive gene-symbol
resolution (localUpdateSymbolListstand-in).datasets.xenium_mouse_brain()— one-line auto-download (~20 MB) of a
public 10x Xenium dataset for the new tutorial.- Tutorial 5 — Xenium spatial (R vs Python): side-by-side R Seurat / shanuz
walkthrough on a public 10x Xenium mouse-brain section (36,602 cells x 248
genes — the dataset in Seurat's own spatial vignette). Every deterministic
anchor (cell counts, marker-defined cell types, nearest-neighbour distances,
local density, composition test) matches R to 8 significant figures. - GitHub Actions CI (ruff + pytest across Python 3.10-3.12),
py.typedmarker.
Notes
- Still open for the spatial milestone (tracked in
ROADMAP.md): a MERSCOPE
loader,FindSpatiallyVariableFeatures(Moran's I), and Visium tissue-image
(SpatialDimPlot/SpatialFeaturePlot) plots. - No breaking changes — all additions are backward compatible; the four
existing tutorials (PBMC 3k, PBMC 8k, CBMC CITE-seq, SCTransform) were rerun
end-to-end post-merge with no regressions.
Full changelog: v0.1.0...v0.1.1
Shanuz v0.1.0
Shanuz v0.1.0 — First Release
A Python port of the Seurat single-cell RNA-seq analysis framework, algorithmically faithful to Seurat v5.
Features
Core data structures
Shanuzobject mirroring the RSeuratS4 classAssay5— sparse-matrix-backed multi-layer assay with per-layer feature/cell name trackingGraph,DimReduc,Neighbor— faithful ports of Seurat's internal structures
Preprocessing
normalize_data— LogNormalize and CLR (Seurat-exact formula)find_variable_features— VST with Seurat-faithful dispersion and LOESSscale_data— z-score withddof=1(sample SD, matching R)percentage_feature_set
Normalization
sctransform— regularized negative-binomial Pearson residuals; vectorised Poisson IRLS, moment-estimated theta, LOESS regularisation,vars_to_regresssupport
Signature scoring
add_module_score— binned control-gene scoring (Tirosh 2016)cell_cycle_scoring— S/G2M phase assignment with built-inCC_GENES
Dimensionality reduction & neighbours
run_pca(scikit-learn,ddof=1stdev)find_neighbors— KNN + fully-sparse SNN (no dense n×n materialisation)jack_straw/score_jackstraw— JackStraw permutation testrun_umap(umap-learn)
Clustering
find_clusters— Louvain (python-igraph, deterministic igraph RNG seeding) and Leiden (leidenalg)
Differential expression
find_markers/find_all_markerswith test types:wilcox(tie-corrected Mann-Whitney U),t,LR(logistic LRT),negbinom(NB GLM LRT),roc(AUC + power)
Plotting
dim_plot,feature_plot,vln_plot,dot_plot,elbow_plot,do_heatmap,dim_heatmap,feature_scatter,variable_feature_plot,ridge_plot
AnnData interoperability
as_anndata,from_anndata
Tutorials
Four end-to-end tutorials validated against the official Seurat vignettes, each pairing R and Python code with side-by-side output plots:
| # | Tutorial |
|---|---|
| 1 | PBMC 3k — Guided Clustering |
| 2 | PBMC 8k — Advanced Subclustering |
| 3 | CBMC CITE-seq — Multimodal (RNA + ADT) |
| 4 | PBMC 3k — SCTransform |
Tests
129 unit tests, all passing.
Installation
git clone https://github.com/GenomicAI/shanuz.git
cd shanuz
pip install -e ".[analysis]"Algorithms faithfully ported from R Seurat
- Seurat CLR formula (
log1p(x / exp(Σ log1p(x>0) / n))) - VST dispersion with Bessel correction
- Wilcoxon with tie correction (
scipy.stats.mannwhitneyu, asymptotic) - SCTransform NB model (Hafemeister & Satija 2019; Choudhary & Satija 2022)
- AddModuleScore (Tirosh et al. 2016)
- JackStraw permutation test