hub

Vitessce: AnnData

This tutorial demonstrates how to use Vitessce to create interactive visualizations for data stored as LaminDB artifacts. It requires a remote LaminDB instance with cloud storage to enable the Vitessce button (shown below) in the web interface.

It has been adapted from the data preparation examples in the Vitessce documentation.

In this part, we’ll visualize an AnnData object stored in both H5AD and Zarr formats.

# pip install "vitessce[all]>=3.5.0" "generate-tiff-offsets>=0.1.9" lamindb
!lamin connect laminlabs/lamindata # <-- replace with your remote instance
Hide code cell output
 connected lamindb: laminlabs/lamindata
 to map a local dev directory, call: lamin settings set dev-dir .
import vitessce as vit
import lamindb as ln

ln.track()
Hide code cell output
 connected lamindb: laminlabs/lamindata
 found notebook vitessce.ipynb, making new version -- anticipating changes
 created Transform('ZOf7HJEqB4y90006', key='vitessce.ipynb'), started new Run('07QTUYSBxdrOqhFO') at 2026-01-26 16:01:44 UTC
 notebook imports: lamindb==2.0.1 vitessce==3.8.0
 recommendation: to identify the notebook across renames, pass the uid: ln.track("ZOf7HJEqB4y9")

Visualize an AnnData object (H5AD format)

Here we use the Habib et al. 2017 dataset from the COVID-19 Cell Atlas that has been previously subset to highly variable genes. It was ingested into the public laminlabs/lamindata instance in this transform.

h5ad_artifact = ln.Artifact.get(key="vitessce_examples/habib17.h5ad")

When using .h5ad files, we construct a Reference Specification which enables interoperability with the Zarr interface. The Reference Specification JSON was also generated in the transform above.

ref_artifact = ln.Artifact.get(key="vitessce_examples/habib17.reference.json")

Save a VitessceConfig object

You can create a dashboard for one or several datasets by using Vitessce’s component API.

You can pass artifacts to the AnnDataWrapper class using the adata_artifact and ref_artifact parameters.

vc = vit.VitessceConfig(
    schema_version="1.0.18",
    description=h5ad_artifact.description,
)

dataset = vc.add_dataset(name="Habib 2017").add_object(
    vit.AnnDataWrapper(
        adata_artifact=h5ad_artifact,
        ref_artifact=ref_artifact,
        obs_feature_matrix_path="X",
        obs_embedding_paths=["obsm/X_umap"],
        obs_embedding_names=["UMAP"],
        obs_set_paths=["obs/CellType"],
        obs_set_names=["Cell Type"],
    )
)

obs_sets = vc.add_view(vit.ViewType.OBS_SETS, dataset=dataset)
obs_sets_sizes = vc.add_view(vit.ViewType.OBS_SET_SIZES, dataset=dataset)
scatterplot = vc.add_view(vit.ViewType.SCATTERPLOT, dataset=dataset, mapping="UMAP")
heatmap = vc.add_view(vit.ViewType.HEATMAP, dataset=dataset)
genes = vc.add_view(vit.ViewType.FEATURE_LIST, dataset=dataset)
vc.link_views([scatterplot, heatmap], ["featureValueColormapRange"], [[0.0, 0.1]])
vc.layout(((scatterplot | obs_sets) / heatmap) | (obs_sets_sizes / genes))
Hide code cell output
<vitessce.config.VitessceConfig at 0x7f3cea328920>

Save the VitessceConfig object.

h5ad_vc_artifact = ln.integrations.save_vitessce_config(
    vc,
    description="View Habib17 (h5ad) in Vitessce",
)
Hide code cell output
 VitessceConfig references these artifacts:
