ngio 0.5.0b7__py3-none-any.whl → 0.5.1__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.
@@ -1,6 +1,6 @@
1
1
  """Abstract class for handling OME-NGFF images."""
2
2
 
3
- import warnings
3
+ import logging
4
4
  from collections.abc import Mapping, Sequence
5
5
  from typing import Any, Literal
6
6
 
@@ -26,6 +26,8 @@ from ngio.ome_zarr_meta.ngio_specs import (
26
26
  SpaceUnits,
27
27
  TimeUnits,
28
28
  )
29
+ from ngio.ome_zarr_meta.ngio_specs._axes import AxesSetup
30
+ from ngio.ome_zarr_meta.ngio_specs._channels import ChannelsMeta
29
31
  from ngio.tables import (
30
32
  ConditionTable,
31
33
  DefaultTableBackend,
@@ -48,6 +50,8 @@ from ngio.utils import (
48
50
  ZarrGroupHandler,
49
51
  )
50
52
 
53
+ logger = logging.getLogger(f"ngio:{__name__}")
54
+
51
55
 
52
56
  def _try_get_table_container(
53
57
  handler: ZarrGroupHandler, create_mode: bool = True
@@ -61,12 +65,19 @@ def _try_get_table_container(
61
65
 
62
66
 
63
67
  def _try_get_label_container(
64
- handler: ZarrGroupHandler, ngff_version: NgffVersions, create_mode: bool = True
68
+ handler: ZarrGroupHandler,
69
+ ngff_version: NgffVersions,
70
+ axes_setup: AxesSetup | None = None,
71
+ create_mode: bool = True,
65
72
  ) -> LabelsContainer | None:
66
73
  """Return a default label container."""
67
74
  try:
68
75
  label_handler = handler.get_handler("labels", create_mode=create_mode)
69
- return LabelsContainer(label_handler, ngff_version=ngff_version)
76
+ return LabelsContainer(
77
+ group_handler=label_handler,
78
+ axes_setup=axes_setup,
79
+ ngff_version=ngff_version,
80
+ )
70
81
  except FileNotFoundError:
71
82
  return None
72
83
 
@@ -97,6 +108,7 @@ class OmeZarrContainer:
97
108
  group_handler: ZarrGroupHandler,
98
109
  table_container: TablesContainer | None = None,
99
110
  label_container: LabelsContainer | None = None,
111
+ axes_setup: AxesSetup | None = None,
100
112
  validate_paths: bool = False,
101
113
  ) -> None:
102
114
  """Initialize the OmeZarrContainer.
@@ -105,16 +117,19 @@ class OmeZarrContainer:
105
117
  group_handler (ZarrGroupHandler): The Zarr group handler.
106
118
  table_container (TablesContainer | None): The tables container.
107
119
  label_container (LabelsContainer | None): The labels container.
120
+ axes_setup (AxesSetup | None): Axes setup to load ome-zarr with
121
+ non-standard axes configurations.
108
122
  validate_paths (bool): Whether to validate the paths of the image multiscale
109
123
  """
110
124
  self._group_handler = group_handler
111
- self._images_container = ImagesContainer(self._group_handler)
112
-
125
+ self._images_container = ImagesContainer(
126
+ self._group_handler, axes_setup=axes_setup
127
+ )
113
128
  self._labels_container = label_container
114
129
  self._tables_container = table_container
115
130
 
116
131
  if validate_paths:
117
- for level_path in self._images_container.levels_paths:
132
+ for level_path in self._images_container.level_paths:
118
133
  self.get_image(path=level_path)
119
134
 
120
135
  def __repr__(self) -> str:
@@ -151,7 +166,8 @@ class OmeZarrContainer:
151
166
  _labels_container = _try_get_label_container(
152
167
  self._group_handler,
153
168
  create_mode=create_mode,
154
- ngff_version=self.image_meta.version,
169
+ ngff_version=self.meta.version,
170
+ axes_setup=self._images_container.axes_setup,
155
171
  )
156
172
  self._labels_container = _labels_container
157
173
  return self._labels_container
@@ -183,116 +199,232 @@ class OmeZarrContainer:
183
199
  raise NgioValidationError("No tables found in the image.")
184
200
  return _tables_container
185
201
 
202
+ @property
203
+ def meta(self) -> NgioImageMeta:
204
+ """Return the image metadata."""
205
+ return self.images_container.meta
206
+
186
207
  @property
187
208
  def image_meta(self) -> NgioImageMeta:
188
209
  """Return the image metadata."""
189
- return self._images_container.meta
210
+ logger.warning(
211
+ "'image_meta' is deprecated and will be removed in ngio=0.6. "
212
+ "Please use 'meta' instead."
213
+ )
214
+ return self.images_container.meta
215
+
216
+ @property
217
+ def axes_setup(self) -> AxesSetup:
218
+ """Return the axes setup."""
219
+ return self.images_container.axes_setup
190
220
 
191
221
  @property
192
222
  def levels(self) -> int:
193
223
  """Return the number of levels in the image."""
194
- return self._images_container.levels
224
+ return self.images_container.levels
195
225
 
196
226
  @property
197
- def levels_paths(self) -> list[str]:
227
+ def level_paths(self) -> list[str]:
198
228
  """Return the paths of the levels in the image."""
199
- return self._images_container.levels_paths
229
+ return self.images_container.level_paths
230
+
231
+ @property
232
+ def levels_paths(self) -> list[str]:
233
+ """Deprecated: use 'level_paths' instead."""
234
+ logger.warning(
235
+ "'levels_paths' is deprecated and will be removed in ngio=0.6. "
236
+ "Please use 'level_paths' instead."
237
+ )
238
+ return self.images_container.level_paths
200
239
 
201
240
  @property
202
241
  def is_3d(self) -> bool:
203
242
  """Return True if the image is 3D."""
204
- return self.get_image().is_3d
243
+ return self.images_container.is_3d
205
244
 
206
245
  @property
207
246
  def is_2d(self) -> bool:
208
247
  """Return True if the image is 2D."""
209
- return self.get_image().is_2d
248
+ return self.images_container.is_2d
210
249
 
211
250
  @property
212
251
  def is_time_series(self) -> bool:
213
252
  """Return True if the image is a time series."""
214
- return self.get_image().is_time_series
253
+ return self.images_container.is_time_series
215
254
 
216
255
  @property
217
256
  def is_2d_time_series(self) -> bool:
218
257
  """Return True if the image is a 2D time series."""
219
- return self.get_image().is_2d_time_series
258
+ return self.images_container.is_2d_time_series
220
259
 
221
260
  @property
222
261
  def is_3d_time_series(self) -> bool:
223
262
  """Return True if the image is a 3D time series."""
224
- return self.get_image().is_3d_time_series
263
+ return self.images_container.is_3d_time_series
225
264
 
226
265
  @property
227
266
  def is_multi_channels(self) -> bool:
228
267
  """Return True if the image is multichannel."""
229
- return self.get_image().is_multi_channels
268
+ return self.images_container.is_multi_channels
230
269
 
231
270
  @property
232
271
  def space_unit(self) -> str | None:
233
272
  """Return the space unit of the image."""
234
- return self.image_meta.space_unit
273
+ return self.images_container.space_unit
235
274
 
236
275
  @property
237
276
  def time_unit(self) -> str | None:
238
277
  """Return the time unit of the image."""
239
- return self.image_meta.time_unit
278
+ return self.images_container.time_unit
240
279
 
241
280
  @property
242
281
  def channel_labels(self) -> list[str]:
243
282
  """Return the channels of the image."""
244
- image = self.get_image()
245
- return image.channel_labels
283
+ return self.images_container.channel_labels
246
284
 
247
285
  @property
248
286
  def wavelength_ids(self) -> list[str | None]:
249
287
  """Return the list of wavelength of the image."""
250
- image = self.get_image()
251
- return image.wavelength_ids
288
+ return self.images_container.wavelength_ids
252
289
 
253
290
  @property
254
291
  def num_channels(self) -> int:
255
292
  """Return the number of channels."""
256
- return len(self.channel_labels)
293
+ return self.images_container.num_channels
257
294
 
258
295
  def get_channel_idx(
259
296
  self, channel_label: str | None = None, wavelength_id: str | None = None
260
297
  ) -> int:
261
298
  """Get the index of a channel by its label or wavelength ID."""
262
- image = self.get_image()
263
- return image.channels_meta.get_channel_idx(
299
+ return self.images_container.get_channel_idx(
264
300
  channel_label=channel_label, wavelength_id=wavelength_id
265
301
  )
266
302
 
267
303
  def set_channel_meta(
268
304
  self,
305
+ channel_meta: ChannelsMeta | None = None,
269
306
  labels: Sequence[str | None] | int | None = None,
270
307
  wavelength_id: Sequence[str | None] | None = None,
308
+ start: Sequence[float | None] | None = None,
309
+ end: Sequence[float | None] | None = None,
271
310
  percentiles: tuple[float, float] | None = None,
272
- colors: Sequence[str] | None = None,
273
- active: Sequence[bool] | None = None,
311
+ colors: Sequence[str | None] | None = None,
312
+ active: Sequence[bool | None] | None = None,
274
313
  **omero_kwargs: dict,
275
314
  ) -> None:
276
- """Create a ChannelsMeta object with the default unit."""
315
+ """Create a ChannelsMeta object with the default unit.
316
+
317
+ Args:
318
+ channel_meta (ChannelsMeta | None): The channels metadata to set.
319
+ If none, it will fall back to the deprecated parameters.
320
+ labels(Sequence[str | None] | int): Deprecated. The list of channels names
321
+ in the image. If an integer is provided, the channels will
322
+ be named "channel_i".
323
+ wavelength_id(Sequence[str | None]): Deprecated. The wavelength ID of the
324
+ channel. If None, the wavelength ID will be the same as
325
+ the channel name.
326
+ start(Sequence[float | None]): Deprecated. The start value for each channel.
327
+ If None, the start value will be computed from the image.
328
+ end(Sequence[float | None]): Deprecated. The end value for each channel.
329
+ If None, the end value will be computed from the image.
330
+ percentiles(tuple[float, float] | None): Deprecated. The start and end
331
+ percentiles for each channel. If None, the percentiles will
332
+ not be computed.
333
+ colors(Sequence[str | None]): Deprecated. The list of colors for the
334
+ channels. If None, the colors will be random.
335
+ active (Sequence[bool | None]): Deprecated. Whether the channel should
336
+ be shown by default.
337
+ omero_kwargs(dict): Deprecated. Extra fields to store in the omero
338
+ attributes.
339
+ """
277
340
  self._images_container.set_channel_meta(
341
+ channel_meta=channel_meta,
278
342
  labels=labels,
279
343
  wavelength_id=wavelength_id,
280
- start=None,
281
- end=None,
344
+ start=start,
345
+ end=end,
282
346
  percentiles=percentiles,
283
347
  colors=colors,
284
348
  active=active,
285
349
  **omero_kwargs,
286
350
  )
287
351
 
352
+ def set_channel_labels(
353
+ self,
354
+ labels: Sequence[str],
355
+ ) -> None:
356
+ """Update the labels of the channels.
357
+
358
+ Args:
359
+ labels (Sequence[str]): The new labels for the channels.
360
+ """
361
+ self._images_container.set_channel_labels(labels=labels)
362
+
363
+ def set_channel_colors(
364
+ self,
365
+ colors: Sequence[str],
366
+ ) -> None:
367
+ """Update the colors of the channels.
368
+
369
+ Args:
370
+ colors (Sequence[str]): The new colors for the channels.
371
+ """
372
+ self._images_container.set_channel_colors(colors=colors)
373
+
288
374
  def set_channel_percentiles(
289
375
  self,
290
376
  start_percentile: float = 0.1,
291
377
  end_percentile: float = 99.9,
292
378
  ) -> None:
293
- """Update the percentiles of the image."""
294
- self._images_container.set_channel_percentiles(
295
- start_percentile=start_percentile, end_percentile=end_percentile
379
+ """Deprecated: Update the channel windows using percentiles.
380
+
381
+ Args:
382
+ start_percentile (float): The start percentile.
383
+ end_percentile (float): The end percentile.
384
+ """
385
+ logger.warning(
386
+ "The 'set_channel_percentiles' method is deprecated and will be removed in "
387
+ "ngio=0.6. Please use 'set_channel_windows_with_percentiles' instead."
388
+ )
389
+ self._images_container.set_channel_windows_with_percentiles(
390
+ percentiles=(start_percentile, end_percentile)
391
+ )
392
+
393
+ def set_channel_windows(
394
+ self,
395
+ starts_ends: Sequence[tuple[float, float]],
396
+ min_max: Sequence[tuple[float, float]] | None = None,
397
+ ) -> None:
398
+ """Update the channel windows.
399
+
400
+ These values are used by viewers to set the display
401
+ range of each channel.
402
+
403
+ Args:
404
+ starts_ends (Sequence[tuple[float, float]]): The start and end values
405
+ for each channel.
406
+ min_max (Sequence[tuple[float, float]] | None): The min and max values
407
+ for each channel. If None, the min and max values will not be updated.
408
+ """
409
+ self._images_container.set_channel_windows(
410
+ starts_ends=starts_ends,
411
+ min_max=min_max,
412
+ )
413
+
414
+ def set_channel_windows_with_percentiles(
415
+ self,
416
+ percentiles: tuple[float, float] | list[tuple[float, float]] = (0.1, 99.9),
417
+ ) -> None:
418
+ """Update the channel windows using percentiles.
419
+
420
+ Args:
421
+ percentiles (tuple[float, float] | list[tuple[float, float]]):
422
+ The start and end percentiles for each channel.
423
+ If a single tuple is provided,
424
+ the same percentiles will be used for all channels.
425
+ """
426
+ self._images_container.set_channel_windows_with_percentiles(
427
+ percentiles=percentiles
296
428
  )
297
429
 
298
430
  def set_axes_units(
@@ -308,12 +440,35 @@ class OmeZarrContainer:
308
440
  time_unit (TimeUnits): The unit of time.
309
441
  set_labels (bool): Whether to set the units for the labels as well.
310
442
  """
443
+ if set_labels:
444
+ for label_name in self.list_labels():
445
+ label = self.get_label(label_name)
446
+ label.set_axes_unit(space_unit=space_unit, time_unit=time_unit)
311
447
  self._images_container.set_axes_unit(space_unit=space_unit, time_unit=time_unit)
312
- if not set_labels:
313
- return
314
- for label_name in self.list_labels():
315
- label = self.get_label(label_name)
316
- label.set_axes_unit(space_unit=space_unit, time_unit=time_unit)
448
+
449
+ def set_axes_names(
450
+ self,
451
+ axes_names: Sequence[str],
452
+ ) -> None:
453
+ """Set the axes names of the image.
454
+
455
+ Args:
456
+ axes_names (Sequence[str]): The axes names of the image.
457
+ """
458
+ self._images_container.set_axes_names(axes_names=axes_names)
459
+
460
+ def set_name(
461
+ self,
462
+ name: str,
463
+ ) -> None:
464
+ """Set the name of the image in the metadata.
465
+
466
+ This does not change the group name or any paths.
467
+
468
+ Args:
469
+ name (str): The name of the image.
470
+ """
471
+ self._images_container.set_name(name=name)
317
472
 
318
473
  def get_image(
319
474
  self,
@@ -520,10 +675,10 @@ class OmeZarrContainer:
520
675
  labels=labels,
521
676
  pixel_size=pixel_size,
522
677
  )
523
-
524
678
  new_ome_zarr = OmeZarrContainer(
525
679
  group_handler=new_container._group_handler,
526
680
  validate_paths=False,
681
+ axes_setup=new_container.meta.axes_handler.axes_setup,
527
682
  )
528
683
 
529
684
  if copy_labels:
@@ -631,12 +786,10 @@ class OmeZarrContainer:
631
786
 
632
787
  """
633
788
  if check_type is not None:
634
- warnings.warn(
635
- "The 'check_type' argument is deprecated, and will be removed in "
636
- "ngio=0.3. Use 'get_table_as' instead or one of the "
637
- "type specific get_*table() methods.",
638
- DeprecationWarning,
639
- stacklevel=2,
789
+ logger.warning(
790
+ "The 'check_type' argument is deprecated and will be removed in "
791
+ "ngio=0.6. Please use 'get_table_as' instead or one of the "
792
+ "type specific get_*table() methods."
640
793
  )
641
794
  return self.tables_container.get(name=name, strict=False)
642
795
 
@@ -878,6 +1031,7 @@ def open_ome_zarr_container(
878
1031
  store: StoreOrGroup,
879
1032
  cache: bool = False,
880
1033
  mode: AccessModeLiteral = "r+",
1034
+ axes_setup: AxesSetup | None = None,
881
1035
  validate_arrays: bool = True,
882
1036
  ) -> OmeZarrContainer:
883
1037
  """Open an OME-Zarr image."""
@@ -885,6 +1039,7 @@ def open_ome_zarr_container(
885
1039
  return OmeZarrContainer(
886
1040
  group_handler=handler,
887
1041
  validate_paths=validate_arrays,
1042
+ axes_setup=axes_setup,
888
1043
  )
889
1044
 
890
1045
 
@@ -893,6 +1048,7 @@ def open_image(
893
1048
  path: str | None = None,
894
1049
  pixel_size: PixelSize | None = None,
895
1050
  strict: bool = True,
1051
+ axes_setup: AxesSetup | None = None,
896
1052
  cache: bool = False,
897
1053
  mode: AccessModeLiteral = "r+",
898
1054
  ) -> Image:
@@ -905,12 +1061,14 @@ def open_image(
905
1061
  strict (bool): Only used if the pixel size is provided. If True, the
906
1062
  pixel size must match the image pixel size exactly. If False, the
907
1063
  closest pixel size level will be returned.
1064
+ axes_setup (AxesSetup | None): Axes setup to load ome-zarr with
1065
+ non-standard axes configurations.
908
1066
  cache (bool): Whether to use a cache for the zarr group metadata.
909
1067
  mode (AccessModeLiteral): The
910
1068
  access mode for the image. Defaults to "r+".
911
1069
  """
912
1070
  group_handler = ZarrGroupHandler(store=store, cache=cache, mode=mode)
913
- images_container = ImagesContainer(group_handler)
1071
+ images_container = ImagesContainer(group_handler, axes_setup=axes_setup)
914
1072
  return images_container.get(
915
1073
  path=path,
916
1074
  pixel_size=pixel_size,
@@ -924,6 +1082,7 @@ def open_label(
924
1082
  path: str | None = None,
925
1083
  pixel_size: PixelSize | None = None,
926
1084
  strict: bool = True,
1085
+ axes_setup: AxesSetup | None = None,
927
1086
  cache: bool = False,
928
1087
  mode: AccessModeLiteral = "r+",
929
1088
  ) -> Label:
@@ -938,13 +1097,15 @@ def open_label(
938
1097
  strict (bool): Only used if the pixel size is provided. If True, the
939
1098
  pixel size must match the image pixel size exactly. If False, the
940
1099
  closest pixel size level will be returned.
1100
+ axes_setup (AxesSetup | None): Axes setup to load ome-zarr with
1101
+ non-standard axes configurations.
941
1102
  cache (bool): Whether to use a cache for the zarr group metadata.
942
1103
  mode (AccessModeLiteral): The access mode for the image. Defaults to "r+".
943
1104
 
944
1105
  """
945
1106
  group_handler = ZarrGroupHandler(store=store, cache=cache, mode=mode)
946
1107
  if name is None:
947
- label_meta_handler = LabelMetaHandler(group_handler)
1108
+ label_meta_handler = LabelMetaHandler(group_handler, axes_setup=axes_setup)
948
1109
  path = (
949
1110
  label_meta_handler.get_meta()
950
1111
  .get_dataset(path=path, pixel_size=pixel_size, strict=strict)
@@ -952,7 +1113,7 @@ def open_label(
952
1113
  )
953
1114
  return Label(group_handler, path, label_meta_handler)
954
1115
 
955
- labels_container = LabelsContainer(group_handler)
1116
+ labels_container = LabelsContainer(group_handler, axes_setup=axes_setup)
956
1117
  return labels_container.get(
957
1118
  name=name,
958
1119
  path=path,
@@ -975,6 +1136,7 @@ def create_empty_ome_zarr(
975
1136
  axes_names: Sequence[str] | None = None,
976
1137
  channels_meta: Sequence[str | Channel] | None = None,
977
1138
  name: str | None = None,
1139
+ axes_setup: AxesSetup | None = None,
978
1140
  ngff_version: NgffVersions = DefaultNgffVersion,
979
1141
  chunks: ChunksLike = "auto",
980
1142
  shards: ShardsLike | None = None,
@@ -1014,6 +1176,8 @@ def create_empty_ome_zarr(
1014
1176
  channels_meta (Sequence[str | Channel] | None): The channels metadata.
1015
1177
  Defaults to None.
1016
1178
  name (str | None): The name of the image. Defaults to None.
1179
+ axes_setup (AxesSetup | None): Axes setup to create ome-zarr with
1180
+ non-standard axes configurations. Defaults to None.
1017
1181
  ngff_version (NgffVersions): The version of the OME-Zarr specification.
1018
1182
  Defaults to DefaultNgffVersion.
1019
1183
  chunks (ChunksLike): The chunk shape. Defaults to "auto".
@@ -1034,19 +1198,15 @@ def create_empty_ome_zarr(
1034
1198
  channel_active (Sequence[bool] | None): Deprecated. Use channels_meta instead.
1035
1199
  """
1036
1200
  if xy_pixelsize is not None:
1037
- warnings.warn(
1038
- "'xy_pixelsize' is deprecated and will be removed in a future "
1039
- "version. Please use 'pixelsize' instead.",
1040
- DeprecationWarning,
1041
- stacklevel=2,
1201
+ logger.warning(
1202
+ "'xy_pixelsize' is deprecated and will be removed in ngio=0.6. "
1203
+ "Please use 'pixelsize' instead."
1042
1204
  )
1043
1205
  pixelsize = xy_pixelsize
1044
1206
  if xy_scaling_factor is not None or z_scaling_factor is not None:
1045
- warnings.warn(
1207
+ logger.warning(
1046
1208
  "'xy_scaling_factor' and 'z_scaling_factor' are deprecated and will be "
1047
- "removed in a future version. Please use 'scaling_factors' instead.",
1048
- DeprecationWarning,
1049
- stacklevel=2,
1209
+ "removed in ngio=0.6. Please use 'scaling_factors' instead."
1050
1210
  )
1051
1211
  xy_scaling_factor_ = xy_scaling_factor or 2.0
1052
1212
  z_scaling_factor_ = z_scaling_factor or 1.0
@@ -1057,40 +1217,32 @@ def create_empty_ome_zarr(
1057
1217
  scaling_factors = (1.0,) * (len(shape) - 3) + zyx_factors
1058
1218
 
1059
1219
  if channel_labels is not None:
1060
- warnings.warn(
1061
- "'channel_labels' is deprecated and will be removed in a future "
1062
- "version. Please use 'channels_meta' instead.",
1063
- DeprecationWarning,
1064
- stacklevel=2,
1220
+ logger.warning(
1221
+ "'channel_labels' is deprecated and will be removed in ngio=0.6. "
1222
+ "Please use 'channels_meta' instead."
1065
1223
  )
1066
1224
  channels_meta = channel_labels
1067
1225
 
1068
1226
  if channel_wavelengths is not None:
1069
- warnings.warn(
1070
- "'channel_wavelengths' is deprecated and will be removed in a future "
1071
- "version. Please use 'channels_meta' instead.",
1072
- DeprecationWarning,
1073
- stacklevel=2,
1227
+ logger.warning(
1228
+ "'channel_wavelengths' is deprecated and will be removed in ngio=0.6. "
1229
+ "Please use 'channels_meta' instead."
1074
1230
  )
1075
1231
  if channel_colors is not None:
1076
- warnings.warn(
1077
- "'channel_colors' is deprecated and will be removed in a future "
1078
- "version. Please use 'channels_meta' instead.",
1079
- DeprecationWarning,
1080
- stacklevel=2,
1232
+ logger.warning(
1233
+ "'channel_colors' is deprecated and will be removed in ngio=0.6. "
1234
+ "Please use 'channels_meta' instead."
1081
1235
  )
1082
1236
  if channel_active is not None:
1083
- warnings.warn(
1084
- "'channel_active' is deprecated and will be removed in a future "
1085
- "version. Please use 'channels_meta' instead.",
1086
- DeprecationWarning,
1087
- stacklevel=2,
1237
+ logger.warning(
1238
+ "'channel_active' is deprecated and will be removed in ngio=0.6. "
1239
+ "Please use 'channels_meta' instead."
1088
1240
  )
1089
1241
 
1090
1242
  if pixelsize is None:
1091
1243
  raise NgioValueError("pixelsize must be provided.")
1092
1244
 
1093
- handler = init_image_like(
1245
+ handler, axes_setup = init_image_like(
1094
1246
  store=store,
1095
1247
  meta_type=NgioImageMeta,
1096
1248
  shape=shape,
@@ -1105,6 +1257,7 @@ def create_empty_ome_zarr(
1105
1257
  axes_names=axes_names,
1106
1258
  channels_meta=channels_meta,
1107
1259
  name=name,
1260
+ axes_setup=axes_setup,
1108
1261
  ngff_version=ngff_version,
1109
1262
  chunks=chunks,
1110
1263
  shards=shards,
@@ -1115,25 +1268,22 @@ def create_empty_ome_zarr(
1115
1268
  overwrite=overwrite,
1116
1269
  )
1117
1270
 
1118
- ome_zarr = OmeZarrContainer(group_handler=handler)
1271
+ ome_zarr = OmeZarrContainer(group_handler=handler, axes_setup=axes_setup)
1119
1272
  if (
1120
- channel_wavelengths is not None
1273
+ channel_labels is not None
1274
+ or channel_wavelengths is not None
1121
1275
  or channel_colors is not None
1122
1276
  or channel_active is not None
1123
1277
  ):
1124
- channel_names = ome_zarr.channel_labels
1278
+ # Deprecated way of setting channel metadata
1279
+ # we set it here for backward compatibility
1125
1280
  ome_zarr.set_channel_meta(
1126
- labels=channel_names,
1281
+ labels=channel_labels,
1127
1282
  wavelength_id=channel_wavelengths,
1128
1283
  percentiles=None,
1129
1284
  colors=channel_colors,
1130
1285
  active=channel_active,
1131
1286
  )
1132
- else:
1133
- ome_zarr.set_channel_meta(
1134
- labels=ome_zarr.channel_labels,
1135
- percentiles=None,
1136
- )
1137
1287
  return ome_zarr
1138
1288
 
1139
1289
 
@@ -1152,6 +1302,7 @@ def create_ome_zarr_from_array(
1152
1302
  channels_meta: Sequence[str | Channel] | None = None,
1153
1303
  percentiles: tuple[float, float] = (0.1, 99.9),
1154
1304
  name: str | None = None,
1305
+ axes_setup: AxesSetup | None = None,
1155
1306
  ngff_version: NgffVersions = DefaultNgffVersion,
1156
1307
  chunks: ChunksLike = "auto",
1157
1308
  shards: ShardsLike | None = None,
@@ -1192,6 +1343,8 @@ def create_ome_zarr_from_array(
1192
1343
  percentiles (tuple[float, float]): The percentiles of the channels for
1193
1344
  computing display ranges. Defaults to (0.1, 99.9).
1194
1345
  name (str | None): The name of the image. Defaults to None.
1346
+ axes_setup (AxesSetup | None): Axes setup to create ome-zarr with
1347
+ non-standard axes configurations. Defaults to None.
1195
1348
  ngff_version (NgffVersions): The version of the OME-Zarr specification.
1196
1349
  Defaults to DefaultNgffVersion.
1197
1350
  chunks (ChunksLike): The chunk shape. Defaults to "auto".
@@ -1210,6 +1363,10 @@ def create_ome_zarr_from_array(
1210
1363
  channel_colors (Sequence[str] | None): Deprecated. Use channels_meta instead.
1211
1364
  channel_active (Sequence[bool] | None): Deprecated. Use channels_meta instead.
1212
1365
  """
1366
+ if len(percentiles) != 2:
1367
+ raise NgioValueError(
1368
+ f"'percentiles' must be a tuple of two values. Got {percentiles}"
1369
+ )
1213
1370
  ome_zarr = create_empty_ome_zarr(
1214
1371
  store=store,
1215
1372
  shape=array.shape,
@@ -1224,6 +1381,7 @@ def create_ome_zarr_from_array(
1224
1381
  axes_names=axes_names,
1225
1382
  channels_meta=channels_meta,
1226
1383
  name=name,
1384
+ axes_setup=axes_setup,
1227
1385
  ngff_version=ngff_version,
1228
1386
  chunks=chunks,
1229
1387
  shards=shards,
@@ -1242,12 +1400,5 @@ def create_ome_zarr_from_array(
1242
1400
  image = ome_zarr.get_image()
1243
1401
  image.set_array(array)
1244
1402
  image.consolidate()
1245
- if len(percentiles) != 2:
1246
- raise NgioValueError(
1247
- f"'percentiles' must be a tuple of two values. Got {percentiles}"
1248
- )
1249
- ome_zarr.set_channel_percentiles(
1250
- start_percentile=percentiles[0],
1251
- end_percentile=percentiles[1],
1252
- )
1403
+ ome_zarr.set_channel_windows_with_percentiles(percentiles=percentiles)
1253
1404
  return ome_zarr