Vector fields (velocity / drift overlays)#
Cellucid “vector fields” are per-cell displacement vectors in embedding space.
They enable overlays such as:
RNA velocity / flow arrows (scVelo-style, if you already have vectors)
CellRank drift vectors derived from a transition matrix
This page documents:
Mental model (beginner-friendly)#
You have an embedding like UMAP:
X_umapwith shape(n_cells, 2)or(n_cells, 3).You compute (or already have) vectors with the same shape.
Cellucid visualizes those vectors as an animated overlay on top of the embedding.
Vectors are not “absolute positions”; they are arrows attached to each cell.
Practical path (common workflows)#
1) From a CellRank transition matrix → drift vectors#
from cellucid import compute_transition_drift
drift = compute_transition_drift(T, adata.obsm["X_umap"], normalize_rows=True)
Where:
Tis(n_cells, n_cells)(dense or sparse)adata.obsm["X_umap"]is(n_cells, dim)
2) Store drift in adata.obsm using Cellucid naming conventions#
from cellucid import add_transition_drift_to_obsm
key = add_transition_drift_to_obsm(
adata,
T,
basis="umap",
field_prefix="T_fwd",
)
print("Wrote vector field to:", key)
This writes a key like:
T_fwd_umap_2dorT_fwd_umap_3d
3) Export the vectors so the viewer can load them#
from cellucid import prepare
prepare(
latent_space=adata.obsm["X_pca"],
obs=adata.obs,
var=adata.var,
gene_expression=adata.X,
X_umap_2d=adata.obsm.get("X_umap_2d", adata.obsm["X_umap"]),
vector_fields={
# You can pass the new obsm entry directly
key: adata.obsm[key],
},
out_dir="./my_export",
)
Naming conventions (important)#
Cellucid’s recommended keys for vector fields follow:
Explicit:
<field>_<basis>_<dim>dexamples:
velocity_umap_2d,T_fwd_umap_3d
Implicit:
<field>_<basis>(only if you’re sure there’s no ambiguity)
Why explicit keys are recommended:
it avoids clashes when you have both 2D and 3D embeddings,
it makes export/serve behavior deterministic.
API reference#
- cellucid.compute_transition_drift(transition_matrix, embedding, *, normalize_rows=True)[source]#
Compute a per-cell drift vector field from a transition matrix.
- The drift is defined as:
drift = E[next_embedding | current_cell] - current_embedding
- Where:
E[next_embedding] = T @ embedding
- Parameters:
transition_matrix (
Union[ndarray,spmatrix]) – A (n_cells, n_cells) matrix. Sparse matrices are recommended for large datasets. Typical source: CellRank kernels’ transition matrices.embedding (
ndarray) – A (n_cells, dim) array of embedding coordinates (e.g. adata.obsm[‘X_umap’]).normalize_rows (
bool) – If True (default), divides each row’s expectation by its row-sum. This makes the drift invariant to a matrix that isn’t strictly row-stochastic.
- Returns:
Drift vectors shaped (n_cells, dim) as float32.
- Return type:
np.ndarray
- cellucid.add_transition_drift_to_obsm(adata, transition_matrix, *, basis='umap', field_prefix='T_fwd', dim=None, explicit_dim_suffix=True, normalize_rows=True, overwrite=False)[source]#
Compute drift vectors from a transition matrix and store them in adata.obsm.
- The output key follows Cellucid’s vector field naming convention:
Explicit: <field_prefix>_<basis>_<dim>d (default)
Implicit: <field_prefix>_<basis>
Examples
Forward drift in UMAP (2D): T_fwd_umap_2d
Backward drift in UMAP (2D): T_bwd_umap_2d
- Parameters:
adata (anndata.AnnData) – AnnData object to modify.
transition_matrix (
Union[ndarray,spmatrix]) – (n_cells, n_cells) matrix, dense or sparse.basis (
str) – Embedding basis name (default: “umap”).field_prefix (
str) – Prefix for the vector field (default: “T_fwd”). Use e.g. “T_bwd” for backward matrices.dim (
Optional[int]) – Embedding dimensionality to use. If None, it is inferred from the best available embedding in obsm: X_{basis}_3d → X_{basis}_2d → X_{basis}_1d → X_{basis} (if 1D/2D/3D).explicit_dim_suffix (
bool) – If True, appends _{dim}d to the output key (recommended for clash-safe imports).normalize_rows (
bool) – Whether to row-normalize during drift computation (see compute_transition_drift).overwrite (
bool) – If False (default), raises if the target key already exists.
- Returns:
The obsm key written.
- Return type:
Edge cases (do not skip)#
Row normalization (transition matrices)#
If your transition matrix is not row-stochastic, set
normalize_rows=True(default).Rows with sum 0 are handled safely (division-by-zero is avoided), but the resulting drift can be zero/undefined depending on the matrix.
Shape mismatches#
transition_matrixmust be(n_cells, n_cells)embeddingmust be(n_cells, dim)The product
T @ embeddingmust produce(n_cells, dim)
Dimension mismatch between export and vectors#
If you export
X_umap_3dbut only provide*_umap_2dvectors, the 3D overlay will not be available.
Troubleshooting (symptom → diagnosis → fix)#
Symptom: “embedding must be 2D”#
Fix:
Ensure you pass an array shaped
(n_cells, dim)(not a flattened vector).
Symptom: “T @ embedding produced shape …”#
Fix:
Confirm
Tis(n_cells, n_cells)and aligned to the same cell order as the embedding.
Symptom: “Vector overlay is not available / not visible in the viewer”#
Likely causes:
You did not export the vector field (or you are serving in AnnData mode without exposing it).
The key naming doesn’t match the embedding dimension currently shown (2D vs 3D).
How to confirm:
In an exported folder, check that
vectors/exists and contains files.In AnnData mode, confirm the vector field exists in
adata.obsmwith the expected key.
Fix:
Export vectors via
prepare(..., vector_fields={...}).Prefer explicit keys like
velocity_umap_2dandvelocity_umap_3dif you use multiple dimensions.
Symptom: “Drift vectors look backwards”#
Likely causes:
You used a backward transition matrix or the wrong convention for
field_prefix.
Fix:
Compute/label forward vs backward consistently (e.g.,
field_prefix="T_fwd"vs"T_bwd").Validate by checking a few expected transitions in a small subset.
See also#
Export / Data Preparation (prepare) for exporting vector fields via
prepare(...)