ngio 0.1.6__py3-none-any.whl → 0.2.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ngio/__init__.py +31 -5
- ngio/common/__init__.py +44 -0
- ngio/common/_array_pipe.py +160 -0
- ngio/common/_axes_transforms.py +63 -0
- ngio/common/_common_types.py +5 -0
- ngio/common/_dimensions.py +113 -0
- ngio/common/_pyramid.py +222 -0
- ngio/{core/roi.py → common/_roi.py} +22 -23
- ngio/common/_slicer.py +97 -0
- ngio/{pipes/_zoom_utils.py → common/_zoom.py} +2 -78
- ngio/hcs/__init__.py +60 -0
- ngio/images/__init__.py +23 -0
- ngio/images/abstract_image.py +240 -0
- ngio/images/create.py +251 -0
- ngio/images/image.py +383 -0
- ngio/images/label.py +96 -0
- ngio/images/omezarr_container.py +512 -0
- ngio/ome_zarr_meta/__init__.py +35 -0
- ngio/ome_zarr_meta/_generic_handlers.py +320 -0
- ngio/ome_zarr_meta/_meta_handlers.py +142 -0
- ngio/ome_zarr_meta/ngio_specs/__init__.py +63 -0
- ngio/ome_zarr_meta/ngio_specs/_axes.py +481 -0
- ngio/ome_zarr_meta/ngio_specs/_channels.py +378 -0
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +134 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +5 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +434 -0
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +84 -0
- ngio/ome_zarr_meta/v04/__init__.py +11 -0
- ngio/ome_zarr_meta/v04/_meta_handlers.py +54 -0
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +412 -0
- ngio/tables/__init__.py +21 -5
- ngio/tables/_validators.py +192 -0
- ngio/tables/backends/__init__.py +8 -0
- ngio/tables/backends/_abstract_backend.py +71 -0
- ngio/tables/backends/_anndata_utils.py +194 -0
- ngio/tables/backends/_anndata_v1.py +75 -0
- ngio/tables/backends/_json_v1.py +56 -0
- ngio/tables/backends/_table_backends.py +102 -0
- ngio/tables/tables_container.py +300 -0
- ngio/tables/v1/__init__.py +6 -5
- ngio/tables/v1/_feature_table.py +161 -0
- ngio/tables/v1/_generic_table.py +99 -182
- ngio/tables/v1/_masking_roi_table.py +175 -0
- ngio/tables/v1/_roi_table.py +226 -0
- ngio/utils/__init__.py +23 -10
- ngio/utils/_datasets.py +51 -0
- ngio/utils/_errors.py +10 -4
- ngio/utils/_zarr_utils.py +378 -0
- {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/METADATA +18 -39
- ngio-0.2.0a1.dist-info/RECORD +53 -0
- ngio/core/__init__.py +0 -7
- ngio/core/dimensions.py +0 -122
- ngio/core/image_handler.py +0 -228
- ngio/core/image_like_handler.py +0 -549
- ngio/core/label_handler.py +0 -410
- ngio/core/ngff_image.py +0 -387
- ngio/core/utils.py +0 -287
- ngio/io/__init__.py +0 -19
- ngio/io/_zarr.py +0 -88
- ngio/io/_zarr_array_utils.py +0 -0
- ngio/io/_zarr_group_utils.py +0 -60
- ngio/iterators/__init__.py +0 -1
- ngio/ngff_meta/__init__.py +0 -27
- ngio/ngff_meta/fractal_image_meta.py +0 -1267
- ngio/ngff_meta/meta_handler.py +0 -92
- ngio/ngff_meta/utils.py +0 -235
- ngio/ngff_meta/v04/__init__.py +0 -6
- ngio/ngff_meta/v04/specs.py +0 -158
- ngio/ngff_meta/v04/zarr_utils.py +0 -376
- ngio/pipes/__init__.py +0 -7
- ngio/pipes/_slicer_transforms.py +0 -176
- ngio/pipes/_transforms.py +0 -33
- ngio/pipes/data_pipe.py +0 -52
- ngio/tables/_ad_reader.py +0 -80
- ngio/tables/_utils.py +0 -301
- ngio/tables/tables_group.py +0 -252
- ngio/tables/v1/feature_tables.py +0 -182
- ngio/tables/v1/masking_roi_tables.py +0 -243
- ngio/tables/v1/roi_tables.py +0 -285
- ngio/utils/_common_types.py +0 -5
- ngio/utils/_pydantic_utils.py +0 -52
- ngio-0.1.6.dist-info/RECORD +0 -44
- {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/WHEEL +0 -0
- {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/licenses/LICENSE +0 -0
ngio/ngff_meta/meta_handler.py
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"""Handler for reading and writing NGFF image metadata."""
|
|
2
|
-
|
|
3
|
-
from typing import Literal, Protocol
|
|
4
|
-
|
|
5
|
-
from ngio.io import AccessModeLiteral, Group, StoreOrGroup
|
|
6
|
-
from ngio.ngff_meta.fractal_image_meta import ImageLabelMeta
|
|
7
|
-
from ngio.ngff_meta.v04.zarr_utils import (
|
|
8
|
-
NgffImageMetaZarrHandlerV04,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class NgffImageMetaHandler(Protocol):
|
|
13
|
-
"""Handler for NGFF image metadata."""
|
|
14
|
-
|
|
15
|
-
def __init__(
|
|
16
|
-
self,
|
|
17
|
-
store: StoreOrGroup,
|
|
18
|
-
meta_mode: Literal["image", "label"],
|
|
19
|
-
cache: bool = False,
|
|
20
|
-
mode: AccessModeLiteral = "a",
|
|
21
|
-
):
|
|
22
|
-
"""Initialize the handler."""
|
|
23
|
-
...
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def group(self) -> Group:
|
|
27
|
-
"""Return the Zarr group."""
|
|
28
|
-
...
|
|
29
|
-
|
|
30
|
-
@property
|
|
31
|
-
def store(self) -> StoreOrGroup:
|
|
32
|
-
"""Return the Zarr store."""
|
|
33
|
-
...
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def zarr_version(self) -> int:
|
|
37
|
-
"""Return the Zarr version."""
|
|
38
|
-
...
|
|
39
|
-
|
|
40
|
-
@staticmethod
|
|
41
|
-
def check_version(store: StoreOrGroup) -> bool:
|
|
42
|
-
"""Check if the version of the metadata is supported."""
|
|
43
|
-
...
|
|
44
|
-
|
|
45
|
-
def load_meta(self) -> ImageLabelMeta:
|
|
46
|
-
"""Load the OME-NGFF 0.4 metadata."""
|
|
47
|
-
...
|
|
48
|
-
|
|
49
|
-
def write_meta(self, meta: ImageLabelMeta) -> None:
|
|
50
|
-
"""Write the OME-NGFF 0.4 metadata."""
|
|
51
|
-
...
|
|
52
|
-
|
|
53
|
-
def update_cache(self, meta: ImageLabelMeta) -> None:
|
|
54
|
-
"""Update the cached metadata."""
|
|
55
|
-
...
|
|
56
|
-
|
|
57
|
-
def clear_cache(self) -> None:
|
|
58
|
-
"""Clear the cached metadata."""
|
|
59
|
-
...
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
_available_load_ngff_image_meta_handlers = {
|
|
63
|
-
"0.4": NgffImageMetaZarrHandlerV04,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def find_ngff_image_meta_handler_version(store: StoreOrGroup) -> str:
|
|
68
|
-
"""Find the version of the NGFF image metadata."""
|
|
69
|
-
for version, handler in _available_load_ngff_image_meta_handlers.items():
|
|
70
|
-
if handler.check_version(store=store):
|
|
71
|
-
return version
|
|
72
|
-
|
|
73
|
-
supported_versions = ", ".join(_available_load_ngff_image_meta_handlers.keys())
|
|
74
|
-
raise ValueError(
|
|
75
|
-
f"The Zarr store does not contain a supported version. \
|
|
76
|
-
Supported OME-Ngff versions are: {supported_versions}."
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def get_ngff_image_meta_handler(
|
|
81
|
-
store: StoreOrGroup,
|
|
82
|
-
meta_mode: Literal["image", "label"],
|
|
83
|
-
version: str | None = None,
|
|
84
|
-
cache: bool = False,
|
|
85
|
-
mode: AccessModeLiteral = "a",
|
|
86
|
-
) -> NgffImageMetaHandler:
|
|
87
|
-
"""Load the NGFF image metadata handler."""
|
|
88
|
-
if version is None:
|
|
89
|
-
version = find_ngff_image_meta_handler_version(store)
|
|
90
|
-
|
|
91
|
-
handler = _available_load_ngff_image_meta_handlers[version]
|
|
92
|
-
return handler(store=store, meta_mode=meta_mode, cache=cache, mode=mode)
|
ngio/ngff_meta/utils.py
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
"""Utility functions for creating and modifying metadata."""
|
|
2
|
-
|
|
3
|
-
from collections.abc import Collection
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
from ngio.ngff_meta.fractal_image_meta import (
|
|
7
|
-
Axis,
|
|
8
|
-
Channel,
|
|
9
|
-
ChannelNames,
|
|
10
|
-
ChannelVisualisation,
|
|
11
|
-
Dataset,
|
|
12
|
-
ImageMeta,
|
|
13
|
-
LabelMeta,
|
|
14
|
-
Omero,
|
|
15
|
-
PixelSize,
|
|
16
|
-
SpaceNames,
|
|
17
|
-
SpaceUnits,
|
|
18
|
-
TimeNames,
|
|
19
|
-
TimeUnits,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _create_multiscale_meta(
|
|
24
|
-
on_disk_axis: Collection[str] = ("t", "c", "z", "y", "x"),
|
|
25
|
-
pixel_sizes: PixelSize | None = None,
|
|
26
|
-
xy_scaling_factor: float = 2.0,
|
|
27
|
-
z_scaling_factor: float = 1.0,
|
|
28
|
-
pixel_units: SpaceUnits | str = SpaceUnits.micrometer,
|
|
29
|
-
time_spacing: float = 1.0,
|
|
30
|
-
time_units: TimeUnits | str | None = None,
|
|
31
|
-
levels: int | list[str] = 5,
|
|
32
|
-
) -> list[Dataset]:
|
|
33
|
-
"""Create a image metadata object from scratch."""
|
|
34
|
-
allowed_axes_names = (
|
|
35
|
-
SpaceNames.allowed_names()
|
|
36
|
-
+ TimeNames.allowed_names()
|
|
37
|
-
+ ChannelNames.allowed_names()
|
|
38
|
-
)
|
|
39
|
-
for ax in on_disk_axis:
|
|
40
|
-
if ax not in allowed_axes_names:
|
|
41
|
-
raise ValueError(
|
|
42
|
-
f"Invalid axis name: {ax}, allowed names: {allowed_axes_names}"
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
if isinstance(pixel_units, str):
|
|
46
|
-
pixel_units = SpaceUnits(pixel_units)
|
|
47
|
-
|
|
48
|
-
if pixel_sizes is None:
|
|
49
|
-
pixel_sizes = PixelSize(z=1.0, y=1.0, x=1.0, unit=pixel_units)
|
|
50
|
-
|
|
51
|
-
pixel_sizes_dict = pixel_sizes.as_dict()
|
|
52
|
-
pixel_sizes_dict["t"] = time_spacing
|
|
53
|
-
|
|
54
|
-
scaling_factor_dict = {
|
|
55
|
-
"z": z_scaling_factor,
|
|
56
|
-
"y": xy_scaling_factor,
|
|
57
|
-
"x": xy_scaling_factor,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if time_units is None:
|
|
61
|
-
time_units = TimeUnits.s
|
|
62
|
-
|
|
63
|
-
if isinstance(time_units, str):
|
|
64
|
-
time_units = TimeUnits(time_units)
|
|
65
|
-
|
|
66
|
-
axes = Axis.batch_create(on_disk_axis, time_unit=time_units, space_unit=pixel_units)
|
|
67
|
-
datasets = []
|
|
68
|
-
|
|
69
|
-
if isinstance(levels, int):
|
|
70
|
-
paths = [str(i) for i in range(levels)]
|
|
71
|
-
elif isinstance(levels, list):
|
|
72
|
-
if not all(isinstance(level, str) for level in levels):
|
|
73
|
-
raise ValueError(f"All levels must be strings. Got: {levels}")
|
|
74
|
-
paths = levels
|
|
75
|
-
|
|
76
|
-
for level, path in enumerate(paths):
|
|
77
|
-
scale = [
|
|
78
|
-
pixel_sizes_dict.get(ax, 1.0) * scaling_factor_dict.get(ax, 1.0) ** level
|
|
79
|
-
for ax in on_disk_axis
|
|
80
|
-
]
|
|
81
|
-
|
|
82
|
-
datasets.append(
|
|
83
|
-
Dataset(
|
|
84
|
-
path=path,
|
|
85
|
-
on_disk_axes=axes,
|
|
86
|
-
on_disk_scale=scale,
|
|
87
|
-
on_disk_translation=None,
|
|
88
|
-
)
|
|
89
|
-
)
|
|
90
|
-
return datasets
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def create_image_metadata(
|
|
94
|
-
on_disk_axis: Collection[str] = ("t", "c", "z", "y", "x"),
|
|
95
|
-
pixel_sizes: PixelSize | None = None,
|
|
96
|
-
xy_scaling_factor: float = 2.0,
|
|
97
|
-
z_scaling_factor: float = 1.0,
|
|
98
|
-
time_spacing: float = 1.0,
|
|
99
|
-
time_units: TimeUnits | str = TimeUnits.s,
|
|
100
|
-
levels: int | list[str] = 5,
|
|
101
|
-
name: str | None = None,
|
|
102
|
-
channel_labels: list[str] | None = None,
|
|
103
|
-
channel_wavelengths: list[str] | None = None,
|
|
104
|
-
channel_visualization: list[ChannelVisualisation] | None = None,
|
|
105
|
-
omero_kwargs: dict[str, Any] | None = None,
|
|
106
|
-
version: str = "0.4",
|
|
107
|
-
) -> ImageMeta:
|
|
108
|
-
"""Create a image metadata object from scratch.
|
|
109
|
-
|
|
110
|
-
Args:
|
|
111
|
-
on_disk_axis: The names of the axes. The order will correspond to the
|
|
112
|
-
on-disk order. Axes order should follow the canonical order
|
|
113
|
-
(t, c, z, y, x). Note that a different order can still be used
|
|
114
|
-
to store the data on disk if NGFF version used is supports it.
|
|
115
|
-
pixel_sizes: The pixel sizes for the z, y, x axes.
|
|
116
|
-
xy_scaling_factor: The scaling factor for the y and x axes, to be used
|
|
117
|
-
for the pyramid building.
|
|
118
|
-
z_scaling_factor: The scaling factor for the z axis, to be used for the
|
|
119
|
-
pyramid building. Note that several tools may not support scaling
|
|
120
|
-
different than 1.0 for the z axis.
|
|
121
|
-
time_spacing: The time spacing (If the time axis is present).
|
|
122
|
-
time_units: The units of the time spacing (If the time axis is present).
|
|
123
|
-
levels: The number of levels in the pyramid or the list of paths.
|
|
124
|
-
name: The name of the metadata.
|
|
125
|
-
channel_labels: The names of the channels.
|
|
126
|
-
channel_wavelengths: The wavelengths of the channels.
|
|
127
|
-
channel_visualization: The visualization of the channels.
|
|
128
|
-
omero_kwargs: The additional omero kwargs.
|
|
129
|
-
version: The version of NGFF metadata.
|
|
130
|
-
|
|
131
|
-
"""
|
|
132
|
-
datasets = _create_multiscale_meta(
|
|
133
|
-
on_disk_axis=on_disk_axis,
|
|
134
|
-
pixel_sizes=pixel_sizes,
|
|
135
|
-
xy_scaling_factor=xy_scaling_factor,
|
|
136
|
-
z_scaling_factor=z_scaling_factor,
|
|
137
|
-
time_spacing=time_spacing,
|
|
138
|
-
time_units=time_units,
|
|
139
|
-
levels=levels,
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
if channel_labels is None:
|
|
143
|
-
return ImageMeta(
|
|
144
|
-
version=version,
|
|
145
|
-
name=name,
|
|
146
|
-
datasets=datasets,
|
|
147
|
-
omero=None,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
if channel_wavelengths is None:
|
|
151
|
-
channel_wavelengths = channel_labels
|
|
152
|
-
else:
|
|
153
|
-
if len(channel_wavelengths) != len(channel_labels):
|
|
154
|
-
raise ValueError(
|
|
155
|
-
"The number of channel wavelengths must match the number of "
|
|
156
|
-
"channel labels."
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
if channel_visualization is None:
|
|
160
|
-
channel_visualization = [
|
|
161
|
-
ChannelVisualisation(color=label) for label in channel_labels
|
|
162
|
-
]
|
|
163
|
-
else:
|
|
164
|
-
if len(channel_visualization) != len(channel_labels):
|
|
165
|
-
raise ValueError(
|
|
166
|
-
"The number of channel kwargs must match the number of channel labels."
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
channels = []
|
|
170
|
-
for label, wavelengths, ch_visualization in zip(
|
|
171
|
-
channel_labels, channel_wavelengths, channel_visualization, strict=True
|
|
172
|
-
):
|
|
173
|
-
channels.append(
|
|
174
|
-
Channel(
|
|
175
|
-
label=label,
|
|
176
|
-
wavelength_id=wavelengths,
|
|
177
|
-
channel_visualisation=ch_visualization,
|
|
178
|
-
)
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
omero_kwargs = {} if omero_kwargs is None else omero_kwargs
|
|
182
|
-
omero = Omero(channels=channels, **omero_kwargs)
|
|
183
|
-
|
|
184
|
-
return ImageMeta(
|
|
185
|
-
version=version,
|
|
186
|
-
name=name,
|
|
187
|
-
datasets=datasets,
|
|
188
|
-
omero=omero,
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def create_label_metadata(
|
|
193
|
-
on_disk_axis: Collection[str] = ("t", "c", "z", "y", "x"),
|
|
194
|
-
pixel_sizes: PixelSize | None = None,
|
|
195
|
-
xy_scaling_factor: float = 2.0,
|
|
196
|
-
z_scaling_factor: float = 1.0,
|
|
197
|
-
time_spacing: float = 1.0,
|
|
198
|
-
time_units: TimeUnits | str | None = None,
|
|
199
|
-
levels: int | list[str] = 5,
|
|
200
|
-
name: str | None = None,
|
|
201
|
-
version: str = "0.4",
|
|
202
|
-
) -> LabelMeta:
|
|
203
|
-
"""Create a label metadata object from scratch.
|
|
204
|
-
|
|
205
|
-
Args:
|
|
206
|
-
on_disk_axis: The names of the axes. The order will correspond to the
|
|
207
|
-
on-disk order. Axes order should follow the canonical order
|
|
208
|
-
(t, c, z, y, x). Note that a different order can still be used
|
|
209
|
-
to store the data on disk if NGFF version used is supports it.
|
|
210
|
-
pixel_sizes: The pixel sizes for the z, y, x axes.
|
|
211
|
-
xy_scaling_factor: The scaling factor for the y and x axes, to be used
|
|
212
|
-
for the pyramid building.
|
|
213
|
-
z_scaling_factor: The scaling factor for the z axis, to be used for the
|
|
214
|
-
pyramid building. Note that several tools may not support scaling
|
|
215
|
-
different than 1.0 for the z axis.
|
|
216
|
-
time_spacing: The time spacing (If the time axis is present).
|
|
217
|
-
time_units: The units of the time spacing (If the time axis is present).
|
|
218
|
-
levels: The number of levels in the pyramid or the list of paths.
|
|
219
|
-
name: The name of the metadata.
|
|
220
|
-
version: The version of NGFF metadata.
|
|
221
|
-
"""
|
|
222
|
-
datasets = _create_multiscale_meta(
|
|
223
|
-
on_disk_axis=on_disk_axis,
|
|
224
|
-
pixel_sizes=pixel_sizes,
|
|
225
|
-
xy_scaling_factor=xy_scaling_factor,
|
|
226
|
-
z_scaling_factor=z_scaling_factor,
|
|
227
|
-
time_spacing=time_spacing,
|
|
228
|
-
time_units=time_units,
|
|
229
|
-
levels=levels,
|
|
230
|
-
)
|
|
231
|
-
return LabelMeta(
|
|
232
|
-
version=version,
|
|
233
|
-
name=name,
|
|
234
|
-
datasets=datasets,
|
|
235
|
-
)
|
ngio/ngff_meta/v04/__init__.py
DELETED
ngio/ngff_meta/v04/specs.py
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
"""Implementations of the OME-NGFF 0.4 specs using Pydantic models.
|
|
2
|
-
|
|
3
|
-
See https://ngff.openmicroscopy.org/0.4/ for detailed specs.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from typing import Literal
|
|
7
|
-
|
|
8
|
-
from pydantic import BaseModel, Field, field_validator
|
|
9
|
-
|
|
10
|
-
from ngio.utils._pydantic_utils import (
|
|
11
|
-
SKIP_NGFF_VALIDATION,
|
|
12
|
-
BaseWithExtraFields,
|
|
13
|
-
unique_items_validator,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Window04(BaseModel):
|
|
18
|
-
"""Model for `Channels.Window`."""
|
|
19
|
-
|
|
20
|
-
max: int | float
|
|
21
|
-
min: int | float
|
|
22
|
-
start: int | float
|
|
23
|
-
end: int | float
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class Channel04(BaseWithExtraFields):
|
|
27
|
-
"""Model for `Omero.channels`."""
|
|
28
|
-
|
|
29
|
-
label: str
|
|
30
|
-
color: str
|
|
31
|
-
active: bool = True
|
|
32
|
-
window: Window04 | None = None
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class Omero04(BaseWithExtraFields):
|
|
36
|
-
"""Model for `NgffImageMeta.Omero`."""
|
|
37
|
-
|
|
38
|
-
channels: list[Channel04]
|
|
39
|
-
version: Literal["0.4"] = "0.4"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class Axis04(BaseModel):
|
|
43
|
-
"""Model for `Multiscale.axes` elements."""
|
|
44
|
-
|
|
45
|
-
name: str
|
|
46
|
-
type: str
|
|
47
|
-
unit: str | None = None
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
class ScaleCoordinateTransformation04(BaseModel):
|
|
51
|
-
"""Model for a scale transformation.
|
|
52
|
-
|
|
53
|
-
This corresponds to scale-type elements of
|
|
54
|
-
`Dataset.coordinateTransformations` or
|
|
55
|
-
`Multiscale.coordinateTransformations`.
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
type: Literal["scale"]
|
|
59
|
-
scale: list[float] = Field(..., min_length=2)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class TranslationCoordinateTransformation04(BaseModel):
|
|
63
|
-
"""Model for a translation transformation.
|
|
64
|
-
|
|
65
|
-
This corresponds to translation-type elements of
|
|
66
|
-
`Dataset.coordinateTransformations` or
|
|
67
|
-
`Multiscale.coordinateTransformations`.
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
type: Literal["translation"]
|
|
71
|
-
translation: list[float] = Field(..., min_length=2)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Transformation04 = (
|
|
75
|
-
ScaleCoordinateTransformation04 | TranslationCoordinateTransformation04
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class Dataset04(BaseModel):
|
|
80
|
-
"""Model for `Multiscale.datasets` elements."""
|
|
81
|
-
|
|
82
|
-
path: str
|
|
83
|
-
coordinateTransformations: list[Transformation04] = Field(
|
|
84
|
-
..., min_length=1, max_length=2
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
@field_validator("coordinateTransformations")
|
|
88
|
-
@classmethod
|
|
89
|
-
def _check_scale_exists(cls, v):
|
|
90
|
-
# check if at least one scale transformation exists
|
|
91
|
-
if SKIP_NGFF_VALIDATION:
|
|
92
|
-
return v
|
|
93
|
-
|
|
94
|
-
num_scale = sum(
|
|
95
|
-
1 for item in v if isinstance(item, ScaleCoordinateTransformation04)
|
|
96
|
-
)
|
|
97
|
-
if num_scale != 1:
|
|
98
|
-
raise ValueError("Exactly one scale transformation is required.")
|
|
99
|
-
|
|
100
|
-
num_translation = sum(
|
|
101
|
-
1 for item in v if isinstance(item, TranslationCoordinateTransformation04)
|
|
102
|
-
)
|
|
103
|
-
if num_translation > 1:
|
|
104
|
-
raise ValueError("At most one translation transformation is allowed.")
|
|
105
|
-
|
|
106
|
-
return v
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
class Multiscale04(BaseModel):
|
|
110
|
-
"""Model for `NgffImageMeta.multiscales` elements."""
|
|
111
|
-
|
|
112
|
-
name: str | None = None
|
|
113
|
-
datasets: list[Dataset04] = Field(..., min_length=1)
|
|
114
|
-
version: Literal["0.4"] | None = "0.4"
|
|
115
|
-
axes: list[Axis04] = Field(..., max_length=5, min_length=2)
|
|
116
|
-
coordinateTransformations: list[Transformation04] | None = None
|
|
117
|
-
_check_unique = field_validator("axes")(unique_items_validator)
|
|
118
|
-
|
|
119
|
-
@field_validator("axes")
|
|
120
|
-
@classmethod
|
|
121
|
-
def _check_axes_order(cls, v):
|
|
122
|
-
# check if the order of axes is correct
|
|
123
|
-
if SKIP_NGFF_VALIDATION:
|
|
124
|
-
return v
|
|
125
|
-
|
|
126
|
-
axes_types = [axis.type for axis in v]
|
|
127
|
-
|
|
128
|
-
if "time" in axes_types:
|
|
129
|
-
time_position = axes_types.index("time")
|
|
130
|
-
if time_position != 0:
|
|
131
|
-
raise ValueError("Time axis should be the first axis.")
|
|
132
|
-
|
|
133
|
-
axes_types = axes_types.pop(0)
|
|
134
|
-
|
|
135
|
-
if len(axes_types) < 2:
|
|
136
|
-
raise ValueError("At least two spatial axes are required.")
|
|
137
|
-
|
|
138
|
-
reversed_axes_types = axes_types[::-1]
|
|
139
|
-
|
|
140
|
-
channel_type_flag = False
|
|
141
|
-
for ax_type in reversed_axes_types:
|
|
142
|
-
if ax_type == "space":
|
|
143
|
-
if channel_type_flag:
|
|
144
|
-
raise ValueError("Channel axis should precede spatial axes.")
|
|
145
|
-
else:
|
|
146
|
-
channel_type_flag = True
|
|
147
|
-
return v
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
class NgffImageMeta04(BaseWithExtraFields):
|
|
151
|
-
"""Model for the metadata of a NGFF image."""
|
|
152
|
-
|
|
153
|
-
multiscales: list[Multiscale04] = Field(
|
|
154
|
-
...,
|
|
155
|
-
min_length=1,
|
|
156
|
-
)
|
|
157
|
-
omero: Omero04 | None = None
|
|
158
|
-
_check_unique = field_validator("multiscales")(unique_items_validator)
|