Reading plates#

Behind every profile there are images and segmentations. read_plate() reads one plate of them into a SpatialData object: fields of view as Images, the CellProfiler objects as Labels, the wells as Shapes, and the well- and cell-level measurements as Tables that annotate them.

It reads two layouts and tells them apart by the contents of the directory you point it at:

  • a Cell Painting Gallery source [Weisbart et al., 2024], the images/ and workspace/ trees of an accession;

  • a CellProfiler export, the folder the ExportForSpatialData module writes out of a pipeline run.

This tutorial uses a synthetic plate, so nothing has to be downloaded first.

import matplotlib.pyplot as plt
import numpy as np

import mantispy as mt

sdata = mt.ds.blobs(n_wells=4, n_sites=4)
sdata
SpatialData object
├── Images
│     ├── 'BLOBS01_A01_s1_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A01_s2_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A01_s3_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A01_s4_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A02_s1_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A02_s2_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A02_s3_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A02_s4_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A03_s1_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A03_s2_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A03_s3_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A03_s4_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A04_s1_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A04_s2_image': DataArray[cyx] (5, 64, 64)
│     ├── 'BLOBS01_A04_s3_image': DataArray[cyx] (5, 64, 64)
│     └── 'BLOBS01_A04_s4_image': DataArray[cyx] (5, 64, 64)
├── Labels
│     ├── 'BLOBS01_A01_s1_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s1_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s1_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s2_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s2_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s2_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s3_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s3_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s3_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s4_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s4_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A01_s4_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s1_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s1_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s1_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s2_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s2_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s2_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s3_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s3_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s3_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s4_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s4_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A02_s4_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s1_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s1_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s1_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s2_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s2_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s2_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s3_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s3_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s3_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s4_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s4_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A03_s4_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s1_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s1_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s1_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s2_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s2_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s2_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s3_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s3_cytoplasm': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s3_nuclei': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s4_cells': DataArray[yx] (64, 64)
│     ├── 'BLOBS01_A04_s4_cytoplasm': DataArray[yx] (64, 64)
│     └── 'BLOBS01_A04_s4_nuclei': DataArray[yx] (64, 64)
├── Shapes
│     └── 'BLOBS01_wells': GeoDataFrame shape: (96, 2) (2D shapes)
└── Tables
      ├── 'cells': AnnData (192, 19)
      └── 'wells': AnnData (4, 19)