Artifact(uid='NNUzTpWz3a0PU2aT0000', version_tag=None, is_latest=True, key='vitessce_examples/habib17.h5ad', description='Habib et al., 2017 Nature Methods, h5ad', suffix='.h5ad', kind='dataset', otype='AnnData', size=22586523, hash='nBetKKNFs4mjJ04X_f4uaA', n_files=None, n_observations=None, branch_id=1, space_id=1, storage_id=2, run_id=1932, schema_id=None, created_by_id=40, created_at=2026-01-20 19:52:45 UTC, is_locked=False)
Artifact(uid='cyzNRxkUQF1sMVrr0000', version_tag=None, is_latest=True, key='vitessce_examples/habib17.reference.json', description='Reference JSON for H5AD file, Habib et al., 2017 Nature Methods', suffix='.json', kind=None, otype=None, size=543575, hash='XFOV2X6Bw6_zTugTOEBehg', n_files=None, n_observations=None, branch_id=1, space_id=1, storage_id=2, run_id=1932, schema_id=None, created_by_id=40, created_at=2026-01-20 19:52:54 UTC, is_locked=False)
! returning collection with same hash: Collection(uid='H1AlT19wFq7HdHqZ0000', version_tag=None, is_latest=True, key='View Habib17 (h5ad) in Vitessce', description=None, hash='hmrSAi0jDsrxvo9Oy3Hiqg', reference=None, reference_type=None, meta_artifact=None, branch_id=1, space_id=1, created_by_id=18, run_id=1934, created_at=2026-01-20 20:28:39 UTC, is_locked=False); if you intended to query to track this collection as an input, use: ln.Collection.get()
 returning artifact with same hash: Artifact(uid='JJ58SAXZaCb6Qbna0000', version_tag=None, is_latest=True, key=None, description='View Habib17 (h5ad) in Vitessce', suffix='.vitessce.json', kind='__lamindb_config__', otype=None, size=1295, hash='yZj12VtmR3rBGZSqmM8iFA', n_files=None, n_observations=None, branch_id=1, space_id=1, storage_id=2, run_id=1935, schema_id=None, created_by_id=18, created_at=2026-01-20 20:28:39 UTC, is_locked=False); to track this artifact as an input, use: ln.Artifact.get()
 VitessceConfig: https://lamin.ai/laminlabs/lamindata/artifact/JJ58SAXZaCb6Qbna0000
 Collection: https://lamin.ai/laminlabs/lamindata/collection/H1AlT19wFq7HdHqZ0000

Note

After running save_vitessce_config, a Vitessce button will appear next to the dataset on the Artifacts or Collections page of the web interface.

If your VitessceConfig object references data from multiple artifacts, the Vitessce button will appear next to a Collection that groups these artifacts (on the Collections tab of the Artifacts page).

Note that when using an .h5ad-based artifact, the presence of the corresponding .reference.json file will result in the creation of a Collection.

The Vitessce button for this dataset is available on the Collection page.

Visualize an AnnData object (Zarr format)

AnnData objects can be saved on-disk to not only .h5ad files, but also to Zarr stores using AnnData’s write_zarr method.

Just like in the above section, we use a zarr storage that has been previously written with write_zarr() and subset to highly variable genes and ingested into the vitessce/examples instance.

adata_zarr_artifact = ln.Artifact.get(key="vitessce_examples/habib17.adata.zarr")

Save a VitessceConfig object

You can create a dashboard for one or several datasets by using Vitessce’s component API. Here, we configure the visualization the same way as above in the .h5ad-based example, with the exception of the ref_artifact parameter, as .zarr-based AnnData objects do not require a Reference Specification for Zarr interoperability.

vc = vit.VitessceConfig(
    schema_version="1.0.18",
    description=adata_zarr_artifact.description,
)

dataset = vc.add_dataset(name="Habib 2017").add_object(
    vit.AnnDataWrapper(
        adata_artifact=adata_zarr_artifact,
        obs_feature_matrix_path="X",
        obs_embedding_paths=["obsm/X_umap"],
        obs_embedding_names=["UMAP"],
        obs_set_paths=["obs/CellType"],
        obs_set_names=["Cell Type"],
    )
)

obs_sets = vc.add_view(vit.Component.OBS_SETS, dataset=dataset)
obs_sets_sizes = vc.add_view(vit.Component.OBS_SET_SIZES, dataset=dataset)
scatterplot = vc.add_view(vit.Component.SCATTERPLOT, dataset=dataset, mapping="UMAP")
heatmap = vc.add_view(vit.Component.HEATMAP, dataset=dataset)
genes = vc.add_view(vit.Component.FEATURE_LIST, dataset=dataset)

vc.link_views([scatterplot, heatmap], ["featureValueColormapRange"], [[0.0, 0.1]])
vc.layout(((scatterplot | obs_sets) / heatmap) | (obs_sets_sizes / genes))
Hide code cell output
<vitessce.config.VitessceConfig at 0x7f3d803240b0>

Save the VitessceConfig object.

adata_zarr_vc_artifact = ln.integrations.save_vitessce_config(
    vc,
    description="View Habib17 in Vitessce",
)
Hide code cell output
 VitessceConfig references these artifacts:
