ngio 0.4.0a2__py3-none-any.whl → 0.4.0a3__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/common/_roi.py CHANGED
@@ -49,7 +49,7 @@ T = TypeVar("T", int, float)
49
49
  class GenericRoi(BaseModel, Generic[T]):
50
50
  """A generic Region of Interest (ROI) model."""
51
51
 
52
- name: str
52
+ name: str | None
53
53
  x: T
54
54
  y: T
55
55
  z: T | None = None
@@ -67,6 +67,38 @@ class GenericRoi(BaseModel, Generic[T]):
67
67
  """Calculate the intersection of this ROI with another ROI."""
68
68
  return roi_intersection(self, other)
69
69
 
70
+ def _nice_str(self) -> str:
71
+ if self.t is not None:
72
+ t_str = f"t={self.t}->{self.t_length}"
73
+ else:
74
+ t_str = "t=None"
75
+ if self.z is not None:
76
+ z_str = f"z={self.z}->{self.z_length}"
77
+ else:
78
+ z_str = "z=None"
79
+
80
+ y_str = f"y={self.y}->{self.y_length}"
81
+ x_str = f"x={self.x}->{self.x_length}"
82
+
83
+ if self.label is not None:
84
+ label_str = f", label={self.label}"
85
+ else:
86
+ label_str = ""
87
+ cls_name = self.__class__.__name__
88
+ return f"{cls_name}({t_str}, {z_str}, {y_str}, {x_str}{label_str})"
89
+
90
+ def get_name(self) -> str:
91
+ """Get the name of the ROI, or a default if not set."""
92
+ if self.name is not None:
93
+ return self.name
94
+ return self._nice_str()
95
+
96
+ def __repr__(self) -> str:
97
+ return self._nice_str()
98
+
99
+ def __str__(self) -> str:
100
+ return self._nice_str()
101
+
70
102
 
