diff --git a/ome_zarr/reader.py b/ome_zarr/reader.py index 2fe8d607..ef79845b 100644 --- a/ome_zarr/reader.py +++ b/ome_zarr/reader.py @@ -424,7 +424,8 @@ def get_field(tile_name: str, level: int) -> np.ndarray: """tile_name is 'row,col'""" row, col = (int(n) for n in tile_name.split(",")) field_index = (column_count * row) + col - path = f"{field_index}/{level}" + image_path = image_paths[field_index] + path = f"{image_path}/{level}" LOGGER.debug("LOADING tile... %s", path) try: data = self.zarr.load(path) @@ -486,7 +487,6 @@ def get_pyramid_lazy(self, node: Node) -> None: LOGGER.info("plate_data: %s", self.plate_data) self.rows = self.plate_data.get("rows") self.columns = self.plate_data.get("columns") - self.first_field = "0" self.row_names = [row["name"] for row in self.rows] self.col_names = [col["name"] for col in self.columns] @@ -502,6 +502,7 @@ def get_pyramid_lazy(self, node: Node) -> None: well_spec: Optional[Well] = well_node.first(Well) if well_spec is None: raise Exception("Could not find first well") + self.first_field_path = well_spec.well_data["images"][0]["path"] self.numpy_type = well_spec.numpy_type LOGGER.debug("img_pyramid_shapes: %s", well_spec.img_pyramid_shapes) @@ -528,7 +529,7 @@ def get_numpy_type(self, image_node: Node) -> np.dtype: def get_tile_path(self, level: int, row: int, col: int) -> str: return ( f"{self.row_names[row]}/" - f"{self.col_names[col]}/{self.first_field}/{level}" + f"{self.col_names[col]}/{self.first_field_path}/{level}" ) def get_stitched_grid(self, level: int, tile_shape: tuple) -> da.core.Array: @@ -568,7 +569,7 @@ def get_tile_path(self, level: int, row: int, col: int) -> str: # pragma: no co """251.zarr/A/1/0/labels/0/3/""" path = ( f"{self.row_names[row]}/{self.col_names[col]}/" - f"{self.first_field}/labels/0/{level}" + f"{self.first_field_path}/labels/0/{level}" ) return path @@ -590,7 +591,7 @@ def get_pyramid_lazy(self, node: Node) -> None: # pragma: no cover properties: Dict[int, Dict[str, Any]] = {} for row in self.row_names: for col in self.col_names: - path = f"{row}/{col}/{self.first_field}/labels/0/.zattrs" + path = f"{row}/{col}/{self.first_field_path}/labels/0/.zattrs" labels_json = self.zarr.get_json(path).get("image-label", {}) # NB: assume that 'label_val' is unique across all images props_list = labels_json.get("properties", []) diff --git a/tests/test_reader.py b/tests/test_reader.py index 556a2087..3520eabc 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -1,6 +1,7 @@ +import numpy as np import pytest import zarr -from numpy import zeros +from numpy import ones, zeros from ome_zarr.data import create_zarr from ome_zarr.io import parse_url @@ -75,7 +76,8 @@ def test_minimal_plate(self): # assert len(nodes[1].specs) == 1 # assert isinstance(nodes[1].specs[0], PlateLabels) - def test_multiwells_plate(self): + @pytest.mark.parametrize("field_paths", [["0", "1", "2"], ["img1", "img2", "img3"]]) + def test_multiwells_plate(self, field_paths): row_names = ["A", "B", "C"] col_names = ["1", "2", "3", "4"] well_paths = ["A/1", "A/2", "A/4", "B/2", "B/3", "C/1", "C/3", "C/4"] @@ -84,16 +86,25 @@ def test_multiwells_plate(self): row, col = wp.split("/") row_group = self.root.require_group(row) well = row_group.require_group(col) - write_well_metadata(well, ["0", "1", "2"]) - for field in range(3): + write_well_metadata(well, field_paths) + for field in field_paths: image = well.require_group(str(field)) - write_image(zeros((1, 1, 1, 256, 256)), image) + write_image(ones((1, 1, 1, 256, 256)), image) reader = Reader(parse_url(str(self.path))) nodes = list(reader()) # currently reading plate labels disabled. Only 1 node assert len(nodes) == 1 - assert len(nodes[0].specs) == 1 - assert isinstance(nodes[0].specs[0], Plate) + plate_node = nodes[0] + assert len(plate_node.specs) == 1 + assert isinstance(plate_node.specs[0], Plate) + # Get the plate node's array. It should be fused from the first field of all + # well arrays (which in this test are non-zero), with zero values for wells + # that failed to load (not expected) or the surplus area not filled by a well. + expected_num_pixels = ( + len(well_paths) * len(field_paths[:1]) * np.prod((1, 1, 1, 256, 256)) + ) + pyramid_0 = plate_node.data[0] + assert np.asarray(pyramid_0).sum() == expected_num_pixels # assert len(nodes[1].specs) == 1 # assert isinstance(nodes[1].specs[0], PlateLabels)