with coordinate systems:
    ▸ 'BLOBS01', with elements:
        BLOBS01_A01_s1_image (Images), BLOBS01_A01_s2_image (Images), BLOBS01_A01_s3_image (Images), BLOBS01_A01_s4_image (Images), BLOBS01_A02_s1_image (Images), BLOBS01_A02_s2_image (Images), BLOBS01_A02_s3_image (Images), BLOBS01_A02_s4_image (Images), BLOBS01_A03_s1_image (Images), BLOBS01_A03_s2_image (Images), BLOBS01_A03_s3_image (Images), BLOBS01_A03_s4_image (Images), BLOBS01_A04_s1_image (Images), BLOBS01_A04_s2_image (Images), BLOBS01_A04_s3_image (Images), BLOBS01_A04_s4_image (Images), BLOBS01_A01_s1_cells (Labels), BLOBS01_A01_s1_cytoplasm (Labels), BLOBS01_A01_s1_nuclei (Labels), BLOBS01_A01_s2_cells (Labels), BLOBS01_A01_s2_cytoplasm (Labels), BLOBS01_A01_s2_nuclei (Labels), BLOBS01_A01_s3_cells (Labels), BLOBS01_A01_s3_cytoplasm (Labels), BLOBS01_A01_s3_nuclei (Labels), BLOBS01_A01_s4_cells (Labels), BLOBS01_A01_s4_cytoplasm (Labels), BLOBS01_A01_s4_nuclei (Labels), BLOBS01_A02_s1_cells (Labels), BLOBS01_A02_s1_cytoplasm (Labels), BLOBS01_A02_s1_nuclei (Labels), BLOBS01_A02_s2_cells (Labels), BLOBS01_A02_s2_cytoplasm (Labels), BLOBS01_A02_s2_nuclei (Labels), BLOBS01_A02_s3_cells (Labels), BLOBS01_A02_s3_cytoplasm (Labels), BLOBS01_A02_s3_nuclei (Labels), BLOBS01_A02_s4_cells (Labels), BLOBS01_A02_s4_cytoplasm (Labels), BLOBS01_A02_s4_nuclei (Labels), BLOBS01_A03_s1_cells (Labels), BLOBS01_A03_s1_cytoplasm (Labels), BLOBS01_A03_s1_nuclei (Labels), BLOBS01_A03_s2_cells (Labels), BLOBS01_A03_s2_cytoplasm (Labels), BLOBS01_A03_s2_nuclei (Labels), BLOBS01_A03_s3_cells (Labels), BLOBS01_A03_s3_cytoplasm (Labels), BLOBS01_A03_s3_nuclei (Labels), BLOBS01_A03_s4_cells (Labels), BLOBS01_A03_s4_cytoplasm (Labels), BLOBS01_A03_s4_nuclei (Labels), BLOBS01_A04_s1_cells (Labels), BLOBS01_A04_s1_cytoplasm (Labels), BLOBS01_A04_s1_nuclei (Labels), BLOBS01_A04_s2_cells (Labels), BLOBS01_A04_s2_cytoplasm (Labels), BLOBS01_A04_s2_nuclei (Labels), BLOBS01_A04_s3_cells (Labels), BLOBS01_A04_s3_cytoplasm (Labels), BLOBS01_A04_s3_nuclei (Labels), BLOBS01_A04_s4_cells (Labels), BLOBS01_A04_s4_cytoplasm (Labels), BLOBS01_A04_s4_nuclei (Labels), BLOBS01_wells (Shapes)
    ▸ 'BLOBS01_A01', with elements:
        BLOBS01_A01_s1_image (Images), BLOBS01_A01_s2_image (Images), BLOBS01_A01_s3_image (Images), BLOBS01_A01_s4_image (Images), BLOBS01_A01_s1_cells (Labels), BLOBS01_A01_s1_cytoplasm (Labels), BLOBS01_A01_s1_nuclei (Labels), BLOBS01_A01_s2_cells (Labels), BLOBS01_A01_s2_cytoplasm (Labels), BLOBS01_A01_s2_nuclei (Labels), BLOBS01_A01_s3_cells (Labels), BLOBS01_A01_s3_cytoplasm (Labels), BLOBS01_A01_s3_nuclei (Labels), BLOBS01_A01_s4_cells (Labels), BLOBS01_A01_s4_cytoplasm (Labels), BLOBS01_A01_s4_nuclei (Labels)
    ▸ 'BLOBS01_A01_s1', with elements:
        BLOBS01_A01_s1_image (Images), BLOBS01_A01_s1_cells (Labels), BLOBS01_A01_s1_cytoplasm (Labels), BLOBS01_A01_s1_nuclei (Labels)
    ▸ 'BLOBS01_A01_s2', with elements:
        BLOBS01_A01_s2_image (Images), BLOBS01_A01_s2_cells (Labels), BLOBS01_A01_s2_cytoplasm (Labels), BLOBS01_A01_s2_nuclei (Labels)
    ▸ 'BLOBS01_A01_s3', with elements:
        BLOBS01_A01_s3_image (Images), BLOBS01_A01_s3_cells (Labels), BLOBS01_A01_s3_cytoplasm (Labels), BLOBS01_A01_s3_nuclei (Labels)
    ▸ 'BLOBS01_A01_s4', with elements:
        BLOBS01_A01_s4_image (Images), BLOBS01_A01_s4_cells (Labels), BLOBS01_A01_s4_cytoplasm (Labels), BLOBS01_A01_s4_nuclei (Labels)
    ▸ 'BLOBS01_A02', with elements:
        BLOBS01_A02_s1_image (Images), BLOBS01_A02_s2_image (Images), BLOBS01_A02_s3_image (Images), BLOBS01_A02_s4_image (Images), BLOBS01_A02_s1_cells (Labels), BLOBS01_A02_s1_cytoplasm (Labels), BLOBS01_A02_s1_nuclei (Labels), BLOBS01_A02_s2_cells (Labels), BLOBS01_A02_s2_cytoplasm (Labels), BLOBS01_A02_s2_nuclei (Labels), BLOBS01_A02_s3_cells (Labels), BLOBS01_A02_s3_cytoplasm (Labels), BLOBS01_A02_s3_nuclei (Labels), BLOBS01_A02_s4_cells (Labels), BLOBS01_A02_s4_cytoplasm (Labels), BLOBS01_A02_s4_nuclei (Labels)
    ▸ 'BLOBS01_A02_s1', with elements:
        BLOBS01_A02_s1_image (Images), BLOBS01_A02_s1_cells (Labels), BLOBS01_A02_s1_cytoplasm (Labels), BLOBS01_A02_s1_nuclei (Labels)
    ▸ 'BLOBS01_A02_s2', with elements:
        BLOBS01_A02_s2_image (Images), BLOBS01_A02_s2_cells (Labels), BLOBS01_A02_s2_cytoplasm (Labels), BLOBS01_A02_s2_nuclei (Labels)
    ▸ 'BLOBS01_A02_s3', with elements:
        BLOBS01_A02_s3_image (Images), BLOBS01_A02_s3_cells (Labels), BLOBS01_A02_s3_cytoplasm (Labels), BLOBS01_A02_s3_nuclei (Labels)
    ▸ 'BLOBS01_A02_s4', with elements:
        BLOBS01_A02_s4_image (Images), BLOBS01_A02_s4_cells (Labels), BLOBS01_A02_s4_cytoplasm (Labels), BLOBS01_A02_s4_nuclei (Labels)
    ▸ 'BLOBS01_A03', with elements:
        BLOBS01_A03_s1_image (Images), BLOBS01_A03_s2_image (Images), BLOBS01_A03_s3_image (Images), BLOBS01_A03_s4_image (Images), BLOBS01_A03_s1_cells (Labels), BLOBS01_A03_s1_cytoplasm (Labels), BLOBS01_A03_s1_nuclei (Labels), BLOBS01_A03_s2_cells (Labels), BLOBS01_A03_s2_cytoplasm (Labels), BLOBS01_A03_s2_nuclei (Labels), BLOBS01_A03_s3_cells (Labels), BLOBS01_A03_s3_cytoplasm (Labels), BLOBS01_A03_s3_nuclei (Labels), BLOBS01_A03_s4_cells (Labels), BLOBS01_A03_s4_cytoplasm (Labels), BLOBS01_A03_s4_nuclei (Labels)
    ▸ 'BLOBS01_A03_s1', with elements:
        BLOBS01_A03_s1_image (Images), BLOBS01_A03_s1_cells (Labels), BLOBS01_A03_s1_cytoplasm (Labels), BLOBS01_A03_s1_nuclei (Labels)
    ▸ 'BLOBS01_A03_s2', with elements:
        BLOBS01_A03_s2_image (Images), BLOBS01_A03_s2_cells (Labels), BLOBS01_A03_s2_cytoplasm (Labels), BLOBS01_A03_s2_nuclei (Labels)
    ▸ 'BLOBS01_A03_s3', with elements:
        BLOBS01_A03_s3_image (Images), BLOBS01_A03_s3_cells (Labels), BLOBS01_A03_s3_cytoplasm (Labels), BLOBS01_A03_s3_nuclei (Labels)
    ▸ 'BLOBS01_A03_s4', with elements:
        BLOBS01_A03_s4_image (Images), BLOBS01_A03_s4_cells (Labels), BLOBS01_A03_s4_cytoplasm (Labels), BLOBS01_A03_s4_nuclei (Labels)
    ▸ 'BLOBS01_A04', with elements:
        BLOBS01_A04_s1_image (Images), BLOBS01_A04_s2_image (Images), BLOBS01_A04_s3_image (Images), BLOBS01_A04_s4_image (Images), BLOBS01_A04_s1_cells (Labels), BLOBS01_A04_s1_cytoplasm (Labels), BLOBS01_A04_s1_nuclei (Labels), BLOBS01_A04_s2_cells (Labels), BLOBS01_A04_s2_cytoplasm (Labels), BLOBS01_A04_s2_nuclei (Labels), BLOBS01_A04_s3_cells (Labels), BLOBS01_A04_s3_cytoplasm (Labels), BLOBS01_A04_s3_nuclei (Labels), BLOBS01_A04_s4_cells (Labels), BLOBS01_A04_s4_cytoplasm (Labels), BLOBS01_A04_s4_nuclei (Labels)
    ▸ 'BLOBS01_A04_s1', with elements:
        BLOBS01_A04_s1_image (Images), BLOBS01_A04_s1_cells (Labels), BLOBS01_A04_s1_cytoplasm (Labels), BLOBS01_A04_s1_nuclei (Labels)
    ▸ 'BLOBS01_A04_s2', with elements:
        BLOBS01_A04_s2_image (Images), BLOBS01_A04_s2_cells (Labels), BLOBS01_A04_s2_cytoplasm (Labels), BLOBS01_A04_s2_nuclei (Labels)
    ▸ 'BLOBS01_A04_s3', with elements:
        BLOBS01_A04_s3_image (Images), BLOBS01_A04_s3_cells (Labels), BLOBS01_A04_s3_cytoplasm (Labels), BLOBS01_A04_s3_nuclei (Labels)
    ▸ 'BLOBS01_A04_s4', with elements:
        BLOBS01_A04_s4_image (Images), BLOBS01_A04_s4_cells (Labels), BLOBS01_A04_s4_cytoplasm (Labels), BLOBS01_A04_s4_nuclei (Labels)

