Find and load datasets#

This guide walks the whole read path: filter the catalog, search it, find datasets by gene, inspect a store without downloading it, and load it as SpatialData. It runs against the live catalog; the last cell prints which catalog snapshot the outputs came from.

pip install git+https://github.com/theislab/spatialdata-db-client
import sddb

cat = sddb.Catalog()
cat
<Catalog: 1778 datasets>

Catalog() fetches the published catalog.parquet once and caches it. query() and search() return a SpatialDataCohort: an ordered, sliceable list of Dataset records that never touches the zarr stores.

Facets#

The distinct values of a facet column are plain pandas on the catalog table.

df = cat.to_df()
sorted(df["organism"].dropna().unique())
['arabidopsis thaliana', 'glycine max', 'human', 'mouse', 'rat', 'zebrafish']

Any other facet column works the same way (sddb-cli facets lists them from the command line).

A facet keyword takes a scalar (equality) or a list (any of). Rows that failed validation are dropped by default (validation="pass").

scalar = cat.query(organism="human", technology="Visium", tissue="lung")
scalar
<SpatialDataCohort: 37 datasets>
several = cat.query(organism="human", technology=["Visium", "VisiumHD"], tissue="lung")
several.summary()
{'n_objects': 44, 'n_studies': 43, 'technologies': ['Visium', 'VisiumHD']}
several.groupby("technology")
technology n
0 Visium 37
1 VisiumHD 7

Ranges#

Append __gte, __gt, __lte or __lt to a numeric column. Missing values never match.

big = cat.query(organism="human", technology=["Visium", "VisiumHD"], n_obs__gte=50_000)
big.to_df()[["uid", "technology", "tissue", "n_obs"]].head()
uid technology tissue n_obs
0 haOzFbJ7Bc9x7NW60001 VisiumHD ovary 475742
1 2TR7434o4LgFuwCi0000 VisiumHD brain 521175
2 TfXXJl6p6e5ZtUxI0000 VisiumHD tonsil 553820
3 wkdYCDgiAN7RJEZb0000 VisiumHD lung 605471
4 k5Q3YIsLRHtzFqFR0000 VisiumHD lung 448109

Find datasets by gene#

expressing= keeps datasets where a gene (symbol or Ensembl id) is detected. min_fraction sets the minimum fraction of observations in which it is detected; a list of genes means all of them (mode="any" for the union).

Note

The first gene query downloads the cross-dataset gene index (~260 MB) into the cache. Later queries, and later sessions, reuse it.

epcam = cat.query(expressing=["EPCAM"], min_fraction=0.5, technology="Visium", organism="human", tissue="lung")
print(epcam)
cat.genes.ranked("EPCAM").head(3)
<SpatialDataCohort: 4 datasets>
uid fraction_obs_detected total_counts
0 EVTMdgu8thDMETSm0000 1.0 38068.0
1 bOgBgMqQm9TObx470000 0.999516 361511.0
2 TeLy8jHRRvoCrNMn0000 0.99895 276076.0

Pick a small dataset#

The datasets below are among the smallest stores in the catalog (about 10 MB each), so this guide stays fast. Each links to its page on the DB site.

uid

technology

tissue

site page

xVK6T0rajFTgOKci0000

VisiumHD

bone element

visium-hd-bone-element

cgmLrEw3hgv7yhZf0000

Visium

head of femur

visium-spatial-gene-expression-head-of-femur

small = cat.cohort(uids=["xVK6T0rajFTgOKci0000", "cgmLrEw3hgv7yhZf0000"])
small.to_df()[["uid", "technology", "tissue", "organism", "n_obs", "size_bytes"]]
uid technology tissue organism n_obs size_bytes
0 cgmLrEw3hgv7yhZf0000 Visium head of femur human 4992 9919670
1 xVK6T0rajFTgOKci0000 VisiumHD bone element human 13627 9475378

Inspect without downloading#

Dataset.elements() reads only the zarr metadata and returns the shape and dtype of every element.

hd = small.filter(technology="VisiumHD")[0]
print(hd)
for name, info in hd.elements().items():
    print(f"{name:55s} {info['shape']} {info['dtype']}")
<Dataset xVK6T0rajFTgOKci0000 technology=VisiumHD organism=human>
images/GSM9556004_033_post_hires_image                  (3, 1906, 6000) uint8
images/GSM9556004_033_post_lowres_image                 (3, 191, 600) uint8
shapes/GSM9556004_033_post_square_008um                 None None
shapes/GSM9556004_033_post_square_008um_for_vitessce    None None
tables/square_008um                                     (13627, 18085) float32

Load#

A remote store cannot be opened lazily yet, so ds.load() with its default lazy=True raises NotImplementedError. Pass lazy=False to copy the store into the cache and open it.

try:
    hd.load()
except NotImplementedError as err:
    print("NotImplementedError:", str(err).splitlines()[0])
NotImplementedError: Remote lazy open isn't supported upstream (spatialdata). Download first: `SpatialDataCohort.download(dest)` then open the local store, or use `load(lazy=False)` to materialise.
sdata = hd.load(lazy=False)
print("images:", list(sdata.images))
print("tables:", {name: t.shape for name, t in sdata.tables.items()})
images: ['GSM9556004_033_post_hires_image', 'GSM9556004_033_post_lowres_image']
tables: {'square_008um': (13627, 18085)}

Load only some elements#

elements=["kind/name"] copies only what you ask for, which matters when a store holds large images.

sdata_tbl = hd.load(lazy=False, elements=["tables/square_008um"])
print("images:", list(sdata_tbl.images))
print("tables:", {name: t.shape for name, t in sdata_tbl.tables.items()})
images: []
tables: {'square_008um': (13627, 18085)}

sddb.open_sdata does the same from a bare store URL, for when you have a zarr_url but no catalog row.

from sddb import open_sdata

sdata_url = open_sdata(hd.zarr_url, lazy=False, elements=["tables/square_008um"])
list(sdata_url.tables)
['square_008um']

View in the browser#

viewer_url() is a pure string transform of the catalog’s vitessce_url, so it needs no download.

url = hd.viewer_url()
print(url[:60] + "...", f"({len(url)} characters)")
https://vitessce.io#?edit=false&url=data:,%257B%2522version%... (8932 characters)

Dataset.view() opens that link in your default browser, and Dataset.view_interactive() renders it inside a notebook. Both need the viz extra and a desktop session, so they are shown here and not executed:

# pip install "spatialdata-db[viz] @ git+https://github.com/theislab/spatialdata-db-client"
hd.view()              # opens vitessce.io in your browser
hd.view_interactive()  # in-notebook widget
print("Catalog generated at:", cat.generated_at)
Catalog generated at: 2026-10-18