Skip to content

Commit 0a3e927

Browse files
authored
Merge pull request #148 from sbesson/hcs_axes_fix
Fix remaining assumptions on 5D dimensions
2 parents 804dccf + 962031f commit 0a3e927

File tree

3 files changed

+37
-24
lines changed

3 files changed

+37
-24
lines changed

ome_zarr/reader.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def __init__(
5757
self.specs.append(PlateLabels(self))
5858
elif Plate.matches(zarr):
5959
self.specs.append(Plate(self))
60-
self.add(zarr, plate_labels=True)
60+
# self.add(zarr, plate_labels=True)
6161
if Well.matches(zarr):
6262
self.specs.append(Well(self))
6363

@@ -412,6 +412,8 @@ def __init__(self, node: Node) -> None:
412412
# Use first Field for rendering settings, shape etc.
413413
image_zarr = self.zarr.create(image_paths[0])
414414
image_node = Node(image_zarr, node)
415+
x_index = len(image_node.metadata["axes"]) - 1
416+
y_index = len(image_node.metadata["axes"]) - 2
415417
level = 0 # load full resolution image
416418
self.numpy_type = image_node.data[level].dtype
417419
self.img_metadata = image_node.metadata
@@ -448,8 +450,8 @@ def get_lazy_well() -> da.Array:
448450
dtype=self.numpy_type,
449451
)
450452
lazy_row.append(lazy_tile)
451-
lazy_rows.append(da.concatenate(lazy_row, axis=4))
452-
return da.concatenate(lazy_rows, axis=3)
453+
lazy_rows.append(da.concatenate(lazy_row, axis=x_index))
454+
return da.concatenate(lazy_rows, axis=y_index)
453455