Coordinate systems#

Every element sits in three coordinate systems: its own field, its well, and the plate. This lays the fields of a well out as a mosaic and the wells as a plate map, with nothing resampled.

sorted(sdata.coordinate_systems)[:6]
['BLOBS01',
 'BLOBS01_A01',
 'BLOBS01_A01_s1',
 'BLOBS01_A01_s2',
 'BLOBS01_A01_s3',
 'BLOBS01_A01_s4']

Rendering a well in its own frame puts its four fields where the microscope stage found them:

from spatialdata.transformations import get_transformation

fig, ax = plt.subplots(figsize=(4, 4))
for name, image in sdata.images.items():
    if "_A01_" not in name:
        continue
    offset = get_transformation(image, "BLOBS01_A01").to_affine_matrix(input_axes=("y", "x"), output_axes=("y", "x"))
    y, x = offset[0, 2], offset[1, 2]
    ax.imshow(np.asarray(image.sel(c="DNA")), extent=(x, x + 64, y + 64, y), cmap="gray")
ax.set(xlim=(0, 128), ylim=(128, 0), title="well A01, four fields")
plt.show()
../_images/981e1e40f6715db2ca097353bcadf3ef6fade0d312ee21949b1c898089d118bb.png

Images and labels#

The image of a field carries one channel per stain, named. The labels carry CellProfiler object numbers, so the rows of the cell table join straight onto them.

