Working with Channel Labels#
This example demonstrates how xarray-ome automatically extracts channel labels from OME-NGFF metadata and uses them as coordinate values.
Loading Data with Channel Labels#
We’ll use a real sample from the Image Data Resource (IDR) that includes channel metadata:
import xarray_ome as xo
# Load IDR sample with channel labels
url = "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.4/idr0062A/6001240.zarr"
print("Loading OME-Zarr from IDR...")
ds = xo.open_ome_dataset(url)
print(f"\nDimensions: {dict(ds.sizes)}")
print(f"Data shape: {ds['image'].shape}")
Loading OME-Zarr from IDR...
Dimensions: {'c': 2, 'z': 236, 'y': 275, 'x': 271}
Data shape: (2, 236, 275, 271)
Channel Coordinates#
Notice how channel coordinates use the labels from metadata instead of numeric indices:
# Channel coordinates use labels from metadata
print("Channel coordinates:", ds.coords['c'].values)
# These labels are also stored in attrs
print("Channel labels (from attrs):", ds.attrs.get('ome_channel_labels'))
Channel coordinates: ['LaminB1' 'Dapi']
Channel labels (from attrs): None
Selecting by Channel Name#
With labeled channels, you can select data using meaningful names:
# Select by channel name
for channel in ds.coords["c"].values:
channel_data = ds.sel(c=channel)
print(f"\n{channel}:")
print(f" Shape: {channel_data['image'].shape}")
print(f" Data type: {channel_data['image'].dtype}")
LaminB1:
Shape: (236, 275, 271)
Data type: uint16
Dapi:
Shape: (236, 275, 271)
Data type: uint16
Physical Coordinates#
The dataset also includes physical coordinates with units:
# Show physical coordinates and units
for coord_name in ["z", "y", "x"]:
coord = ds.coords[coord_name]
unit = ds.attrs['ome_axes_units'][coord_name]
spacing = coord[1].values - coord[0].values if len(coord) > 1 else 0
print(f"\n{coord_name}:")
print(f" Unit: {unit}")
print(f" Range: [{coord.min().values:.2f}, {coord.max().values:.2f}]")
print(f" Spacing: {spacing:.4f}")
z:
Unit: micrometer
Range: [0.00, 117.55]
Spacing: 0.5002
y:
Unit: micrometer
Range: [0.00, 98.75]
Spacing: 0.3604
x:
Unit: micrometer
Range: [0.00, 97.31]
Spacing: 0.3604
Metadata#
All OME-NGFF metadata is preserved in the dataset attributes:
print("Image name:", ds.attrs.get('ome_image_name'))
print("OME-NGFF version:", ds.attrs['ome_ngff_metadata']['version'])
print("Resolution level:", ds.attrs.get('ome_ngff_resolution'))
Image name: None
OME-NGFF version: 0.4
Resolution level: 0
Selecting Data by Channel Name#
You can use the channel labels for intuitive data selection:
# Get just the LaminB1 channel
lamin_data = ds.sel(c='LaminB1')
print(f"LaminB1 shape: {lamin_data['image'].shape}")
# Get just the Dapi channel
dapi_data = ds.sel(c='Dapi')
print(f"Dapi shape: {dapi_data['image'].shape}")
# Get a single z-slice of the Dapi channel
dapi_slice = ds.sel(c='Dapi').isel(z=100)
print(f"Dapi z-slice shape: {dapi_slice['image'].shape}")
LaminB1 shape: (236, 275, 271)
Dapi shape: (236, 275, 271)
Dapi z-slice shape: (275, 271)
Notes#
Channel labels are extracted from
omero.channels[].labelin the OME-NGFF metadataThis field is marked as “transitional” in the spec but is the only standard location for channel labels
Works across all OME-NGFF versions (v0.1-v0.5)
If labels are missing, defaults to
channel_0,channel_1, etc.