Artifact(uid='Ljx9cSOxELkGisVt0000', version_tag=None, is_latest=True, key='vitessce_examples/habib17.adata.zarr', description='Habib et al., 2017 Nature Methods, zarr', suffix='.zarr', kind='dataset', otype='AnnData', size=10601062, hash='YPuOwAd5BZ3pbPoGNBH4aw', n_files=208, n_observations=None, branch_id=1, space_id=1, storage_id=2, run_id=1932, schema_id=None, created_by_id=40, created_at=2026-01-20 19:53:03 UTC, is_locked=False)
 returning artifact with same hash: Artifact(uid='WLkGgCTmG8eWBzng0000', version_tag=None, is_latest=True, key=None, description='View Habib17 in Vitessce', suffix='.vitessce.json', kind='__lamindb_config__', otype=None, size=1204, hash='VBBxpSj1tfUHuVKPJXdgKw', n_files=None, n_observations=None, branch_id=1, space_id=1, storage_id=2, run_id=1936, schema_id=None, created_by_id=18, created_at=2026-01-20 20:28:40 UTC, is_locked=False); to track this artifact as an input, use: ln.Artifact.get()
 VitessceConfig: https://lamin.ai/laminlabs/lamindata/artifact/WLkGgCTmG8eWBzng0000
 Dataset: https://lamin.ai/laminlabs/lamindata/artifact/Ljx9cSOxELkGisVt0000

Note

After running save_vitessce_config, a Vitessce button will appear next to the dataset on the Artifacts or Collections page of the web interface.

If your VitessceConfig object references data from multiple artifacts, the Vitessce button will appear next to a Collection that groups these artifacts (on the Collections tab of the Artifacts page).

Clicking the Vitessce button for this Artifact (.zarr-based) or Collection (.h5ad-based) launches the same interactive viewer, as both formats represent the same dataset here:

Hide code cell content
# compare the generated vitessce config to the public one on vitessce/examples (H5AD)
db = ln.DB("vitessce/examples")
public_vc_json = db.Artifact.get("ffUKrGJGNHL3TDhG0000").load()
h5ad_vc_json = h5ad_vc_artifact.load()

assert public_vc_json["layout"] == h5ad_vc_json["layout"]
assert public_vc_json["coordinationSpace"] == h5ad_vc_json["coordinationSpace"]

# compare the generated vitessce config to the public one on vitessce/examples (Zarr)
public_vc_json = db.Artifact.get("J4tMB6qAeHvsgEsp0000").load()
adata_zarr_vc_json = adata_zarr_vc_artifact.load()

assert public_vc_json["layout"] == adata_zarr_vc_json["layout"]
assert public_vc_json["coordinationSpace"] == adata_zarr_vc_json["coordinationSpace"]
 mapped: Artifact(uid='ffUKrGJGNHL3TDhG0000')
 mapped: Artifact(uid='J4tMB6qAeHvsgEsp0000')
ln.finish()
Hide code cell output
 returning artifact with same hash: Artifact(uid='SacJn4quoltpxJDA0000', version_tag=None, is_latest=True, key=None, description='Report of run pJtnwFvswx1Gosx1', suffix='.html', kind='__lamindb_run__', otype=None, size=303312, hash='kGWP5W2gernxI-uClc3AFA', n_files=None, n_observations=None, branch_id=1, space_id=1, storage_id=2, run_id=2024, schema_id=None, created_by_id=18, created_at=2026-01-23 22:09:42 UTC, is_locked=False); to track this artifact as an input, use: ln.Artifact.get()
! updated description from Report of run pJtnwFvswx1Gosx1 to Report of run 07QTUYSBxdrOqhFO
! returning transform  with same hash & key: Transform(uid='ZOf7HJEqB4y90005', version_tag=None, is_latest=False, key='vitessce.ipynb', description='Vitessce: AnnData', kind='notebook', hash='ado7iapAbP1x33-7RfrfcA', reference=None, reference_type=None, environment=None, branch_id=1, space_id=1, created_by_id=18, created_at=2026-01-23 22:09:35 UTC, is_locked=False)
 new latest version is: Transform(uid='ZOf7HJEqB4y90005', version_tag=None, is_latest=True, key='vitessce.ipynb', description='Vitessce: AnnData', kind='notebook', hash='ado7iapAbP1x33-7RfrfcA', reference=None, reference_type=None, environment=None, branch_id=1, space_id=1, created_by_id=18, created_at=2026-01-23 22:09:35 UTC, is_locked=False)
 finished Run('07QTUYSBxdrOqhFO') after 16s at 2026-01-26 16:02:01 UTC
 go to: https://lamin.ai/laminlabs/lamindata/transform/ZOf7HJEqB4y90005
 to update your notebook from the CLI, run: lamin save /home/runner/work/lamin-spatial/lamin-spatial/docs/vitessce.ipynb