image = sdata["BLOBS01_A01_s1_image"]
list(image.coords["c"].values)
[np.str_('DNA'),
 np.str_('RNA'),
 np.str_('AGP'),
 np.str_('ER'),
 np.str_('Mito')]
fig, axes = plt.subplots(1, 4, figsize=(12, 3))
axes[0].imshow(np.asarray(image.sel(c="DNA")), cmap="gray")
axes[0].set_title("DNA")
for ax, name in zip(axes[1:], ("cells", "nuclei", "cytoplasm"), strict=True):
    ax.imshow(np.asarray(sdata[f"BLOBS01_A01_s1_{name}"]), cmap="tab20")
    ax.set_title(name)
for ax in axes:
    ax.set_axis_off()
plt.show()
../_images/ccf42e6b3e0d5126e5baa00535480d825810ddd6fc2cbf997c814a353badbe1d.png

Cytoplasm is the cell mask minus the nucleus mask, as CellProfiler defines it.

The tables#

cells holds one row per segmented object and wells one row per well. Both are ordinary AnnData objects. Their var is annotated with what each feature name encodes, as read_profiles() annotates a profile read from disk.

cells = sdata.tables["cells"]
cells
AnnData object with n_obs × n_vars = 192 × 19
    obs: 'Metadata_Plate', 'Metadata_Well', 'Metadata_Site', 'Metadata_ObjectNumber', 'region'
    var: 'object', 'feature_group', 'feature', 'channel', 'scale', 'angle', 'gray_levels', 'radial_bin', 'params', 'is_feature'
    uns: 'mantispy', 'spatialdata_attrs'
    layers: None (.X)
