Dynamo One-Shot Total RNA Velocity
Goal
Run the stable execution spine behind the hematopoiesis scNT-seq tutorial: preprocess a one-shot labeling dataset, smooth by labeling time, force the Model-2 no-splicing branch for kinetics, compute total RNA velocity with alpha - gamma * s, then project that custom velocity to a low-dimensional embedding without treating the tutorial dataset as the workflow identity.
Quick Workflow
- Inspect the input
AnnData for new, total, and time, plus any reusable helpers such as uns["genes_to_use"] and obsm["X_umap"].
- Preprocess with the monocle path. If a curated gene list exists, preserve it explicitly and use
Preprocessor(force_gene_list=...) plus config_monocle_recipe(..., n_top_genes=len(gene_list)).
- Materialize grouped moments with
dyn.tl.moments(..., group='time') so the one-shot fit sees time-specific neighborhoods and creates M_n, M_t, and M_s.
- Force the no-splicing Model-2 branch by setting
adata.uns["pp"]["has_splicing"] = False, then run dyn.tl.dynamics(..., group='time', model='deterministic') unless the user explicitly wants another branch.
- Convert the fitted kinetic parameters into total RNA velocity with
dyn.tl.calculate_velocity_alpha_minus_gamma_s(...).
- Project the custom total RNA velocity with
dyn.tl.cell_velocities(..., X=adata.layers["M_t"], V=adata.layers["velocity_alpha_minus_gamma_s"], method='cosine').
- Treat
streamline_plot and phase_portraits as optional visualization steps after velocity_umap already exists.
Interface Summary
Preprocessor.config_monocle_recipe(adata, n_top_genes=2000) configures the notebook-style monocle preprocessing path.
Preprocessor.preprocess_adata_monocle(adata, tkey=None, experiment_type=None) is the exact notebook entrypoint; Preprocessor.preprocess_adata(..., recipe='monocle', ...) is the higher-level wrapper.
dyn.tl.moments(..., group=None, use_gaussian_kernel=False, use_mnn=False, layers='all') creates smoothed first and second moments and stores obsp["moments_con"].
dyn.tl.dynamics(..., group=None, model='auto', est_method='auto', ...) estimates one-shot kinetic parameters and writes velocity-like layers such as velocity_N and velocity_T.
dyn.tl.calculate_velocity_alpha_minus_gamma_s(adata, gene_subset_key='use_for_pca', velocity_layer_name='velocity_alpha_minus_gamma_s') converts fitted rates plus M_n and M_s into the total RNA velocity layer used in the notebook.
dyn.tl.cell_velocities(..., X=None, V=None, basis='umap', method='pearson', adj_key='distances', enforce=False) projects the custom velocity to low-dimensional space and stores a kernel-specific transition matrix.
dyn.pl.streamline_plot(..., basis='umap', method='gaussian') and dyn.pl.phase_portraits(...) are optional presentation entrypoints after the analytical path is complete.
Read references/source-grounding.md before documenting narrower parameter behavior than the live source currently supports.
Branch Selection
- Use the curated-gene-list branch when
uns["genes_to_use"] or a user-supplied marker/HVG list exists. Preserve that list explicitly before subsetting or concatenating because anndata.concat(...) can drop it.
- Use
recipe='monocle' for this workflow family. Other recipe branches are real source-level options, but the total-RNA one-shot path here was empirically checked only on the monocle branch.
- Use
group='time' on moments(...) and dynamics(...) unless the user explicitly wants to smooth and fit without time-specific neighborhoods.
- Use
one_shot_method='sci_fate' for notebook parity and one_shot_method='combined' when the user explicitly wants the steady-state-plus-absolute-gamma branch. Both were empirically checked.
- Use
model='deterministic' by default for this total-RNA workflow. If the user wants a splicing-aware or stochastic branch, stop and switch to a different workflow instead of silently mixing models.
- Use
cell_velocities(..., method='cosine') for notebook-style total-RNA projection. Use method='pearson' when the user wants the alternate kernel with a different transition-matrix key. Treat kmc, fp, and transform as advanced branches with extra assumptions.
- Use
streamline_plot(..., method='gaussian') for default streamline rendering. Switch to method='SparseVFC' only after a vector field has been reconstructed and the user explicitly wants that rendering path.
Read references/branch-selection.md before choosing non-default recipe, one_shot_method, model, method, or plotting branches.
Input Contract
- Expect a metabolic-labeling
AnnData with usable new and total layers and a labeling-time column.
- Expect the time column to be accessible as
adata.obs["time"] before calling calculate_velocity_alpha_minus_gamma_s(...), or rename / copy the user's time key to time.
- Treat
spliced and unspliced as optional inputs for the raw object, not as the target model branch. The notebook-compatible total-RNA path forces has_splicing=False before dynamics(...).
- Expect
M_n, M_t, and M_s to be created by moments(...) before calling calculate_velocity_alpha_minus_gamma_s(...).
- Expect a valid embedding such as
X_umap plus a matching adjacency matrix under obsp["distances"] before calling cell_velocities(...).
- Treat tutorial-specific fields such as
genes_to_use, cell_type, and the hematopoiesis sample layout as worked examples, not universal defaults.
Minimal Execution Patterns
For the notebook-compatible one-shot total RNA workflow:
import dynamo as dyn
adata = dyn.sample_data.hematopoiesis_raw()
adata.obs_names_make_unique()
selected_genes = list(adata.uns["genes_to_use"])
pre = dyn.pp.Preprocessor(force_gene_list=selected_genes)
pre.config_monocle_recipe(adata, n_top_genes=len(selected_genes))
pre.preprocess_adata_monocle(adata, tkey="time", experiment_type="one-shot")
dyn.tl.reduceDimension(adata)
dyn.tl.moments(adata, group="time")
adata.uns["pp"]["has_splicing"] = False
dyn.tl.dynamics(
adata,
group="time",
model="deterministic",
cores=1,
)
dyn.tl.calculate_velocity_alpha_minus_gamma_s(adata)
dyn.tl.cell_velocities(
adata,
enforce=True,
X=adata.layers["M_t"],
V=adata.layers["velocity_alpha_minus_gamma_s"],
method="cosine",
)
For a generic one-shot labeling dataset without a baked-in gene list:
pre = dyn.pp.Preprocessor()
pre.preprocess_adata(adata, recipe="monocle", tkey="time", experiment_type="one-shot")
For a non-default combined one-shot branch:
dyn.tl.dynamics(
adata,
group="time",
model="deterministic",
cores=1,
)
For a non-default pearson projection branch:
dyn.tl.cell_velocities(
adata,
enforce=True,
X=adata.layers["M_t"],
V=adata.layers["velocity_alpha_minus_gamma_s"],
method="pearson",
)
Validation
After preprocessing, check these items:
adata.uns["pp"]["experiment_type"] == "one-shot"
adata.var["use_for_pca"] exists
adata.obsm["X_pca"] exists
After moments(..., group='time'), check these items:
adata.obsp["moments_con"] exists
adata.layers["M_n"], adata.layers["M_t"], and adata.layers["M_s"] exist
Before dynamics(...), check these items:
adata.obs["time"] exists
adata.uns["pp"]["has_splicing"] is False for the Model-2 branch
After dynamics(...), check these items:
adata.uns["dynamics"]["model"] == "deterministic" for the default branch
adata.layers["velocity_T"] exists
adata.var["use_for_dynamics"] exists
After calculate_velocity_alpha_minus_gamma_s(...), check these items:
adata.layers["velocity_alpha_minus_gamma_s"] exists
- the function reports each unique time point it processed
After cell_velocities(...), check these items:
adata.obsm["velocity_umap"] exists for the default UMAP branch
adata.obsp["cosine_transition_matrix"] exists for method='cosine'
adata.obsp["pearson_transition_matrix"] exists for method='pearson'
Constraints
- Do not treat
velocity_T from dynamics(...) as the notebook endpoint. The tutorial's total-RNA visualization path depends on the extra calculate_velocity_alpha_minus_gamma_s(...) plus cell_velocities(...) steps.
- Do not forget to rename or copy the time column to
adata.obs["time"] before calculate_velocity_alpha_minus_gamma_s(...); current source hard-codes that key.
- Do not assume
uns["genes_to_use"] survives AnnData concatenation or subsetting workflows. Preserve it explicitly when reconstructing subsets.
- Do not keep
has_splicing=True if the goal is Model-2 total RNA velocity. Preprocessing auto-detects splicing and labeling together on the hematopoiesis raw object.
- Do not interpret
one_shot_method from adata.uns["dynamics"]; current runtime does not store it there.
- Do not make small per-time groups the default. Reviewer runs with fewer than
50 cells per time group emitted NaN-velocity warnings and filtered genes before projection.
Resource Map
- Read
references/branch-selection.md for decision rules across recipe, grouped smoothing, one_shot_method, and projection method branches.
- Read
references/visualization-and-phase-portraits.md when the user explicitly wants notebook-style streamlines or total-RNA phase-portrait adaptation.
- Read
references/source-grounding.md for inspected signatures, source-level branch evidence, and empirical execution notes.
- Read
references/source-notebook-map.md to see how docs/tutorials/notebooks/301_tutorial_hsc_velocity.ipynb was converted into this reusable skill.
- Read
references/compatibility.md when notebook wording and current source behavior diverge.
1---2name: dynamo-one-shot-total-rna-velocity3description: Run or adapt a one-shot total RNA velocity workflow in `dynamo` for metabolic-labeling or scNT-seq `AnnData`, including monocle preprocessing with an optional curated gene list, grouped moments by labeling time, Model-2 `dynamics`, `calculate_velocity_alpha_minus_gamma_s`, low-dimensional projection with `cell_velocities`, and optional streamline or phase-portrait plotting. Use when converting tutorials such as `301_tutorial_hsc_velocity.ipynb`, or when choosing between `one_shot_method` branches like `sci_fate` and `combined` and projection `method` branches like `cosine` and `pearson`.4---56# Dynamo One-Shot Total RNA Velocity78## Goal910Run the stable execution spine behind the hematopoiesis scNT-seq tutorial: preprocess a one-shot labeling dataset, smooth by labeling time, force the Model-2 no-splicing branch for kinetics, compute total RNA velocity with `alpha - gamma * s`, then project that custom velocity to a low-dimensional embedding without treating the tutorial dataset as the workflow identity.1112## Quick Workflow13141. Inspect the input `AnnData` for `new`, `total`, and `time`, plus any reusable helpers such as `uns["genes_to_use"]` and `obsm["X_umap"]`.152. Preprocess with the monocle path. If a curated gene list exists, preserve it explicitly and use `Preprocessor(force_gene_list=...)` plus `config_monocle_recipe(..., n_top_genes=len(gene_list))`.163. Materialize grouped moments with `dyn.tl.moments(..., group='time')` so the one-shot fit sees time-specific neighborhoods and creates `M_n`, `M_t`, and `M_s`.174. Force the no-splicing Model-2 branch by setting `adata.uns["pp"]["has_splicing"] = False`, then run `dyn.tl.dynamics(..., group='time', one_shot_method='sci_fate', model='deterministic')` unless the user explicitly wants another branch.185. Convert the fitted kinetic parameters into total RNA velocity with `dyn.tl.calculate_velocity_alpha_minus_gamma_s(...)`.196. Project the custom total RNA velocity with `dyn.tl.cell_velocities(..., X=adata.layers["M_t"], V=adata.layers["velocity_alpha_minus_gamma_s"], method='cosine')`.207. Treat `streamline_plot` and `phase_portraits` as optional visualization steps after `velocity_umap` already exists.2122## Interface Summary2324- `Preprocessor.config_monocle_recipe(adata, n_top_genes=2000)` configures the notebook-style monocle preprocessing path.25- `Preprocessor.preprocess_adata_monocle(adata, tkey=None, experiment_type=None)` is the exact notebook entrypoint; `Preprocessor.preprocess_adata(..., recipe='monocle', ...)` is the higher-level wrapper.26- `dyn.tl.moments(..., group=None, use_gaussian_kernel=False, use_mnn=False, layers='all')` creates smoothed first and second moments and stores `obsp["moments_con"]`.27- `dyn.tl.dynamics(..., group=None, model='auto', est_method='auto', one_shot_method='combined', ...)` estimates one-shot kinetic parameters and writes velocity-like layers such as `velocity_N` and `velocity_T`.28- `dyn.tl.calculate_velocity_alpha_minus_gamma_s(adata, gene_subset_key='use_for_pca', velocity_layer_name='velocity_alpha_minus_gamma_s')` converts fitted rates plus `M_n` and `M_s` into the total RNA velocity layer used in the notebook.29- `dyn.tl.cell_velocities(..., X=None, V=None, basis='umap', method='pearson', adj_key='distances', enforce=False)` projects the custom velocity to low-dimensional space and stores a kernel-specific transition matrix.30- `dyn.pl.streamline_plot(..., basis='umap', method='gaussian')` and `dyn.pl.phase_portraits(...)` are optional presentation entrypoints after the analytical path is complete.3132Read `references/source-grounding.md` before documenting narrower parameter behavior than the live source currently supports.3334## Branch Selection3536- Use the curated-gene-list branch when `uns["genes_to_use"]` or a user-supplied marker/HVG list exists. Preserve that list explicitly before subsetting or concatenating because `anndata.concat(...)` can drop it.37- Use `recipe='monocle'` for this workflow family. Other `recipe` branches are real source-level options, but the total-RNA one-shot path here was empirically checked only on the monocle branch.38- Use `group='time'` on `moments(...)` and `dynamics(...)` unless the user explicitly wants to smooth and fit without time-specific neighborhoods.39- Use `one_shot_method='sci_fate'` for notebook parity and `one_shot_method='combined'` when the user explicitly wants the steady-state-plus-absolute-gamma branch. Both were empirically checked.40- Use `model='deterministic'` by default for this total-RNA workflow. If the user wants a splicing-aware or stochastic branch, stop and switch to a different workflow instead of silently mixing models.41- Use `cell_velocities(..., method='cosine')` for notebook-style total-RNA projection. Use `method='pearson'` when the user wants the alternate kernel with a different transition-matrix key. Treat `kmc`, `fp`, and `transform` as advanced branches with extra assumptions.42- Use `streamline_plot(..., method='gaussian')` for default streamline rendering. Switch to `method='SparseVFC'` only after a vector field has been reconstructed and the user explicitly wants that rendering path.4344Read `references/branch-selection.md` before choosing non-default `recipe`, `one_shot_method`, `model`, `method`, or plotting branches.4546## Input Contract4748- Expect a metabolic-labeling `AnnData` with usable `new` and `total` layers and a labeling-time column.49- Expect the time column to be accessible as `adata.obs["time"]` before calling `calculate_velocity_alpha_minus_gamma_s(...)`, or rename / copy the user's time key to `time`.50- Treat `spliced` and `unspliced` as optional inputs for the raw object, not as the target model branch. The notebook-compatible total-RNA path forces `has_splicing=False` before `dynamics(...)`.51- Expect `M_n`, `M_t`, and `M_s` to be created by `moments(...)` before calling `calculate_velocity_alpha_minus_gamma_s(...)`.52- Expect a valid embedding such as `X_umap` plus a matching adjacency matrix under `obsp["distances"]` before calling `cell_velocities(...)`.53- Treat tutorial-specific fields such as `genes_to_use`, `cell_type`, and the hematopoiesis sample layout as worked examples, not universal defaults.5455## Minimal Execution Patterns5657For the notebook-compatible one-shot total RNA workflow:5859```python60import dynamo as dyn6162adata = dyn.sample_data.hematopoiesis_raw()63adata.obs_names_make_unique()6465selected_genes = list(adata.uns["genes_to_use"])6667pre = dyn.pp.Preprocessor(force_gene_list=selected_genes)68pre.config_monocle_recipe(adata, n_top_genes=len(selected_genes))69pre.preprocess_adata_monocle(adata, tkey="time", experiment_type="one-shot")7071dyn.tl.reduceDimension(adata)72dyn.tl.moments(adata, group="time")7374adata.uns["pp"]["has_splicing"] = False75dyn.tl.dynamics(76 adata,77 group="time",78 one_shot_method="sci_fate",79 model="deterministic",80 cores=1,81)8283dyn.tl.calculate_velocity_alpha_minus_gamma_s(adata)84dyn.tl.cell_velocities(85 adata,86 enforce=True,87 X=adata.layers["M_t"],88 V=adata.layers["velocity_alpha_minus_gamma_s"],89 method="cosine",90)91```9293For a generic one-shot labeling dataset without a baked-in gene list:9495```python96pre = dyn.pp.Preprocessor()97pre.preprocess_adata(adata, recipe="monocle", tkey="time", experiment_type="one-shot")98```99100For a non-default `combined` one-shot branch:101102```python103dyn.tl.dynamics(104 adata,105 group="time",106 one_shot_method="combined",107 model="deterministic",108 cores=1,109)110```111112For a non-default `pearson` projection branch:113114```python115dyn.tl.cell_velocities(116 adata,117 enforce=True,118 X=adata.layers["M_t"],119 V=adata.layers["velocity_alpha_minus_gamma_s"],120 method="pearson",121)122```123124## Validation125126After preprocessing, check these items:127128- `adata.uns["pp"]["experiment_type"] == "one-shot"`129- `adata.var["use_for_pca"]` exists130- `adata.obsm["X_pca"]` exists131132After `moments(..., group='time')`, check these items:133134- `adata.obsp["moments_con"]` exists135- `adata.layers["M_n"]`, `adata.layers["M_t"]`, and `adata.layers["M_s"]` exist136137Before `dynamics(...)`, check these items:138139- `adata.obs["time"]` exists140- `adata.uns["pp"]["has_splicing"] is False` for the Model-2 branch141142After `dynamics(...)`, check these items:143144- `adata.uns["dynamics"]["model"] == "deterministic"` for the default branch145- `adata.layers["velocity_T"]` exists146- `adata.var["use_for_dynamics"]` exists147148After `calculate_velocity_alpha_minus_gamma_s(...)`, check these items:149150- `adata.layers["velocity_alpha_minus_gamma_s"]` exists151- the function reports each unique time point it processed152153After `cell_velocities(...)`, check these items:154155- `adata.obsm["velocity_umap"]` exists for the default UMAP branch156- `adata.obsp["cosine_transition_matrix"]` exists for `method='cosine'`157- `adata.obsp["pearson_transition_matrix"]` exists for `method='pearson'`158159## Constraints160161- Do not treat `velocity_T` from `dynamics(...)` as the notebook endpoint. The tutorial's total-RNA visualization path depends on the extra `calculate_velocity_alpha_minus_gamma_s(...)` plus `cell_velocities(...)` steps.162- Do not forget to rename or copy the time column to `adata.obs["time"]` before `calculate_velocity_alpha_minus_gamma_s(...)`; current source hard-codes that key.163- Do not assume `uns["genes_to_use"]` survives `AnnData` concatenation or subsetting workflows. Preserve it explicitly when reconstructing subsets.164- Do not keep `has_splicing=True` if the goal is Model-2 total RNA velocity. Preprocessing auto-detects splicing and labeling together on the hematopoiesis raw object.165- Do not interpret `one_shot_method` from `adata.uns["dynamics"]`; current runtime does not store it there.166- Do not make small per-time groups the default. Reviewer runs with fewer than `50` cells per time group emitted NaN-velocity warnings and filtered genes before projection.167168## Resource Map169170- Read `references/branch-selection.md` for decision rules across `recipe`, grouped smoothing, `one_shot_method`, and projection `method` branches.171- Read `references/visualization-and-phase-portraits.md` when the user explicitly wants notebook-style streamlines or total-RNA phase-portrait adaptation.172- Read `references/source-grounding.md` for inspected signatures, source-level branch evidence, and empirical execution notes.173- Read `references/source-notebook-map.md` to see how `docs/tutorials/notebooks/301_tutorial_hsc_velocity.ipynb` was converted into this reusable skill.174- Read `references/compatibility.md` when notebook wording and current source behavior diverge.