454456
node.data = [get_lazy_well()]
455457
node.metadata = image_node.metadata
@@ -470,7 +472,7 @@ def get_pyramid_lazy(self, node: Node) -> None:
470472
stitched full-resolution images.
471473
"""
472474
self.plate_data = self.lookup("plate", {})
473-
LOGGER.info("plate_data", self.plate_data)
475+
LOGGER.info("plate_data: %s", self.plate_data)
474476
self.rows = self.plate_data.get("rows")
475477
self.columns = self.plate_data.get("columns")
476478
self.first_field = "0"
@@ -491,10 +493,11 @@ def get_pyramid_lazy(self, node: Node) -> None:
491493
raise Exception("could not find first well")
492494
self.numpy_type = well_spec.numpy_type
493495

494-
LOGGER.debug("img_pyramid_shapes", well_spec.img_pyramid_shapes)
496+
LOGGER.debug(f"img_pyramid_shapes: {well_spec.img_pyramid_shapes}")
495497

496-
size_y = well_spec.img_shape[3]
497-
size_x = well_spec.img_shape[4]
498+
self.axes = well_spec.img_metadata["axes"]
499+
size_y = well_spec.img_shape[len(self.axes) - 2]
500+
size_x = well_spec.img_shape[len(self.axes) - 1]
498501

499502
# FIXME - if only returning a single stiched plate (not a pyramid)
500503
# need to decide optimal size. E.g. longest side < 1500
@@ -511,7 +514,7 @@ def get_pyramid_lazy(self, node: Node) -> None:
511514
if longest_side <= TARGET_SIZE:
512515
break
513516

514-
LOGGER.debug("target_level", target_level)
517+
LOGGER.debug(f"target_level: {target_level}")
515518

516519
pyramid = []
517520

@@ -541,16 +544,19 @@ def get_tile_path(self, level: int, row: int, col: int) -> str:
541544
)
542545

543546
def get_stitched_grid(self, level: int, tile_shape: tuple) -> da.core.Array:
547+
LOGGER.debug(f"get_stitched_grid() level: {level}, tile_shape: {tile_shape}")
548+
544549
def get_tile(tile_name: str) -> np.ndarray:
545550
"""tile_name is 'level,z,c,t,row,col'"""
546551
row, col = (int(n) for n in tile_name.split(","))
547552
path = self.get_tile_path(level, row, col)
548-
LOGGER.debug(f"LOADING tile... {path}")
553+
LOGGER.debug(f"LOADING tile... {path} with shape: {tile_shape}")
549554

550555
try:
551556
data = self.zarr.load(path)
552-
except ValueError:
557+
except ValueError as e:
553558
LOGGER.error(f"Failed to load {path}")
559+
LOGGER.debug(f"{e}")
554560
data = np.zeros(tile_shape, dtype=self.numpy_type)
555561
return data
556562

@@ -566,23 +572,29 @@ def get_tile(tile_name: str) -> np.ndarray:
566572
lazy_reader(tile_name), shape=tile_shape, dtype=self.numpy_type
567573
)
568574
lazy_row.append(lazy_tile)
569-
lazy_rows.append(da.concatenate(lazy_row, axis=4))
570-
return da.concatenate(lazy_rows, axis=3)
575+
lazy_rows.append(da.concatenate(lazy_row, axis=len(self.axes) - 1))
576+
return da.concatenate(lazy_rows, axis=len(self.axes) - 2)
571577

572578

573579
class PlateLabels(Plate):
574-
def get_tile_path(self, level: int, row: int, col: int) -> str:
580+
def get_tile_path(self, level: int, row: int, col: int) -> str: # pragma: no cover
575581
"""251.zarr/A/1/0/labels/0/3/"""
576582
path = (
577583
f"{self.row_names[row]}/{self.col_names[col]}/"
578584
f"{self.first_field}/labels/0/{level}"
579585
)
580586
return path
581587

582-
def get_pyramid_lazy(self, node: Node) -> None:
588+
def get_pyramid_lazy(self, node: Node) -> None: # pragma: no cover
583589
super().get_pyramid_lazy(node)
584590
# pyramid data may be multi-channel, but we only have 1 labels channel
585-
node.data[0] = node.data[0][:, 0:1, :, :, :]
591+
# TODO: when PlateLabels are re-enabled, update the logic to handle
592+
# 0.4 axes (list of dictionaries)
593+
if "c" in self.axes:
594+
c_index = self.axes.index("c")
595+
idx = [slice(None)] * len(self.axes)
596+
idx[c_index] = slice(0, 1)
597+
node.data[0] = node.data[0][tuple(idx)]
586598
# remove image metadata
587599
node.metadata = {}
588600

@@ -602,7 +614,7 @@ def get_pyramid_lazy(self, node: Node) -> None:
602614
del properties[label_val]["label-value"]
603615
node.metadata["properties"] = properties
604616

605-
def get_numpy_type(self, image_node: Node) -> np.dtype:
617+
def get_numpy_type(self, image_node: Node) -> np.dtype: # pragma: no cover
606618
# FIXME - don't assume Well A1 is valid
607619
path = self.get_tile_path(0, 0, 0)
608620
label_zarr = self.zarr.load(path)

tests/test_node.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ def test_multiwells_plate(self, fmt):
109109
for wp in empty_wells:
110110
assert parse_url(str(self.path / wp)) is None
111111

112-
@pytest.mark.xfail(reason="https://github.com/ome/ome-zarr-py/issues/145")
113112
@pytest.mark.parametrize(
114113
"axes, dims",
115114
(

tests/test_reader.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from ome_zarr.data import create_zarr
66
from ome_zarr.io import parse_url
7-
from ome_zarr.reader import Node, Plate, PlateLabels, Reader
7+
from ome_zarr.reader import Node, Plate, Reader
88
from ome_zarr.writer import write_image, write_plate_metadata, write_well_metadata
99

1010

@@ -50,11 +50,12 @@ def test_minimal_plate(self):
5050

5151
reader = Reader(parse_url(str(self.path)))
5252
nodes = list(reader())
53-
assert len(nodes) == 2
53+
# currently reading plate labels disabled. Only 1 node
54+
assert len(nodes) == 1
5455
assert len(nodes[0].specs) == 1
5556
assert isinstance(nodes[0].specs[0], Plate)
56-
assert len(nodes[1].specs) == 1
57-
assert isinstance(nodes[1].specs[0], PlateLabels)
57+
# assert len(nodes[1].specs) == 1
58+
# assert isinstance(nodes[1].specs[0], PlateLabels)
5859

5960
def test_multiwells_plate(self):
6061
row_names = ["A", "B", "C"]
@@ -72,8 +73,9 @@ def test_multiwells_plate(self):
7273

7374
reader = Reader(parse_url(str(self.path)))
7475
nodes = list(reader())
75-
assert len(nodes) == 2
76+
# currently reading plate labels disabled. Only 1 node
77+
assert len(nodes) == 1
7678
assert len(nodes[0].specs) == 1
7779
assert isinstance(nodes[0].specs[0], Plate)
78-
assert len(nodes[1].specs) == 1
79-
assert isinstance(nodes[1].specs[0], PlateLabels)
80+
# assert len(nodes[1].specs) == 1
81+
# assert isinstance(nodes[1].specs[0], PlateLabels)

0 commit comments

Comments
 (0)