sclsd implements Latent Space Dynamics (LSD), a thermodynamic framework for modeling cell differentiation from single-cell RNA sequencing data.
Notebooks for reproducing manuscript figures and analyses are available at csglab/sclsd-manuscript.
This README is the maintained documentation for the sclsd package. It covers
installation, input data, configuration, training, inference, reproducibility,
and citation information.
LSD reinterprets Waddington's epigenetic landscape as an energy landscape in a learned latent cell state space. Cell differentiation is modeled as a stochastic dynamical system governed by a gradient flow down this potential surface, combined with noise representing gene expression variability.
The model jointly infers:
- Cell state: A latent representation of each cell's gene expression profile
- Differentiation state: A 2D embedding capturing developmental progression
- Waddington potential: An energy function whose gradient defines differentiation dynamics
- Developmental entropy: A measure of cellular plasticity derived from the uncertainty in differentiation state
pip install sclsdOr from source:
git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .The package requires Python 3.9 or later. Runtime dependencies, including
PyTorch, Pyro, torchdiffeq, Scanpy, AnnData, and CellRank, are installed by
pip. The complete dependency specification is maintained in
pyproject.toml.
import scanpy as sc
import torch
from sclsd import LSD, LSDConfig
# Load preprocessed AnnData (log-normalized, with neighbors computed)
adata = sc.read("data.h5ad")
# Configure model
cfg = LSDConfig()
cfg.model.z_dim = 10 # Cell state dimensionality
cfg.walks.path_len = 50 # Trajectory length for training
cfg.walks.num_walks = 4096 # Number of training trajectories
# Initialize model
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
lsd = LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotime
lsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectories
lsd.prepare_walks()
# Train
lsd.train(num_epochs=100)
# Get results
result = lsd.get_adata()After training, lsd.get_adata() returns an AnnData object with:
| Key | Location | Description |
|---|---|---|
X_cell_state |
obsm |
Latent cell state representation |
X_diff_state |
obsm |
2D differentiation state embedding |
potential |
obs |
Waddington potential value |
entropy |
obs |
Developmental entropy (plasticity) |
lsd_pseudotime |
obs |
Pseudotime derived from potential |
transitions |
obsp |
Cell-cell transition probability matrix |
Propagate cells through the learned landscape to predict terminal fates:
result = lsd.get_cell_fates(
adata=result,
time_range=15.0,
cluster_key="clusters",
return_paths=True
)
# Predicted fates stored in result.obs["fate"]Visualize differentiation flow fields:
lsd.stream_lines("X_umap", color="clusters")Simulate gene knockouts and predict fate changes:
X = torch.from_numpy(result.X.toarray()).float()
perturbed_fates, unperturbed_fates = lsd.perturb(
adata=result,
x=X,
gene_name="Noto",
cluster_key="clusters",
perturbation_level=0 # Knockout
)Key parameters in LSDConfig:
cfg = LSDConfig()
# Model architecture
cfg.model.z_dim = 10 # Cell state dimensions
cfg.model.B_dim = 2 # Differentiation state dimensions (default: 2)
cfg.model.V_coeff = 0.01 # Potential regularization
# Training trajectories
cfg.walks.path_len = 50 # Steps per trajectory
cfg.walks.num_walks = 4096 # Number of trajectories
cfg.walks.batch_size = 256 # Batch size
# Optimizer
cfg.optimizer.adam.lr = 1e-3 # Learning rateInput AnnData should contain:
- Log-normalized expression in
adata.X - Raw counts in
adata.layers["raw"] - Library sizes in
adata.obs["librarysize"] - Precomputed neighbor graph in
adata.obsp["connectivities"] - Pseudotime values in
adata.obswhen initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly
LSD models cell state dynamics via the stochastic differential equation:
where
Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.
Dataset-specific training and postprocessing notebooks are available in the
sclsd-manuscript repository.
The preprocessed datasets used by those notebooks are available from
Zenodo record 18331587.
If you use sclsd or the accompanying analyses, please cite:
Poursina, A., Hajhashemi, S., Mikaeili Namini, A., Saberi, A., Emad, A., & Najafabadi, H. S. (2026). A Latent Space Thermodynamic Model of Cell Differentiation. bioRxiv, 2026.03.04.709512. https://doi.org/10.64898/2026.03.04.709512
@article{poursina2026latent,
title = {A Latent Space Thermodynamic Model of Cell Differentiation},
author = {Poursina, Ali and Hajhashemi, Shayan and
{Mikaeili Namini}, Arsham and Saberi, Ali and
Emad, Amin and Najafabadi, Hamed S.},
journal = {bioRxiv},
pages = {2026.03.04.709512},
year = {2026},
publisher = {Cold Spring Harbor Laboratory},
doi = {10.64898/2026.03.04.709512},
url = {https://www.biorxiv.org/content/10.64898/2026.03.04.709512v1}
}For questions about the sclsd software, contact Ali Poursina at ali.poursina@mail.mcgill.ca. Bug reports and feature requests can also be submitted through the GitHub issue tracker.
MIT License