cells.var
object feature_group feature channel scale angle gray_levels radial_bin params is_feature
Cells_AreaShape_Area Cells AreaShape Area NaN NaN NaN NaN NaN NaN True
Cells_Intensity_MeanIntensity_DNA Cells Intensity MeanIntensity DNA NaN NaN NaN NaN NaN True
Cells_Intensity_MeanIntensity_RNA Cells Intensity MeanIntensity RNA NaN NaN NaN NaN NaN True
Cells_Intensity_MeanIntensity_AGP Cells Intensity MeanIntensity AGP NaN NaN NaN NaN NaN True
Cells_Intensity_MeanIntensity_ER Cells Intensity MeanIntensity ER NaN NaN NaN NaN NaN True
Cells_Intensity_MeanIntensity_Mito Cells Intensity MeanIntensity Mito NaN NaN NaN NaN NaN True
Nuclei_AreaShape_Area Nuclei AreaShape Area NaN NaN NaN NaN NaN NaN True
Nuclei_Intensity_MeanIntensity_DNA Nuclei Intensity MeanIntensity DNA NaN NaN NaN NaN NaN True
Nuclei_Intensity_MeanIntensity_RNA Nuclei Intensity MeanIntensity RNA NaN NaN NaN NaN NaN True
Nuclei_Intensity_MeanIntensity_AGP Nuclei Intensity MeanIntensity AGP NaN NaN NaN NaN NaN True
Nuclei_Intensity_MeanIntensity_ER Nuclei Intensity MeanIntensity ER NaN NaN NaN NaN NaN True
Nuclei_Intensity_MeanIntensity_Mito Nuclei Intensity MeanIntensity Mito NaN NaN NaN NaN NaN True
Cytoplasm_AreaShape_Area Cytoplasm AreaShape Area NaN NaN NaN NaN NaN NaN True
Cytoplasm_Intensity_MeanIntensity_DNA Cytoplasm Intensity MeanIntensity DNA NaN NaN NaN NaN NaN True
Cytoplasm_Intensity_MeanIntensity_RNA Cytoplasm Intensity MeanIntensity RNA NaN NaN NaN NaN NaN True
Cytoplasm_Intensity_MeanIntensity_AGP Cytoplasm Intensity MeanIntensity AGP NaN NaN NaN NaN NaN True
Cytoplasm_Intensity_MeanIntensity_ER Cytoplasm Intensity MeanIntensity ER NaN NaN NaN NaN NaN True
Cytoplasm_Intensity_MeanIntensity_Mito Cytoplasm Intensity MeanIntensity Mito NaN NaN NaN NaN NaN True
Cells_Correlation_Correlation_DNA_RNA Cells Correlation Correlation DNA|RNA NaN NaN NaN NaN NaN True

region names the Labels element each row annotates, and Metadata_ObjectNumber the label value inside it:

cells.obs.head()
Metadata_Plate Metadata_Well Metadata_Site Metadata_ObjectNumber region
BLOBS01_A01_s1_cells:1 BLOBS01 A01 1 1 BLOBS01_A01_s1_cells
BLOBS01_A01_s1_cells:2 BLOBS01 A01 1 2 BLOBS01_A01_s1_cells
BLOBS01_A01_s1_cells:3 BLOBS01 A01 1 3 BLOBS01_A01_s1_cells
BLOBS01_A01_s1_cells:4 BLOBS01 A01 1 4 BLOBS01_A01_s1_cells
BLOBS01_A01_s1_cells:5 BLOBS01 A01 1 5 BLOBS01_A01_s1_cells

Reading a real plate#

A gallery source needs the accession directory, the batch and the plate barcode:

sdata = mt.io.read_plate(
    "cpg0000-jump-pilot/source_4",
    "BR00116991",
    batch="2020_11_04_CPJUMP1",
    wells=["A01"],
)

wells defaults to every well whose images are present, so a partial download reads back as itself. The gallery publishes one-pixel object outlines rather than segmentation masks, so the Labels are reconstructed from them. A component is accepted only when exactly one object centroid falls in it and its area is close to the area CellProfiler measured. Rows whose object was not reconstructed are dropped. Every label therefore stands for one object.

Where a source recorded no stage coordinates, or no pixel size to convert them with, each field sits in its own frame. read_plate() then keeps that layout instead of inventing one, and leaves out the well shapes and the plate frame they would have lived in.

A plate straight out of a pipeline run needs only its folder:

sdata = mt.io.read_plate("run_export/Plate1")

Nothing is reconstructed on that path. The ExportForSpatialData module writes real label arrays, a per-cell table already joined across compartments, and a manifest in the table’s uns listing what it wrote. The reader builds only what the manifest names, so a folder that was moved still reads. Arrays a failed cycle never wrote are skipped, together with the rows that annotate them.

Two plates#

Element names carry the plate barcode, so two plates concatenate without renaming:

import spatialdata as sd

other = mt.ds.blobs(n_wells=4, n_sites=4, plate="BLOBS02", seed=1)
merged = sd.concatenate([sdata, other], concatenate_tables=True)
merged.tables["wells"].obs.groupby("Metadata_Plate", observed=True).size()
Metadata_Plate
BLOBS01    4
BLOBS02    4
dtype: int64