71
103
  def _1d_intersection(
72
104
  a: T | None, a_length: T | None, b: T | None, b_length: T | None
@@ -113,11 +145,17 @@ def roi_intersection(
113
145
  x, x_length = _1d_intersection(
114
146
  ref_roi.x, ref_roi.x_length, other_roi.x, other_roi.x_length
115
147
  )
148
+ if x is None and x_length is None:
149
+ # No intersection
150
+ return None
116
151
  assert x is not None and x_length is not None
117
152
 
118
153
  y, y_length = _1d_intersection(
119
154
  ref_roi.y, ref_roi.y_length, other_roi.y, other_roi.y_length
120
155
  )
156
+ if y is None and y_length is None:
157
+ # No intersection
158
+ return None
121
159
  assert y is not None and y_length is not None
122
160
 
123
161
  z, z_length = _1d_intersection(
@@ -127,11 +165,8 @@ def roi_intersection(
127
165
  ref_roi.t, ref_roi.t_length, other_roi.t, other_roi.t_length
128
166
  )
129
167
 
130
- if (
131
- x_length <= 0
132
- or y_length <= 0
133
- or (z_length is not None and z_length <= 0)
134
- or (t_length is not None and t_length <= 0)
168
+ if (z_length is not None and z_length <= 0) or (
169
+ t_length is not None and t_length <= 0
135
170
  ):
136
171
  # No intersection
137
172
  return None
@@ -144,9 +179,14 @@ def roi_intersection(
144
179
  )
145
180
  label = ref_roi.label or other_roi.label
146
181
 
182
+ if ref_roi.name is not None and other_roi.name is not None:
183
+ name = f"{ref_roi.name}:{other_roi.name}"
184
+ else:
185
+ name = ref_roi.name or other_roi.name
186
+
147
187
  cls_ref = ref_roi.__class__
148
188
  return cls_ref(
149
- name=f"[{ref_roi.name}_x_{other_roi.name}]",
189
+ name=name,
150
190
  x=x,
151
191
  y=y,
152
192
  z=z,
@@ -47,7 +47,7 @@ class FeatureExtractorIterator(AbstractIteratorBuilder):
47
47
  self._input = input_image
48
48
  self._input_label = input_label
49
49
  self._ref_image = input_image
50
- self._rois = input_image.build_image_roi_table().rois()
50
+ self._rois = input_image.build_image_roi_table(name=None).rois()
51
51
 
52
52
  # Set iteration parameters
53
53
  self._input_slicing_kwargs = add_channel_selection_to_slicing_dict(
@@ -53,7 +53,7 @@ class ImageProcessingIterator(AbstractIteratorBuilder):
53
53
  self._input = input_image
54
54
  self._output = output_image
55
55
  self._ref_image = input_image
56
- self._rois = input_image.build_image_roi_table().rois()
56
+ self._rois = input_image.build_image_roi_table(name=None).rois()
57
57
 
58
58
  # Set iteration parameters
59
59
  self._input_slicing_kwargs = add_channel_selection_to_slicing_dict(
@@ -24,7 +24,7 @@ def grid(
24
24
  stride_y: int | None = None,
25
25
  stride_z: int | None = None,
26
26
  stride_t: int | None = None,
27
- base_name: str = "",
27
+ base_name: str | None = None,
28
28
  ) -> list[Roi]:
29
29
  """This method is a placeholder for creating a regular grid of ROIs."""
30
30
  t_dim = ref_image.dimensions.get("t", default=1)
@@ -49,7 +49,7 @@ def grid(
49
49
  for y in range(0, y_dim, stride_y):
50
50
  for x in range(0, x_dim, stride_x):
51
51
  roi = RoiPixels(
52
- name=f"{base_name}({t}, {z}, {y}, {x})",
52
+ name=base_name,
53
53
  x=x,
54
54
  y=y,
55
55
  z=z,
@@ -55,7 +55,7 @@ class SegmentationIterator(AbstractIteratorBuilder):
55
55
  self._input = input_image
56
56
  self._output = output_label
57
57
  self._ref_image = input_image
58
- self._rois = input_image.build_image_roi_table().rois()
58
+ self._rois = input_image.build_image_roi_table(name=None).rois()
59
59
 
60
60
  # Set iteration parameters
61
61
  self._input_slicing_kwargs = add_channel_selection_to_slicing_dict(
@@ -445,7 +445,7 @@ class AbstractImage(Generic[_image_handler]):
445
445
  """
446
446
  consolidate_image(image=self, order=order, mode=mode)
447
447
 
448
- def build_image_roi_table(self, name: str = "image") -> RoiTable:
448
+ def build_image_roi_table(self, name: str | None = "image") -> RoiTable:
449
449
  """Build the ROI table for an image."""
450
450
  return build_image_roi_table(image=self, name=name)
451
451
 
@@ -467,7 +467,7 @@ def consolidate_image(
467
467
  )
468
468
 
469
469
 
470
- def build_image_roi_table(image: AbstractImage, name: str = "image") -> RoiTable:
470
+ def build_image_roi_table(image: AbstractImage, name: str | None = "image") -> RoiTable:
471
471
  """Build the ROI table for an image."""
472
472
  dim_x = image.dimensions.get("x")
473
473
  dim_y = image.dimensions.get("y")
@@ -589,7 +589,7 @@ class OmeZarrContainer:
589
589
  backend=backend,
590
590
  )
591
591
 
592
- def build_image_roi_table(self, name: str = "image") -> RoiTable:
592
+ def build_image_roi_table(self, name: str | None = "image") -> RoiTable:
593
593
  """Compute the ROI table for an image."""
594
594
  return self.get_image().build_image_roi_table(name=name)
595
595
 
@@ -6,6 +6,7 @@ https://fractal-analytics-platform.github.io/fractal-tasks-core/tables/
6
6
 
7
7
  from collections.abc import Iterable
8
8
  from typing import Literal
9
+ from uuid import uuid4
9
10
 
10
11
  import pandas as pd
11
12
  from pydantic import BaseModel
@@ -146,7 +147,7 @@ def _rois_to_dataframe(rois: dict[str, Roi], index_key: str | None) -> pd.DataFr
146
147
  len_z_micrometer = roi.z_length if roi.z_length is not None else 1.0
147
148
 
148
149
  row = {
149
- index_key: roi.name,
150
+ index_key: roi.get_name(),
150
151
  "x_micrometer": roi.x,
151
152
  "y_micrometer": roi.y,
152
153
  "z_micrometer": z_micrometer,
@@ -179,8 +180,15 @@ class RoiDictWrapper:
179
180
  """A wrapper for a dictionary of ROIs to provide a consistent interface."""
180
181
 
181
182
  def __init__(self, rois: Iterable[Roi]) -> None:
182
- self._rois_by_name = {roi.name: roi for roi in rois}
183
- self._rois_by_label = {roi.label: roi for roi in rois if roi.label is not None}
183
+ self._rois_by_name = {}
184
+ self._rois_by_label = {}
185
+ for roi in rois:
186
+ name = roi.get_name()
187
+ if name in self._rois_by_name:
188
+ name = f"{name}_{uuid4().hex[:8]}"
189
+ self._rois_by_name[name] = roi
190
+ if roi.label is not None:
191
+ self._rois_by_label[roi.label] = roi
184
192
 
185
193
  def get_by_name(self, name: str, default: Roi | None = None) -> Roi | None:
186
194
  """Get an ROI by its name."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngio
3
- Version: 0.4.0a2
3
+ Version: 0.4.0a3
4
4
  Summary: Next Generation file format IO
5
5
  Project-URL: homepage, https://github.com/BioVisionCenter/ngio
6
6
  Project-URL: repository, https://github.com/BioVisionCenter/ngio
@@ -5,7 +5,7 @@ ngio/common/_array_io_utils.py,sha256=LktLM2_2LkjYkwzyJXHZ0LyuwrQN4GYTqgpByBxNml
5
5
  ngio/common/_dimensions.py,sha256=ubBSmnQmZOmen1jUn3LWZlNXCjUuV9FTjZWzUYidOwk,4852
6
6
  ngio/common/_masking_roi.py,sha256=ZZTXordEZoq_ADk0OzADvq-5dPOwUBSuNobzFR8fpTw,5697
7
7
  ngio/common/_pyramid.py,sha256=ElY_nBcchN3eeD9obLZ31IIo42HVlDn8R-legQpNxzQ,7503
8
- ngio/common/_roi.py,sha256=SJ_YJx5hR35T_OIx7ev9Y-rXInu7B4VEh8VKgcsdkcg,21166
8
+ ngio/common/_roi.py,sha256=x5HHudELvYjOmoLJulk2cNrgfOZ0o1Q1OFtldZAKIKU,22360
9
9
  ngio/common/_synt_images_utils.py,sha256=B6uYOW1NyrM06YMR-csca3_YnAAkPRTbvnbLdy9tk9E,3188
10
10
  ngio/common/_zoom.py,sha256=p_trkLLrNM6hYvchJQJOHfYpzSlzzdDJmcyTx6K5J1M,6030
11
11
  ngio/common/transforms/__init__.py,sha256=Dn8SpMw_e_bg9kx4ZVPrGHJIu_yOK1FkIlePlN_C7FQ,120
@@ -14,20 +14,20 @@ ngio/common/transforms/_zoom.py,sha256=mbnPnJZsCCms5x1Tq2akvsRDbsDYomiNRGqiF6KY2
14
14
  ngio/experimental/__init__.py,sha256=3pmBtHi-i8bKjTsvrOJM56ZyRX3Pv_dceCdt88-8COQ,147
15
15
  ngio/experimental/iterators/__init__.py,sha256=on_sUvuRhHBb7-r5u3Ojvu6K9FGjUOrWGUkLQ4aRzbs,556
16
16
  ngio/experimental/iterators/_abstract_iterator.py,sha256=p8ZxQuoqPGLZCp79FprhgV-QsN5uuqadffoXnEqSdys,5533
17
- ngio/experimental/iterators/_feature.py,sha256=6uONbB527SS2NLlpiFtL3AVOazH-QpGhETLEt8pykgU,5987
18
- ngio/experimental/iterators/_image_processing.py,sha256=4U2FCS5pyDes9VJAGbQn7_e8YMs2TU0ocVr2m1QZhYA,6639
19
- ngio/experimental/iterators/_rois_utils.py,sha256=LfBKk2XEY-UuomT_9uOg-0b0_GUo6IX5h0OJmrbMs4g,4375
20
- ngio/experimental/iterators/_segmentation.py,sha256=pCR2eR5LUMV5nouw6vRDjIyIabnvfxp7cE6sukW4GZc,11220
17
+ ngio/experimental/iterators/_feature.py,sha256=5MI0hgcR2lFUQLI4RpVCL2SDJNhmunW33tIUQhPWl_s,5996
18
+ ngio/experimental/iterators/_image_processing.py,sha256=fkD8PDm-3RaKpsRIRzvkeEkvDJ-fzcSWqrMXI3DBM4w,6648
19
+ ngio/experimental/iterators/_rois_utils.py,sha256=yFIlUAsSuh9ArUakJv7kTIiO2yG5r7kuDw-ljmtHj5Y,4359
20
+ ngio/experimental/iterators/_segmentation.py,sha256=NMzHcny2aUCRiSa9dROQ0kMzllYqIEwMh-fUmekw7dY,11229
21
21
  ngio/hcs/__init__.py,sha256=G8j9vD-liLeB_UeGtKYIgshWvJnUA6ks9GwjvWBLdHs,357
22
22
  ngio/hcs/_plate.py,sha256=qfRwbCKaoz_AWTi8RDFFwOxy5geSknfJrPcqFVno9zI,44288
23
23
  ngio/images/__init__.py,sha256=9Whvt7GTiCgT_vXaEEqGnDaY1-UsRk3dhLTv091F_g4,1211
24
- ngio/images/_abstract_image.py,sha256=AmulSId7WMpKke1ROshxX1hYLHHNQMBy_4F4aPkE-Jw,15601
24
+ ngio/images/_abstract_image.py,sha256=DfKz2xjB4QKMTYn8K9YorQSiPyzcwe9QCDtzzgsCnHE,15615
25
25
  ngio/images/_create.py,sha256=X0EalQgrcdh_RVgSxIkv0YNQydKXNRpCXHlgn1oVpI0,9445
26
26
  ngio/images/_create_synt_container.py,sha256=XjsQjBEnEGiqrfyKBdp_h4dJmScBMpMg1yUEqObo7Nw,5004
27
27
  ngio/images/_image.py,sha256=4PwHsD0KiiJwcyuVX4-iuLCv6V05N6JlCDlEggyLJkw,31742
28
28
  ngio/images/_label.py,sha256=rv6-oigkpa5mUTdogdPhfC3JYkEbdjXxY6Y6f1oD-RI,10603
29
29
  ngio/images/_masked_image.py,sha256=oFApCcPejfapzilh3ecO2NmI_FReU1FJPc-8XJqsYYU,19619
30
- ngio/images/_ome_zarr_container.py,sha256=uMQcvfwKj1uL3LG6k7pBQuPfG0KiM94fcf3kP7fu9eg,36705
30
+ ngio/images/_ome_zarr_container.py,sha256=WvvqH73pQkIIyiJTM6Fyzz6wjLs57V3hdEM7YBWzpOo,36712
31
31
  ngio/images/_table_ops.py,sha256=jFv_AMqoB4JBpoWsMtZppZVW7dAOC_u-JpfNm8b33kY,15292
32
32
  ngio/ome_zarr_meta/__init__.py,sha256=oZ8PEsWM7U0KwzpsnvVfX9k4UfuTz5sZ8B6B9eY5hyY,1193
33
33
  ngio/ome_zarr_meta/_meta_handlers.py,sha256=ctknNDT8jxwyvxQf9on5gW31H1tRRsnneO38GT2UXoE,25880
@@ -63,14 +63,14 @@ ngio/tables/v1/__init__.py,sha256=Wr1_9RZFpaN8FYMTnxT9Yjkw4AS7y9FMWailmB_uj5g,61
63
63
  ngio/tables/v1/_condition_table.py,sha256=T0Uq5BKkmMoEspt_Rx0U99Ow6S9GAMZDHqvUO5obCAM,1780
64
64
  ngio/tables/v1/_feature_table.py,sha256=n9uMHwoBh-_dlOhUXCFbmAjXFVXncNCR3SjE2qzXI68,3821
65
65
  ngio/tables/v1/_generic_table.py,sha256=1ktJHeuv7U1g5Z8PFUuTkCjOzcYMQd8xegKHKUedJB8,1240
66
- ngio/tables/v1/_roi_table.py,sha256=szhtLzHWW-DaDz_OsGK89ur-WpNufCSMvEc66DRzv8g,16867
66
+ ngio/tables/v1/_roi_table.py,sha256=g7UpMmpf3uAfaG59WYRnimUBgiB_T1qUJRwMZpMt9cI,17099
67
67
  ngio/utils/__init__.py,sha256=XPYh8ehC7uXNU2cFFXZAw-S3DpWpX1Yq2xGkffZv5vI,1142
68
68
  ngio/utils/_datasets.py,sha256=2g-Neg78dNcqyDz39QQw-Ifp9GITHjVHisdqgvvDNDE,5475
69
69
  ngio/utils/_errors.py,sha256=pKQ12LUjQLYE1nUawemA5h7HsgznjaSvV1n2PQU33N0,759
70
70
  ngio/utils/_fractal_fsspec_store.py,sha256=RdcCFOgHexRKX9zZvJV5RI-5OPc7VOPS6q_IeRxm24I,1548
71
71
  ngio/utils/_logger.py,sha256=N5W0a_xwze4blS1MolidBkTMbjTbg8GPguJZNun3mAE,1392
72
72
  ngio/utils/_zarr_utils.py,sha256=aYHhjHWGy5Jx7IkPb4nt9N0-HgyvJnyvK9GGqnccZkE,13606
73
- ngio-0.4.0a2.dist-info/METADATA,sha256=Wd5zLtu8OLbjEbgV9Lb5FDlBP9dFT9QU4S8h2358jKc,5868
74
- ngio-0.4.0a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
75
- ngio-0.4.0a2.dist-info/licenses/LICENSE,sha256=UgN_a1QCeNh9rZWfz-wORQFxE3elQzLWPQaoK6N6fxQ,1502
76
- ngio-0.4.0a2.dist-info/RECORD,,
73
+ ngio-0.4.0a3.dist-info/METADATA,sha256=PrG0TduDw2_iog0OKt2wF_gse3DW0oshBq158P6BS34,5868
74
+ ngio-0.4.0a3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
75
+ ngio-0.4.0a3.dist-info/licenses/LICENSE,sha256=UgN_a1QCeNh9rZWfz-wORQFxE3elQzLWPQaoK6N6fxQ,1502
76
+ ngio-0.4.0a3.dist-info/RECORD,,
File without changes