Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

sclsd: Latent Space Dynamics for Single-Cell Trajectory Inference

Python 3.9+License: MITPyPI

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.

Overview

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

Installation

pip install sclsd

Or from source:

git clone https://github.com/csglab/sclsd.git
cd sclsd
pip install -e .

Dependencies

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.

Quick Start

importscanpyasscimporttorchfromsclsdimportLSD, LSDConfig# Load preprocessed AnnData (log-normalized, with neighbors computed)adata=sc.read("data.h5ad")
# Configure modelcfg=LSDConfig()
cfg.model.z_dim=10# Cell state dimensionalitycfg.walks.path_len=50# Trajectory length for trainingcfg.walks.num_walks=4096# Number of training trajectories# Initialize modeldevice=torch.device("cuda"iftorch.cuda.is_available() else"cpu")
lsd=LSD(adata, cfg, device=device)
# Set prior transition matrix from pseudotimelsd.set_prior_transition(prior_time_key="dpt_pseudotime")
# Generate training trajectorieslsd.prepare_walks()
# Trainlsd.train(num_epochs=100)
# Get resultsresult=lsd.get_adata()

Output

After training, lsd.get_adata() returns an AnnData object with:

KeyLocationDescription
X_cell_stateobsmLatent cell state representation
X_diff_stateobsm2D differentiation state embedding
potentialobsWaddington potential value
entropyobsDevelopmental entropy (plasticity)
lsd_pseudotimeobsPseudotime derived from potential
transitionsobspCell-cell transition probability matrix

Key Methods

Cell Fate Prediction

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"]

Velocity Streamlines

Visualize differentiation flow fields:

lsd.stream_lines("X_umap", color="clusters")

In Silico Gene Perturbation

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
)

Configuration

Key parameters in LSDConfig:

cfg=LSDConfig()
# Model architecturecfg.model.z_dim=10# Cell state dimensionscfg.model.B_dim=2# Differentiation state dimensions (default: 2)cfg.model.V_coeff=0.01# Potential regularization# Training trajectoriescfg.walks.path_len=50# Steps per trajectorycfg.walks.num_walks=4096# Number of trajectoriescfg.walks.batch_size=256# Batch size# Optimizercfg.optimizer.adam.lr=1e-3# Learning rate

Data Requirements

Input 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.obs when initializing transitions from a pseudotime key; alternatively, users may supply a transition matrix directly

Method

LSD models cell state dynamics via the stochastic differential equation:

$$dz = -\nabla V(z) , dt + \sigma , dW$$

where $V(z)$ is the Waddington potential parameterized by a neural network, and the gradient defines a neural ODE. The model is trained by variational inference, reconstructing gene expression through a zero-inflated negative binomial likelihood.

Training trajectories are generated by random walks on a k-nearest neighbor graph, biased by pseudotime to follow developmental progression.

Reproducibility

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.

Citation

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

View version 1 on bioRxiv

BibTeX

@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}
}

Contact

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.

License

MIT License

About

scLSD: A Latent Space Thermodynamic Model of Cell Differentiation

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages