3D visualization in dynamo¶
dynamo v1.4 ships a full suite of 3D visualizations (matplotlib, Plotly, PyVista). This tutorial renders them on the pancreatic endocrinogenesis dataset (Ductal → Ngn3 → Pre-endocrine → endocrine), so the 3D velocity arrows can be checked against the 2D flow.
Rendering. Each 3D plot is shown twice: a static image (so it displays on GitHub, which strips interactive JavaScript) followed by the interactive Plotly / PyVista version (rotate & zoom — it renders on nbviewer / readthedocs and in JupyterLab).
import os
os.environ['PYVISTA_OFF_SCREEN'] = 'true'
import warnings; warnings.filterwarnings('ignore')
import io, base64
from IPython.display import HTML, Image, display
import matplotlib.pyplot as plt
import imageio.v2 as imageio
import pyvista as pv
pv.OFF_SCREEN = True
import dynamo as dyn
dyn.configuration.set_figure_params('dynamo', background='white')
def _png(img, w, h):
plt.close('all') # drop the empty matplotlib figure dynamo's pv path leaves open
fig = plt.figure(figsize=(w / 100, h / 100))
plt.imshow(img); plt.axis('off'); fig.tight_layout(pad=0); plt.show()
def show_pv_both(obj, w=720, h=560):
"""Static screenshot (for GitHub) + interactive scene (for nbviewer / readthedocs)."""
pl = obj[0] if isinstance(obj, (list, tuple)) else obj
pl.window_size = [w, h]
_png(pl.screenshot(return_img=True), w, h)
pl.export_html('_pv.html'); html = open('_pv.html').read(); os.remove('_pv.html')
b64 = base64.b64encode(html.encode()).decode()
display(HTML(f'<iframe src="data:text/html;base64,{b64}" width="{w}" height="{h}" frameborder="0"></iframe>'))
def show_plotly(fig):
display(HTML(fig.to_html(include_plotlyjs='cdn', full_html=False)))
1. Preprocess and estimate velocity¶
adata = dyn.sample_data.pancreatic_endocrinogenesis()
celltype_key = 'clusters'
dyn.pp.Preprocessor().preprocess_adata(adata, recipe='monocle')
dyn.tl.dynamics(adata, model='stochastic', cores=4)
adata
|-----> Downloading data to ./data/endocrinogenesis_day15.h5ad
|-----> File ./data/endocrinogenesis_day15.h5ad already exists.
|-----> Running monocle preprocessing pipeline...
|-----------> filtered out 0 outlier cells
|-----------> filtered out 21736 outlier genes
|-----> PCA dimension reduction
|-----> <insert> X_pca to obsm in AnnData Object.
|-----> [Preprocessor-monocle] completed [3.7344s]
╭─ SUMMARY: Preprocessor.preprocess_adata ───────────────────────────╮
│ Duration: 3.7363s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
│ ● OBS │ ✚ Size_Factor (float) │
│ │ ✚ initial_cell_size (float) │
│ │ ✚ initial_spliced_cell_size (float) │
│ │ ✚ initial_unspliced_cell_size (float) │
│ │ ✚ nCounts (float) │
│ │ ✚ nGenes (int) │
│ │ ✚ ntr (float) │
│ │ ✚ pMito (float) │
│ │ ✚ pass_basic_filter (bool) │
│ │ ✚ spliced_Size_Factor (float) │
│ │ ✚ unspliced_Size_Factor (float) │
│ │
│ ● VAR │ ✚ frac (float) │
│ │ ✚ log_cv (float) │
│ │ ✚ log_m (float) │
│ │ ✚ nCells (int) │
│ │ ✚ nCounts (float) │
│ │ ✚ ntr (float) │
│ │ ✚ pass_basic_filter (bool) │
│ │ ✚ score (float) │
│ │ ✚ use_for_pca (bool) │
│ │
│ ● UNS │ ✚ PCs │
│ │ ✚ explained_variance_ratio_ │
│ │ ✚ feature_selection │
│ │ ✚ pca_mean │
│ │ ✚ pp │
│ │ ✚ velocyto_SVR │
│ │
│ ● LAYERS │ ✚ X_spliced (sparse matrix, 3696x27998) │
│ │ ✚ X_unspliced (sparse matrix, 3696x27998) │
│ │
╰────────────────────────────────────────────────────────────────────╯
|-----> dynamics_del_2nd_moments_key is None. Using default value from DynamoAdataConfig: dynamics_del_2nd_moments_key=False
|-----------> removing existing M layers:[]...
|-----------> making adata smooth...
|-----> calculating first/second moments...
|-----> [moments calculation] completed [24.4173s]
╭─ SUMMARY: dynamics ────────────────────────────────────────────────╮
│ Duration: 30.5001s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
│ ● VAR │ ✚ use_for_dynamics (bool) │
│ │
│ ● UNS │ ✚ dynamics │
│ │ ✚ vel_params_names │
│ │
│ ● OBSP │ ✚ moments_con (sparse matrix, 3696x3696) │
│ │
│ ● LAYERS │ ✚ M_s (sparse matrix, 3696x27998) │
│ │ ✚ M_ss (sparse matrix, 3696x27998) │
│ │ ✚ M_u (sparse matrix, 3696x27998) │
│ │ ✚ M_us (sparse matrix, 3696x27998) │
│ │ ✚ M_uu (sparse matrix, 3696x27998) │
│ │ ✚ velocity_S (sparse matrix, 3696x27998) │
│ │
╰────────────────────────────────────────────────────────────────────╯
AnnData object with n_obs × n_vars = 3696 × 27998
obs: 'clusters_coarse', 'clusters', 'S_score', 'G2M_score', 'nGenes', 'nCounts', 'pMito', 'pass_basic_filter', 'Size_Factor', 'initial_cell_size', 'spliced_Size_Factor', 'initial_spliced_cell_size', 'unspliced_Size_Factor', 'initial_unspliced_cell_size', 'ntr'
var: 'highly_variable_genes', 'nCells', 'nCounts', 'pass_basic_filter', 'log_m', 'log_cv', 'score', 'frac', 'use_for_pca', 'ntr', 'use_for_dynamics'
uns: 'clusters_coarse_colors', 'clusters_colors', 'day_colors', 'neighbors', 'pca', 'pp', 'velocyto_SVR', 'feature_selection', 'PCs', 'explained_variance_ratio_', 'pca_mean', 'history_log', 'vel_params_names', 'dynamics'
obsm: 'X_pca', 'X_umap'
varm: 'vel_params'
layers: 'spliced', 'unspliced', 'X_spliced', 'X_unspliced', 'M_u', 'M_uu', 'M_s', 'M_us', 'M_ss', 'velocity_S'
obsp: 'distances', 'connectivities', 'moments_con'
2. 2D reference flow¶
The 2D velocity streamlines run from Ductal/Ngn3 progenitors to the endocrine fates — the ground truth we compare the 3D arrows against.
dyn.tl.reduceDimension(adata, basis='umap', n_components=2, enforce=True)
dyn.tl.cell_velocities(adata, basis='umap')
dyn.pl.streamline_plot(adata, color=[celltype_key], basis='umap', figsize=(5, 5))
|-----> retrieve data for non-linear dimension reduction...
|-----> [UMAP] using X_umap with n_pca_components = 30
|-----> <insert> X_umap to obsm in AnnData Object.
|-----> [UMAP] completed [20.6363s]
╭─ SUMMARY: reduceDimension ─────────────────────────────────────────╮
│ Duration: 20.6379s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
│ ● UNS │ ✚ umap_fit │
│ │
╰────────────────────────────────────────────────────────────────────╯
|-----? Some row sums(out degree) in adata's neighbor graph are zero.
|-----> Neighbor graph is broken, recomputing....
|-----> Start computing neighbor graph...
|-----------> X_data is None, fetching or recomputing...
|-----> fetching X data from layer:None, basis:pca
|-----> method arg is None, choosing methods automatically...
|-----------> method ball_tree selected
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 1.0011%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 2.0022%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 3.0032%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 4.0043%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 5.0054%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 6.0065%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 7.0076%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 8.0087%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 9.0097%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 10.0108%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 11.0119%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 12.0130%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 13.0141%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 14.0152%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 15.0162%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 16.0173%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 17.0184%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 18.0195%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 19.0206%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 20.0216%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 21.0227%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 22.0238%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 23.0249%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 24.0260%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 25.0271%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 26.0281%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 27.0292%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 28.0303%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 29.0314%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 30.0325%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 31.0335%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 32.0346%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 33.0357%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 34.0368%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 35.0379%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 36.0390%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 37.0400%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 38.0411%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 39.0422%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 40.0433%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 41.0444%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 42.0455%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 43.0465%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 44.0476%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 45.0487%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 46.0498%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 47.0509%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 48.0519%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 49.0530%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 50.0541%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 51.0552%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 52.0563%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 53.0574%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 54.0584%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 55.0595%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 56.0606%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 57.0617%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 58.0628%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 59.0639%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 60.0649%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 61.0660%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 62.0671%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 63.0682%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 64.0693%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 65.0703%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 66.0714%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 67.0725%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 68.0736%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 69.0747%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 70.0758%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 71.0768%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 72.0779%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 73.0790%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 74.0801%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 75.0812%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 76.0823%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 77.0833%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 78.0844%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 79.0855%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 80.0866%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 81.0877%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 82.0887%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 83.0898%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 84.0909%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 85.0920%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 86.0931%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 87.0942%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 88.0952%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 89.0963%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 90.0974%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 91.0985%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 92.0996%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 93.1006%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 94.1017%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 95.1028%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 96.1039%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 97.1050%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 98.1061%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 99.1071%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] in progress: 100.0000%
|-----> [calculating transition matrix via pearson kernel with sqrt transform.] completed [3.2030s]
|-----> [projecting velocity vector to low dimensional embedding] in progress: 1.0011%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 2.0022%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 3.0032%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 4.0043%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 5.0054%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 6.0065%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 7.0076%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 8.0087%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 9.0097%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 10.0108%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 11.0119%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 12.0130%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 13.0141%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 14.0152%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 15.0162%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 16.0173%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 17.0184%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 18.0195%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 19.0206%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 20.0216%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 21.0227%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 22.0238%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 23.0249%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 24.0260%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 25.0271%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 26.0281%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 27.0292%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 28.0303%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 29.0314%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 30.0325%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 31.0335%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 32.0346%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 33.0357%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 34.0368%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 35.0379%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 36.0390%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 37.0400%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 38.0411%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 39.0422%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 40.0433%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 41.0444%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 42.0455%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 43.0465%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 44.0476%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 45.0487%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 46.0498%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 47.0509%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 48.0519%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 49.0530%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 50.0541%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 51.0552%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 52.0563%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 53.0574%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 54.0584%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 55.0595%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 56.0606%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 57.0617%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 58.0628%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 59.0639%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 60.0649%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 61.0660%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 62.0671%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 63.0682%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 64.0693%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 65.0703%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 66.0714%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 67.0725%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 68.0736%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 69.0747%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 70.0758%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 71.0768%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 72.0779%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 73.0790%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 74.0801%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 75.0812%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 76.0823%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 77.0833%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 78.0844%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 79.0855%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 80.0866%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 81.0877%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 82.0887%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 83.0898%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 84.0909%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 85.0920%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 86.0931%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 87.0942%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 88.0952%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 89.0963%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 90.0974%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 91.0985%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 92.0996%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 93.1006%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 94.1017%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 95.1028%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 96.1039%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 97.1050%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 98.1061%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 99.1071%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 100.0000%
|-----> [projecting velocity vector to low dimensional embedding] completed [0.3836s]
|-----> method arg is None, choosing methods automatically...
|-----------> method kd_tree selected
╭─ SUMMARY: cell_velocities ─────────────────────────────────────────╮
│ Duration: 4.1752s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
│ ● VAR │ ✚ use_for_transition (bool) │
│ │
│ ● UNS │ ✚ grid_velocity_umap │
│ │
│ ● OBSP │ ✚ pearson_transition_matrix (sparse matrix, 3696x3696) │
│ │
│ ● OBSM │ ✚ velocity_umap (array, 3696x2) │
│ │
╰────────────────────────────────────────────────────────────────────╯
|-----> method arg is None, choosing methods automatically...
|-----------> method kd_tree selected
|-----------> plotting with basis key=X_umap
|-----------> skip filtering clusters by stack threshold when stacking color because it is not a numeric type
3. Build a 3D embedding¶
Compute a 3-component UMAP and project velocities onto it.
dyn.tl.reduceDimension(adata, basis='umap', n_components=3, enforce=True)
dyn.tl.cell_velocities(adata, basis='umap')
print('X_umap:', adata.obsm['X_umap'].shape, '| velocity_umap:', adata.obsm['velocity_umap'].shape)
|-----> retrieve data for non-linear dimension reduction...
|-----> [UMAP] using X_umap with n_pca_components = 30
|-----> <insert> X_umap to obsm in AnnData Object.
|-----> [UMAP] completed [17.5555s]
╭─ SUMMARY: reduceDimension ─────────────────────────────────────────╮
│ Duration: 17.557s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
╰────────────────────────────────────────────────────────────────────╯
Using existing pearson_transition_matrix found in .obsp.
|-----> [projecting velocity vector to low dimensional embedding] in progress: 1.0011%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 2.0022%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 3.0032%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 4.0043%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 5.0054%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 6.0065%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 7.0076%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 8.0087%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 9.0097%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 10.0108%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 11.0119%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 12.0130%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 13.0141%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 14.0152%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 15.0162%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 16.0173%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 17.0184%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 18.0195%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 19.0206%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 20.0216%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 21.0227%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 22.0238%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 23.0249%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 24.0260%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 25.0271%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 26.0281%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 27.0292%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 28.0303%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 29.0314%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 30.0325%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 31.0335%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 32.0346%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 33.0357%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 34.0368%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 35.0379%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 36.0390%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 37.0400%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 38.0411%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 39.0422%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 40.0433%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 41.0444%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 42.0455%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 43.0465%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 44.0476%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 45.0487%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 46.0498%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 47.0509%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 48.0519%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 49.0530%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 50.0541%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 51.0552%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 52.0563%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 53.0574%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 54.0584%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 55.0595%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 56.0606%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 57.0617%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 58.0628%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 59.0639%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 60.0649%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 61.0660%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 62.0671%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 63.0682%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 64.0693%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 65.0703%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 66.0714%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 67.0725%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 68.0736%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 69.0747%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 70.0758%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 71.0768%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 72.0779%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 73.0790%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 74.0801%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 75.0812%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 76.0823%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 77.0833%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 78.0844%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 79.0855%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 80.0866%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 81.0877%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 82.0887%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 83.0898%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 84.0909%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 85.0920%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 86.0931%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 87.0942%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 88.0952%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 89.0963%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 90.0974%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 91.0985%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 92.0996%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 93.1006%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 94.1017%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 95.1028%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 96.1039%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 97.1050%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 98.1061%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 99.1071%
|-----> [projecting velocity vector to low dimensional embedding] in progress: 100.0000%
|-----> [projecting velocity vector to low dimensional embedding] completed [0.3961s]
|-----> method arg is None, choosing methods automatically...
|-----------> method kd_tree selected
╭─ SUMMARY: cell_velocities ─────────────────────────────────────────╮
│ Duration: 0.6477s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
╰────────────────────────────────────────────────────────────────────╯
X_umap: (3696, 3) | velocity_umap: (3696, 3)
4. Rotating 3D velocity field (animated)¶
A rotating animation reads the 3D velocity field far better than a single static view. We render the matplotlib cell_wise_vectors_3d once and orbit the camera. With thousands of cells, subsample the arrows (cell_inds) and lengthen them (quiver_3d_kwargs['length']) so they are legible.
quiver_kwargs = {'linewidth': 2.0, 'edgecolors': 'white', 'alpha': 1,
'length': 35, 'arrow_length_ratio': 0.4, 'cmap': None}
axes = dyn.pl.cell_wise_vectors_3d(
adata, basis='umap', color=[celltype_key], plot_method='matplotlib',
cell_inds=200, pointsize=0.04, quiver_3d_kwargs=quiver_kwargs,
elev=20, azim=-60, figsize=(6, 6), save_show_or_return='return',
)
ax = axes[0] if isinstance(axes, (list, tuple)) else axes
fig = ax.get_figure(); fig.set_size_inches(6, 6)
frames = []
for azim in range(-90, 270, 10):
ax.view_init(elev=20, azim=azim)
buf = io.BytesIO(); fig.savefig(buf, format='png', dpi=85); buf.seek(0)
frames.append(imageio.imread(buf))
plt.close(fig)
imageio.mimsave('velocity_3d.gif', frames, fps=12, loop=0)
Image(filename='velocity_3d.gif')
|-----> X shape: (3696, 3) V shape: (3696, 3)
|-----------> plotting with basis key=X_umap
|-----------> skip filtering clusters by stack threshold when stacking color because it is not a numeric type
5. 3D scatter — scatters_interactive¶
A static PyVista screenshot (GitHub), then the interactive Plotly scatter (drag to rotate on nbviewer / readthedocs).
pl = dyn.pl.scatters_interactive(
adata, basis='umap', color=celltype_key, plot_method='pv', save_show_or_return='return'
)
pl = pl[0] if isinstance(pl, (list, tuple)) else pl
pl.window_size = [700, 560]
_png(pl.screenshot(return_img=True), 700, 560)
fig, _ = dyn.pl.scatters_interactive(
adata, basis='umap', color=celltype_key, plot_method='plotly', save_show_or_return='return'
)
fig.update_layout(width=700, height=550)
show_plotly(fig)
|-----------> plotting with basis key=X_umap
|-----------> skip filtering clusters by stack threshold when stacking color because it is not a numeric type
|-----------> plotting with basis key=X_umap
|-----------> skip filtering clusters by stack threshold when stacking color because it is not a numeric type
6. 3D velocity vectors — cell_wise_vectors_3d (static)¶
The matplotlib renderer at two viewing angles; the arrows follow the same direction as the 2D streamlines.
dyn.pl.cell_wise_vectors_3d(
adata, basis='umap', color=[celltype_key], plot_method='matplotlib',
cell_inds=120, pointsize=0.05, quiver_3d_kwargs=quiver_kwargs, elev=25, azim=-60,
)
dyn.pl.cell_wise_vectors_3d(
adata, basis='umap', color=[celltype_key], plot_method='matplotlib',
cell_inds=120, pointsize=0.05, quiver_3d_kwargs=quiver_kwargs, elev=20, azim=40,
)
7. 3D velocity vectors — cell_wise_vectors_3d (interactive)¶
The PyVista backend: static screenshot, then an interactive scene to rotate/zoom on the velocity glyphs.
pl = dyn.pl.cell_wise_vectors_3d(
adata, basis='umap', color=[celltype_key], plot_method='pv', save_show_or_return='return'
)
show_pv_both(pl)
8. 3D vector-field topography — topography_3D¶
Reconstruct a continuous 3D vector field (dyn.vf.VectorField, dims=3) and its fixed points (dyn.vf.topography); static matplotlib, then static + interactive PyVista.
dyn.vf.VectorField(adata, basis='umap', dims=3)
dyn.vf.topography(adata, basis='umap', n=10)
dyn.pl.topography_3D(
adata, basis='umap', color=[celltype_key], plot_method='matplotlib', save_show_or_return='return'
)
|-----> VectorField reconstruction begins...
|-----> Retrieve X and V based on basis: UMAP.
Vector field will be learned in the UMAP space.
|-----> Generating high dimensional grids and convert into a row matrix.
|-----> Learning vector field with method: sparsevfc.
|-----> [SparseVFC] begins...
|-----> Sampling control points based on data velocity magnitude...
|-----> method arg is None, choosing methods automatically...
|-----------> method kd_tree selected
|-----> [SparseVFC] completed [3.4957s]
|-----> [VectorField] completed [3.6084s]
╭─ SUMMARY: VectorField ─────────────────────────────────────────────╮
│ Duration: 3.6113s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
│ ● OBS │ ✚ control_point_umap (bool) │
│ │ ✚ inlier_prob_umap (float) │
│ │ ✚ obs_vf_angle_umap (float) │
│ │
│ ● UNS │ ✚ VecFld_umap │
│ │
│ ● OBSM │ ✚ X_umap_SparseVFC (array, 3696x3) │
│ │ ✚ velocity_umap_SparseVFC (array, 3696x3) │
│ │
╰────────────────────────────────────────────────────────────────────╯
|-----> method arg is None, choosing methods automatically...
|-----------> method kd_tree selected
╭─ SUMMARY: topography ──────────────────────────────────────────────╮
│ Duration: 0.066s │
│ Shape: 3,696 x 27,998 (Unchanged) │
│ │
│ CHANGES DETECTED │
│ ──────────────── │
╰────────────────────────────────────────────────────────────────────╯
|-----------> plotting with basis key=X_umap
|-----------> skip filtering clusters by stack threshold when stacking color because it is not a numeric type
╭─ EXPLANATION: FIXED POINTS ────────────────────────────────────────╮
│ What it measures:
│ Fixed points are steady states of the dynamical system where dx/dt = 0.│
│ Full circles are stable/unstable fixed points; half-circles are saddle points.│
│ │
│ Interpreting values:
│ ● Absorbing / attractors (black, filled): Stable terminal cell │
│ types — all trajectories │
│ converge here (e.g., │
│ melanophore, iridophore, │
│ xanthophore, unknown │
│ terminal states) │
│ ● Emitting / repellers (red, filled): Progenitor/source states — │
│ cells spontaneously │
│ differentiate outward from │
│ these points (e.g., the │
│ multipotent pigment │
│ progenitor hub) │
│ ● Saddles / unstable (blue, half-filled): Bifurcation/decision │
│ points — stable in some │
│ directions, unstable in │
│ others; mark where cell │
│ fates diverge into │
│ different lineages │
│ (e.g., iridophore vs. │
│ melanophore split, │
│ neuron vs. satellite │
│ glia split) │
│ ● Confidence (color intensity): Brighter color = fixed point is │
│ closer to observed cells and │
│ therefore more confident │
│ ● Biological meaning: Together these fixed points map the full │
│ cellular landscape: sources (progenitors), │
│ sinks (terminal states), and the decision │
│ hubs between them │
╰────────────────────────────────────────────────────────────────────╯
<Axes3D: title={'center': 'clusters'}, xlabel='umap_1', ylabel='umap_2', zlabel='umap_3'>
pl = dyn.pl.topography_3D(
adata, basis='umap', color=[celltype_key], plot_method='pv', save_show_or_return='return'
)
show_pv_both(pl)
|-----------> plotting with basis key=X_umap
|-----------> skip filtering clusters by stack threshold when stacking color because it is not a numeric type
╭─ EXPLANATION: FIXED POINTS ────────────────────────────────────────╮
│ What it measures:
│ Fixed points are steady states of the dynamical system where dx/dt = 0.│
│ Full circles are stable/unstable fixed points; half-circles are saddle points.│
│ │
│ Interpreting values:
│ ● Absorbing / attractors (black, filled): Stable terminal cell │
│ types — all trajectories │
│ converge here (e.g., │
│ melanophore, iridophore, │
│ xanthophore, unknown │
│ terminal states) │
│ ● Emitting / repellers (red, filled): Progenitor/source states — │
│ cells spontaneously │
│ differentiate outward from │
│ these points (e.g., the │
│ multipotent pigment │
│ progenitor hub) │
│ ● Saddles / unstable (blue, half-filled): Bifurcation/decision │
│ points — stable in some │
│ directions, unstable in │
│ others; mark where cell │
│ fates diverge into │
│ different lineages │
│ (e.g., iridophore vs. │
│ melanophore split, │
│ neuron vs. satellite │
│ glia split) │
│ ● Confidence (color intensity): Brighter color = fixed point is │
│ closer to observed cells and │
│ therefore more confident │
│ ● Biological meaning: Together these fixed points map the full │
│ cellular landscape: sources (progenitors), │
│ sinks (terminal states), and the decision │
│ hubs between them │
╰────────────────────────────────────────────────────────────────────╯
9. Fate streamtubes and animation¶
Fate streamtubes (plot_3d_streamtube, Plotly) and 3D animation (dyn.mv.PyvistaAnim):
dyn.pl.plot_3d_streamtube(adata, color=celltype_key, layer='X', group=celltype_key,
init_group='Ductal', basis='umap')
dyn.pd.fate(adata, basis='umap', init_cells=adata.obs_names[:50])
dyn.mv.PyvistaAnim(adata, basis='umap', filename='fate_animation.gif').animate()
Summary¶
The 3D velocity arrows follow the same Ductal → endocrine direction as the 2D streamlines.
Each 3D plot is shown as a static image (GitHub) and an interactive Plotly/PyVista scene (nbviewer / readthedocs), plus a rotating GIF of the velocity field.