ngio 0.5.0__py3-none-any.whl → 0.5.0a2__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.
Files changed (53) hide show
  1. ngio/__init__.py +2 -5
  2. ngio/common/__init__.py +6 -11
  3. ngio/common/_masking_roi.py +54 -34
  4. ngio/common/_pyramid.py +85 -309
  5. ngio/common/_roi.py +330 -258
  6. ngio/experimental/iterators/_feature.py +3 -3
  7. ngio/experimental/iterators/_rois_utils.py +11 -10
  8. ngio/hcs/_plate.py +60 -132
  9. ngio/images/_abstract_image.py +35 -539
  10. ngio/images/_create.py +287 -0
  11. ngio/images/_create_synt_container.py +42 -39
  12. ngio/images/_image.py +250 -516
  13. ngio/images/_label.py +172 -249
  14. ngio/images/_masked_image.py +2 -2
  15. ngio/images/_ome_zarr_container.py +241 -644
  16. ngio/io_pipes/_io_pipes.py +9 -9
  17. ngio/io_pipes/_io_pipes_masked.py +7 -7
  18. ngio/io_pipes/_io_pipes_roi.py +6 -6
  19. ngio/io_pipes/_io_pipes_types.py +3 -3
  20. ngio/io_pipes/_match_shape.py +8 -6
  21. ngio/io_pipes/_ops_slices_utils.py +5 -8
  22. ngio/ome_zarr_meta/__init__.py +18 -29
  23. ngio/ome_zarr_meta/_meta_handlers.py +708 -392
  24. ngio/ome_zarr_meta/ngio_specs/__init__.py +0 -4
  25. ngio/ome_zarr_meta/ngio_specs/_axes.py +51 -152
  26. ngio/ome_zarr_meta/ngio_specs/_dataset.py +22 -13
  27. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +91 -129
  28. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +68 -57
  29. ngio/ome_zarr_meta/v04/__init__.py +1 -5
  30. ngio/ome_zarr_meta/v04/{_v04_spec.py → _v04_spec_utils.py} +85 -54
  31. ngio/ome_zarr_meta/v05/__init__.py +1 -5
  32. ngio/ome_zarr_meta/v05/{_v05_spec.py → _v05_spec_utils.py} +87 -64
  33. ngio/resources/__init__.py +1 -1
  34. ngio/resources/resource_model.py +1 -1
  35. ngio/tables/_tables_container.py +11 -62
  36. ngio/tables/backends/_anndata.py +8 -58
  37. ngio/tables/backends/_anndata_utils.py +6 -1
  38. ngio/tables/backends/_csv.py +19 -3
  39. ngio/tables/backends/_json.py +13 -10
  40. ngio/tables/backends/_non_zarr_backends.py +196 -0
  41. ngio/tables/backends/_parquet.py +31 -3
  42. ngio/tables/v1/_roi_table.py +24 -41
  43. ngio/utils/__init__.py +12 -6
  44. ngio/utils/_datasets.py +0 -6
  45. ngio/utils/_logger.py +50 -0
  46. ngio/utils/_zarr_utils.py +58 -167
  47. {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/METADATA +4 -11
  48. ngio-0.5.0a2.dist-info/RECORD +89 -0
  49. {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/WHEEL +1 -1
  50. ngio/images/_create_utils.py +0 -406
  51. ngio/tables/backends/_py_arrow_backends.py +0 -222
  52. ngio-0.5.0.dist-info/RECORD +0 -88
  53. {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -1,31 +1,32 @@
1
1
  """HCS (High Content Screening) specific metadata classes for NGIO."""
2
2
 
3
- import warnings
4
3
  from typing import Annotated
5
4
 
6
- from ome_zarr_models.common.plate import (
5
+ from ome_zarr_models.v04.hcs import HCSAttrs
6
+ from ome_zarr_models.v04.plate import (
7
7
  Acquisition,
8
8
  Column,
9
- PlateBase,
9
+ Plate,
10
10
  Row,
11
11
  WellInPlate,
12
12
  )
13
- from ome_zarr_models.common.well_types import WellImage as WellImageCommon
13
+ from ome_zarr_models.v04.well import WellAttrs as WellAttrs04
14
+ from ome_zarr_models.v04.well_types import WellImage as WellImage04
15
+ from ome_zarr_models.v04.well_types import WellMeta as WellMeta04
14
16
  from pydantic import BaseModel, SkipValidation, field_serializer
15
17
 
16
18
  from ngio.ome_zarr_meta.ngio_specs._ngio_image import DefaultNgffVersion, NgffVersions
17
- from ngio.utils import NgioValueError
19
+ from ngio.utils import NgioValueError, ngio_logger
18
20
 
19
21
 
20
22
  def path_in_well_validation(path: str) -> str:
21
23
  """Validate the path in the well."""
22
24
  # Check if the value contains only alphanumeric characters
23
25
  if not path.isalnum():
24
- warnings.warn(
26
+ ngio_logger.warning(
25
27
  f"Path '{path}' contains non-alphanumeric characters. "
26
28
  "This may cause issues with some tools. "
27
- "Consider using only alphanumeric characters in the path.",
28
- stacklevel=2,
29
+ "Consider using only alphanumeric characters in the path."
29
30
  )
30
31
  return path
31
32
 
@@ -40,7 +41,7 @@ class ImageInWellPath(BaseModel):
40
41
  acquisition_name: str | None = None
41
42
 
42
43
 
43
- class CustomWellImage(WellImageCommon):
44
+ class CustomWellImage(WellImage04):
44
45
  path: Annotated[str, SkipValidation]
45
46
 
46
47
  @field_serializer("path")
@@ -49,29 +50,32 @@ class CustomWellImage(WellImageCommon):
49
50
  return path_in_well_validation(value)
50
51
 
51
52
 
52
- class PlateWithVersion(PlateBase):
53
- version: NgffVersions
53
+ class CustomWellMeta(WellMeta04):
54
+ images: list[CustomWellImage] # type: ignore (override of WellMeta04.images)
54
55
 
55
56
 
56
- class NgioWellMeta(BaseModel):
57
- """HCS well metadata."""
57
+ class CustomWellAttrs(WellAttrs04):
58
+ well: CustomWellMeta # type: ignore (override of WellAttrs04.well)
58
59
 
59
- images: list[CustomWellImage] # type: ignore (override of WellMeta04.images)
60
- version: NgffVersions
60
+
61
+ class NgioWellMeta(CustomWellAttrs):
62
+ """HCS well metadata."""
61
63
 
62
64
  @classmethod
63
65
  def default_init(
64
66
  cls,
65
- ngff_version: NgffVersions = DefaultNgffVersion,
67
+ version: NgffVersions | None = None,
66
68
  ) -> "NgioWellMeta":
67
- well = cls(images=[], version=ngff_version)
69
+ if version is None:
70
+ version = DefaultNgffVersion
71
+ well = cls(well=CustomWellMeta(images=[], version=version))
68
72
  return well
69
73
 
70
74
  @property
71
75
  def acquisition_ids(self) -> list[int]:
72
76
  """Return the acquisition ids in the well."""
73
77
  acquisitions = []
74
- for images in self.images:
78
+ for images in self.well.images:
75
79
  if (
76
80
  images.acquisition is not None
77
81
  and images.acquisition not in acquisitions
@@ -81,7 +85,7 @@ class NgioWellMeta(BaseModel):
81
85
 
82
86
  def get_image_acquisition_id(self, image_path: str) -> int | None:
83
87
  """Return the acquisition id for the given image path."""
84
- for images in self.images:
88
+ for images in self.well.images:
85
89
  if images.path == image_path:
86
90
  return images.acquisition
87
91
  raise NgioValueError(f"Image at path {image_path} not found in the well.")
@@ -96,9 +100,11 @@ class NgioWellMeta(BaseModel):
96
100
  acquisition (int | None): The acquisition id to filter the images.
97
101
  """
98
102
  if acquisition is None:
99
- return [images.path for images in self.images]
103
+ return [images.path for images in self.well.images]
100
104
  return [
101
- images.path for images in self.images if images.acquisition == acquisition
105
+ images.path
106
+ for images in self.well.images
107
+ if images.acquisition == acquisition
102
108
  ]
103
109
 
104
110
  def add_image(
@@ -112,7 +118,7 @@ class NgioWellMeta(BaseModel):
112
118
  strict (bool): If True, check if the image already exists in the well.
113
119
  If False, do not check if the image already exists in the well.
114
120
  """
115
- list_of_images = self.images
121
+ list_of_images = self.well.images
116
122
  for image in list_of_images:
117
123
  if image.path == path:
118
124
  raise NgioValueError(
@@ -131,7 +137,9 @@ class NgioWellMeta(BaseModel):
131
137
 
132
138
  new_image = CustomWellImage(path=path, acquisition=acquisition)
133
139
  list_of_images.append(new_image)
134
- return NgioWellMeta(images=list_of_images, version=self.version)
140
+ return NgioWellMeta(
141
+ well=CustomWellMeta(images=list_of_images, version=self.well.version)
142
+ )
135
143
 
136
144
  def remove_image(self, path: str) -> "NgioWellMeta":
137
145
  """Remove an image from the well.
@@ -139,66 +147,35 @@ class NgioWellMeta(BaseModel):
139
147
  Args:
140
148
  path (str): The path of the image.
141
149
  """
142
- list_of_images = self.images
150
+ list_of_images = self.well.images
143
151
  for image in list_of_images:
144
152
  if image.path == path:
145
153
  list_of_images.remove(image)
146
- return NgioWellMeta(images=list_of_images, version=self.version)
154
+ return NgioWellMeta(
155
+ well=CustomWellMeta(
156
+ images=list_of_images, version=self.well.version
157
+ )
158
+ )
147
159
  raise NgioValueError(f"Image at path {path} not found in the well.")
148
160
 
149
161
 
150
- def _format_int_column(column: int, num_digits: int = 2) -> str:
151
- """Format the column as a string.
152
-
153
- We make sure to pad the column with zeros
154
- to have a consistent format.
155
-
156
- Args:
157
- column (int): The column to format.
158
- num_digits (int): The number of digits to pad the column.
159
-
160
- Returns:
161
- str: The column as a string.
162
- """
163
- return f"{column:0{num_digits}d}"
164
-
165
-
166
- def _stringify_column(column: str | int, num_digits: int = 2) -> str:
162
+ def _stringify_column(column: str | int) -> str:
167
163
  """Convert the column to a string.
168
164
 
169
- This will ensure that columns are always strings.
170
- and will help with sorting and comparison.
171
-
172
165
  Args:
173
166
  column (str | int): The column to convert.
174
- num_digits (int): The number of digits to pad the column.
175
167
 
176
168
  Returns:
177
169
  str: The column as a string.
178
170
  """
179
- if isinstance(column, int):
180
- return _format_int_column(column, num_digits=num_digits)
181
-
182
- elif isinstance(column, str):
183
- try:
184
- column_int = int(column)
185
- return _format_int_column(column_int, num_digits=num_digits)
186
- except ValueError:
187
- pass
171
+ if isinstance(column, str):
188
172
  return column
189
- raise NgioValueError(f"Column {column} must be a string or an integer.")
190
-
191
173
 
192
- def _find_row_index(rows: list[str], row: str) -> int | None:
193
- """Find the index of a row in the list of rows.
174
+ # Maybe we should pad the column with zeros
175
+ return str(column)
194
176
 
195
- Args:
196
- rows: List of row names.
197
- row: The row name to find.
198
177
 
199
- Returns:
200
- The index of the row, or None if not found.
201
- """
178
+ def _find_row_index(rows: list[str], row: str) -> int | None:
202
179
  try:
203
180
  return rows.index(row)
204
181
  except ValueError:
@@ -206,17 +183,8 @@ def _find_row_index(rows: list[str], row: str) -> int | None:
206
183
 
207
184
 
208
185
  def _find_column_index(columns: list[str], column: str | int) -> int | None:
209
- """Find the index of a column in the list of columns.
210
-
211
- Args:
212
- columns: List of column names.
213
- column: The column name or number to find.
214
-
215
- Returns:
216
- The index of the column, or None if not found.
217
- """
218
- _num_columns = [_stringify_column(columns) for columns in columns]
219
- column = _stringify_column(column)
186
+ _num_columns = [int(columns) for columns in columns]
187
+ column = int(column)
220
188
  try:
221
189
  return _num_columns.index(column)
222
190
  except ValueError:
@@ -226,16 +194,6 @@ def _find_column_index(columns: list[str], column: str | int) -> int | None:
226
194
  def _relabel_wells(
227
195
  wells: list[WellInPlate], rows: list[Row], columns: list[Column]
228
196
  ) -> list[WellInPlate]:
229
- """Relabel well indices after rows or columns have been added.
230
-
231
- Args:
232
- wells: List of wells to relabel.
233
- rows: Updated list of rows.
234
- columns: Updated list of columns.
235
-
236
- Returns:
237
- List of wells with updated row and column indices.
238
- """
239
197
  new_wells = []
240
198
  _rows = [row.name for row in rows]
241
199
  _columns = [column.name for column in columns]
@@ -260,30 +218,26 @@ def _relabel_wells(
260
218
  return new_wells
261
219
 
262
220
 
263
- class NgioPlateMeta(BaseModel):
221
+ class NgioPlateMeta(HCSAttrs):
264
222
  """HCS plate metadata."""
265
223
 
266
- plate: PlateWithVersion
267
- version: NgffVersions
268
-
269
224
  @classmethod
270
225
  def default_init(
271
226
  cls,
272
227
  images: list[ImageInWellPath] | None = None,
273
228
  name: str | None = None,
274
- ngff_version: NgffVersions = DefaultNgffVersion,
229
+ version: NgffVersions | None = None,
275
230
  ) -> "NgioPlateMeta":
276
231
  plate = cls(
277
- plate=PlateWithVersion(
232
+ plate=Plate(
278
233
  rows=[],
279
234
  columns=[],
280
235
  acquisitions=None,
281
236
  wells=[],
282
237
  field_count=None,
238
+ version=version,
283
239
  name=name,
284
- version=ngff_version,
285
- ),
286
- version=ngff_version,
240
+ )
287
241
  )
288
242
 
289
243
  if images is None:
@@ -340,8 +294,23 @@ class NgioPlateMeta(BaseModel):
340
294
  Returns:
341
295
  str: The path of the well.
342
296
  """
343
- row_idx = _find_row_index(self.rows, row)
344
- column_idx = _find_column_index(self.columns, column)
297
+ if row not in self.rows:
298
+ raise NgioValueError(
299
+ f"Row {row} not found in the plate. Available rows are {self.rows}."
300
+ )
301
+
302
+ row_idx = self.rows.index(row)
303
+
304
+ _num_columns = [int(columns) for columns in self.columns]
305
+
306
+ try:
307
+ _column = int(column)
308
+ except ValueError:
309
+ raise NgioValueError(
310
+ f"Column {column} must be an integer or convertible to an integer."
311
+ ) from None
312
+
313
+ column_idx = _num_columns.index(_column)
345
314
 
346
315
  for well in self.plate.wells:
347
316
  if well.columnIndex == column_idx and well.rowIndex == row_idx:
@@ -377,16 +346,16 @@ class NgioPlateMeta(BaseModel):
377
346
  else:
378
347
  wells = self.plate.wells
379
348
 
380
- new_plate = PlateWithVersion(
349
+ new_plate = Plate(
381
350
  rows=rows,
382
351
  columns=self.plate.columns,
383
352
  acquisitions=self.plate.acquisitions,
384
353
  wells=wells,
385
354
  field_count=self.plate.field_count,
386
355
  name=self.plate.name,
387
- version=self.version,
356
+ version=self.plate.version,
388
357
  )
389
- return NgioPlateMeta(plate=new_plate, version=self.version), row_idx
358
+ return NgioPlateMeta(plate=new_plate), row_idx
390
359
 
391
360
  def add_column(self, column: str | int) -> "tuple[NgioPlateMeta, int]":
392
361
  """Add a column to the plate.
@@ -404,7 +373,7 @@ class NgioPlateMeta(BaseModel):
404
373
 
405
374
  columns_names.append(_stringify_column(column))
406
375
  # sort as numbers
407
- columns_names.sort(key=lambda x: _stringify_column(x))
376
+ columns_names.sort(key=lambda x: int(x))
408
377
  column_idx = columns_names.index(_stringify_column(column))
409
378
  relabel_wells = True
410
379
 
@@ -415,30 +384,27 @@ class NgioPlateMeta(BaseModel):
415
384
  else:
416
385
  wells = self.plate.wells
417
386
 
418
- new_plate = PlateWithVersion(
387
+ new_plate = Plate(
419
388
  rows=self.plate.rows,
420
389
  columns=columns,
421
390
  acquisitions=self.plate.acquisitions,
422
391
  wells=wells,
423
392
  field_count=self.plate.field_count,
424
393
  name=self.plate.name,
425
- version=self.version,
394
+ version=self.plate.version,
426
395
  )
427
- return NgioPlateMeta(plate=new_plate, version=self.version), column_idx
396
+ return NgioPlateMeta(plate=new_plate), column_idx
428
397
 
429
398
  def add_well(
430
399
  self,
431
400
  row: str,
432
401
  column: str | int,
433
402
  ) -> "NgioPlateMeta":
434
- """Add a well to the plate.
403
+ """Add an image to the well.
435
404
 
436
405
  Args:
437
406
  row (str): The row of the well.
438
407
  column (str | int): The column of the well.
439
-
440
- Returns:
441
- NgioPlateMeta: Updated plate metadata with the new well.
442
408
  """
443
409
  plate, row_idx = self.add_row(row=row)
444
410
  plate, column_idx = plate.add_column(column=column)
@@ -456,16 +422,16 @@ class NgioPlateMeta(BaseModel):
456
422
  )
457
423
  )
458
424
 
459
- new_plate = PlateWithVersion(
425
+ new_plate = Plate(
460
426
  rows=plate.plate.rows,
461
427
  columns=plate.plate.columns,
462
428
  acquisitions=plate.plate.acquisitions,
463
429
  wells=wells,
464
430
  field_count=plate.plate.field_count,
465
431
  name=plate.plate.name,
466
- version=plate.version,
432
+ version=plate.plate.version,
467
433
  )
468
- return NgioPlateMeta(plate=new_plate, version=plate.version)
434
+ return NgioPlateMeta(plate=new_plate)
469
435
 
470
436
  def add_acquisition(
471
437
  self,
@@ -495,16 +461,16 @@ class NgioPlateMeta(BaseModel):
495
461
  Acquisition(id=acquisition_id, name=acquisition_name, **acquisition_kwargs)
496
462
  )
497
463
 
498
- new_plate = PlateWithVersion(
464
+ new_plate = Plate(
499
465
  rows=self.plate.rows,
500
466
  columns=self.plate.columns,
501
467
  acquisitions=acquisitions,
502
468
  wells=self.plate.wells,
503
469
  field_count=self.plate.field_count,
504
470
  name=self.plate.name,
505
- version=self.version,
471
+ version=self.plate.version,
506
472
  )
507
- return NgioPlateMeta(plate=new_plate, version=self.version)
473
+ return NgioPlateMeta(plate=new_plate)
508
474
 
509
475
  def remove_well(self, row: str, column: str | int) -> "NgioPlateMeta":
510
476
  """Remove a well from the plate.
@@ -531,33 +497,30 @@ class NgioPlateMeta(BaseModel):
531
497
  f"Well at row {row} and column {column} not found in the plate."
532
498
  )
533
499
 
534
- new_plate = PlateWithVersion(
500
+ new_plate = Plate(
535
501
  rows=self.plate.rows,
536
502
  columns=self.plate.columns,
537
503
  acquisitions=self.plate.acquisitions,
538
504
  wells=wells,
539
505
  field_count=self.plate.field_count,
540
506
  name=self.plate.name,
541
- version=self.version,
507
+ version=self.plate.version,
542
508
  )
543
- return NgioPlateMeta(plate=new_plate, version=self.version)
509
+ return NgioPlateMeta(plate=new_plate)
544
510
 
545
511
  def derive(
546
512
  self,
547
513
  name: str | None = None,
548
- ngff_version: NgffVersions | None = None,
514
+ version: NgffVersions | None = None,
549
515
  keep_acquisitions: bool = False,
550
516
  ) -> "NgioPlateMeta":
551
517
  """Derive the plate metadata.
552
518
 
553
519
  Args:
554
- name (str | None): The name of the derived plate.
555
- ngff_version (NgffVersions | None): The version of the derived plate.
520
+ name (str): The name of the derived plate.
521
+ version (NgffVersion | None): The version of the derived plate.
556
522
  If None, use the version of the original plate.
557
523
  keep_acquisitions (bool): If True, keep the acquisitions in the plate.
558
-
559
- Returns:
560
- NgioPlateMeta: The derived plate metadata.
561
524
  """
562
525
  columns = self.plate.columns
563
526
  rows = self.plate.rows
@@ -567,18 +530,17 @@ class NgioPlateMeta(BaseModel):
567
530
  else:
568
531
  acquisitions = None
569
532
 
570
- if ngff_version is None:
571
- ngff_version = self.version
533
+ if version is None:
534
+ version = self.plate.version # type: ignore (version is NgffVersions or None)
572
535
 
573
536
  return NgioPlateMeta(
574
- plate=PlateWithVersion(
537
+ plate=Plate(
575
538
  rows=rows,
576
539
  columns=columns,
577
540
  acquisitions=acquisitions,
578
541
  wells=[],
579
542
  field_count=self.plate.field_count,
543
+ version=version,
580
544
  name=name,
581
- version=ngff_version,
582
- ),
583
- version=ngff_version,
545
+ )
584
546
  )
@@ -13,11 +13,11 @@ import numpy as np
13
13
  from pydantic import BaseModel
14
14
 
15
15
  from ngio.ome_zarr_meta.ngio_specs._axes import (
16
- AxesHandler,
17
16
  DefaultSpaceUnit,
18
17
  DefaultTimeUnit,
19
18
  SpaceUnits,
20
19
  TimeUnits,
20
+ build_canonical_axes_handler,
21
21
  )
22
22
  from ngio.ome_zarr_meta.ngio_specs._channels import ChannelsMeta
23
23
  from ngio.ome_zarr_meta.ngio_specs._dataset import Dataset
@@ -41,13 +41,6 @@ class ImageLabelSource(BaseModel):
41
41
  return cls(version=version, source={"image": "../../"})
42
42
 
43
43
 
44
- class NgioLabelsGroupMeta(BaseModel):
45
- """Metadata model for the /labels group in OME-NGFF."""
46
-
47
- version: NgffVersions
48
- labels: list[str]
49
-
50
-
51
44
  class AbstractNgioImageMeta:
52
45
  """Base class for ImageMeta and LabelMeta."""
53
46
 
@@ -73,23 +66,42 @@ class AbstractNgioImageMeta:
73
66
  @classmethod
74
67
  def default_init(
75
68
  cls,
76
- levels: Sequence[str],
77
- axes_handler: AxesHandler,
78
- scales: Sequence[tuple[float, ...]],
79
- translations: Sequence[tuple[float, ...] | None],
69
+ levels: int | Sequence[str],
70
+ axes_names: Sequence[str],
71
+ pixel_size: PixelSize,
72
+ scaling_factors: Sequence[float] | None = None,
80
73
  name: str | None = None,
81
74
  version: NgffVersions = DefaultNgffVersion,
82
75
  ):
83
76
  """Initialize the ImageMeta object."""
77
+ axes_handler = build_canonical_axes_handler(
78
+ axes_names,
79
+ space_units=pixel_size.space_unit,
80
+ time_units=pixel_size.time_unit,
81
+ )
82
+
83
+ px_size_dict = pixel_size.as_dict()
84
+ scale = [px_size_dict.get(name, 1.0) for name in axes_handler.axes_names]
85
+
86
+ if scaling_factors is None:
87
+ _default = {"x": 2.0, "y": 2.0}
88
+ scaling_factors = [
89
+ _default.get(name, 1.0) for name in axes_handler.axes_names
90
+ ]
91
+
92
+ if isinstance(levels, int):
93
+ levels = [str(i) for i in range(levels)]
94
+
84
95
  datasets = []
85
- for level, scale, translation in zip(levels, scales, translations, strict=True):
96
+ for level in levels:
86
97
  dataset = Dataset(
87
98
  path=level,
88
99
  axes_handler=axes_handler,
89
100
  scale=scale,
90
- translation=translation,
101
+ translation=None,
91
102
  )
92
103
  datasets.append(dataset)
104
+ scale = [s * f for s, f in zip(scale, scaling_factors, strict=True)]
93
105
 
94
106
  return cls(
95
107
  version=version,
@@ -129,42 +141,6 @@ class AbstractNgioImageMeta:
129
141
  datasets=new_datasets,
130
142
  )
131
143
 
132
- def rename_axes(self, axes_names: Sequence[str]):
133
- """Rename axes in the metadata.
134
-
135
- Args:
136
- axes_names(Sequence[str]): The new axes names in the order of the current
137
- axes.
138
- """
139
- new_axes_handler = self.axes_handler.rename_axes(axes_names=axes_names)
140
- new_datasets = []
141
- for dataset in self.datasets:
142
- new_dataset = Dataset(
143
- path=dataset.path,
144
- axes_handler=new_axes_handler,
145
- scale=dataset.scale,
146
- translation=dataset.translation,
147
- )
148
- new_datasets.append(new_dataset)
149
-
150
- return type(self)(
151
- version=self.version,
152
- name=self.name,
153
- datasets=new_datasets,
154
- )
155
-
156
- def rename_image(self, name: str):
157
- """Rename the image in the metadata.
158
-
159
- Args:
160
- name(str): The new name of the image.
161
- """
162
- return type(self)(
163
- version=self.version,
164
- name=name,
165
- datasets=self.datasets,
166
- )
167
-
168
144
  @property
169
145
  def version(self) -> NgffVersions:
170
146
  """Version of the OME-NFF metadata used to build the object."""
@@ -361,15 +337,50 @@ class AbstractNgioImageMeta:
361
337
  )
362
338
  return dataset, lr_dataset
363
339
 
364
- def scaling_factor(self, path: str | None = None) -> tuple[float, ...]:
365
- """Get the scaling factors to downscale to the next lower resolution dataset."""
340
+ def scaling_factor(self, path: str | None = None) -> list[float]:
341
+ """Get the scaling factors from a dataset to its lower resolution."""
342
+ if self.levels == 1:
343
+ return [1.0] * len(self.axes_handler.axes_names)
344
+ dataset, lr_dataset = self._get_closest_datasets(path=path)
345
+
346
+ scaling_factors = []
347
+ for ax_name in self.axes_handler.axes_names:
348
+ s_d = dataset.get_scale(ax_name)
349
+ s_lr_d = lr_dataset.get_scale(ax_name)
350
+ scaling_factors.append(s_lr_d / s_d)
351
+ return scaling_factors
352
+
353
+ def yx_scaling(self, path: str | None = None) -> tuple[float, float]:
354
+ """Get the scaling factor from a dataset to its lower resolution."""
366
355
  if self.levels == 1:
367
- return (1.0,) * len(self.axes_handler.axes_names)
356
+ return 1.0, 1.0
368
357
  dataset, lr_dataset = self._get_closest_datasets(path=path)
369
- scale = dataset.scale
370
- lr_scale = lr_dataset.scale
371
- scaling_factors = [s / s_lr for s_lr, s in zip(scale, lr_scale, strict=True)]
372
- return tuple(scaling_factors)
358
+
359
+ if lr_dataset is None:
360
+ raise NgioValueError(
361
+ "No lower resolution dataset found. "
362
+ "This is the lowest resolution dataset."
363
+ )
364
+
365
+ s_d = dataset.get_scale("y")
366
+ s_lr_d = lr_dataset.get_scale("y")
367
+ scale_y = s_lr_d / s_d
368
+
369
+ s_d = dataset.get_scale("x")
370
+ s_lr_d = lr_dataset.get_scale("x")
371
+ scale_x = s_lr_d / s_d
372
+
373
+ return scale_y, scale_x
374
+
375
+ def z_scaling(self, path: str | None = None) -> float:
376
+ """Get the scaling factor from a dataset to its lower resolution."""
377
+ if self.levels == 1:
378
+ return 1.0
379
+ dataset, lr_dataset = self._get_closest_datasets(path=path)
380
+
381
+ s_d = dataset.get_scale("z", default=1.0)
382
+ s_lr_d = lr_dataset.get_scale("z", default=1.0)
383
+ return s_lr_d / s_d
373
384
 
374
385
 
375
386
  class NgioLabelMeta(AbstractNgioImageMeta):
@@ -1,14 +1,12 @@
1
1
  """Utility to read/write OME-Zarr metadata v0.4."""
2
2
 
3
- from ngio.ome_zarr_meta.v04._v04_spec import (
3
+ from ngio.ome_zarr_meta.v04._v04_spec_utils import (
4
4
  ngio_to_v04_image_meta,
5
5
  ngio_to_v04_label_meta,
6
- ngio_to_v04_labels_group_meta,
7
6
  ngio_to_v04_plate_meta,
8
7
  ngio_to_v04_well_meta,
9
8
  v04_to_ngio_image_meta,
10
9
  v04_to_ngio_label_meta,
11
- v04_to_ngio_labels_group_meta,
12
10
  v04_to_ngio_plate_meta,
13
11
  v04_to_ngio_well_meta,
14
12
  )
@@ -16,12 +14,10 @@ from ngio.ome_zarr_meta.v04._v04_spec import (
16
14
  __all__ = [
17
15
  "ngio_to_v04_image_meta",
18
16
  "ngio_to_v04_label_meta",
19
- "ngio_to_v04_labels_group_meta",
20
17
  "ngio_to_v04_plate_meta",
21
18
  "ngio_to_v04_well_meta",
22
19
  "v04_to_ngio_image_meta",
23
20
  "v04_to_ngio_label_meta",
24
- "v04_to_ngio_labels_group_meta",
25
21
  "v04_to_ngio_plate_meta",
26
22
  "v04_to_ngio_well_meta",
27
23
  ]