Esempio n. 1
0
def test_labeled_indices_sel_slice():
    """Select a single tile across each index from an ImageStack with labeled indices.  Verify that
    the data is correct and that the physical coordinates are correctly set."""
    stack = setup_imagestack()
    selector = {
        Axes.ROUND: slice(None, 4),
        Axes.CH: slice(4, 6),
        Axes.ZPLANE: 4
    }
    subselected = stack.sel(selector)

    # verify that the subselected stack has the correct index labels.
    for index_type, expected_results in ((Axes.ROUND, [1, 4]),
                                         (Axes.CH, [4, 6]), (
                                             Axes.ZPLANE,
                                             [4],
                                         )):
        assert subselected.axis_labels(index_type) == expected_results

    for selectors in subselected._iter_axes({Axes.ROUND, Axes.CH,
                                             Axes.ZPLANE}):
        # verify that the subselected stack has the correct data.
        expected_fill_value = fill_value(selectors[Axes.ROUND],
                                         selectors[Axes.CH],
                                         selectors[Axes.ZPLANE])
        verify_stack_fill(subselected, selectors, expected_fill_value)

        # verify that each tile in the subselected stack has the correct physical coordinates.
    verify_physical_coordinates(
        stack,
        X_COORDS,
        Y_COORDS,
        get_physical_coordinates_of_z_plane(Z_COORDS),
    )
Esempio n. 2
0
def test_labeled_indices_sel_single_tile():
    """Select a single tile across each index from an ImageStack with labeled indices.  Verify that
    the data is correct and that the physical coordinates are correctly set."""
    stack = setup_imagestack()

    for selector in stack._iter_axes({Axes.ROUND, Axes.CH, Axes.ZPLANE}):
        subselected = stack.sel(selector)

        # verify that the subselected stack has the correct index labels.
        for index_type in (Axes.ROUND, Axes.CH, Axes.ZPLANE):
            assert subselected.axis_labels(index_type) == [
                selector[index_type]
            ]

        # verify that the subselected stack has the correct data.
        expected_fill_value = fill_value(selector[Axes.ROUND],
                                         selector[Axes.CH],
                                         selector[Axes.ZPLANE])
        verify_stack_fill(stack, selector, expected_fill_value)

        # assert that the physical coordinate values are what we expect.
    verify_physical_coordinates(
        stack,
        X_COORDS,
        Y_COORDS,
        get_physical_coordinates_of_z_plane(Z_COORDS),
    )
Esempio n. 3
0
def test_imagestack_export(tmpdir, format, count, recwarn):
    """
    Save a synthetic stack to files and check the results
    """
    stack_shape = OrderedDict([(Axes.ROUND, 3), (Axes.CH, 2), (Axes.ZPLANE, 1),
                               (Axes.Y, 50), (Axes.X, 40)])

    physical_coords = OrderedDict([
        (PhysicalCoordinateTypes.X_MIN, X_COORDS[0]),
        (PhysicalCoordinateTypes.X_MAX, X_COORDS[1]),
        (PhysicalCoordinateTypes.Y_MIN, Y_COORDS[0]),
        (PhysicalCoordinateTypes.Y_MAX, Y_COORDS[1]),
        (PhysicalCoordinateTypes.Z_MIN, Z_COORDS[0]),
        (PhysicalCoordinateTypes.Z_MAX, Z_COORDS[1])
    ])

    stack = test_utils.imagestack_with_coords_factory(stack_shape,
                                                      physical_coords)

    stack_json = tmpdir / "output.json"
    stack.export(str(stack_json), tile_format=format)
    files = list(
        [x for x in tmpdir.listdir() if str(x).endswith(format.file_ext)])
    loaded_stack = ImageStack.from_path_or_url(str(stack_json))
    verify_physical_coordinates(
        loaded_stack,
        X_COORDS,
        Y_COORDS,
        get_physical_coordinates_of_z_plane(Z_COORDS),
    )
    assert count == len(files)
    with open(files[0], "rb") as fh:
        format.reader_func(fh)
Esempio n. 4
0
def test_coordinates():
    """Set up an ImageStack with tiles that are aligned.  Verify that the coordinates
    retrieved match.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           AlignedTiles,
                                           True,
                                       ))
    for selectors in stack._iter_axes({Axes.ZPLANE}):
        verify_physical_coordinates(
            stack, X_COORDS, Y_COORDS,
            get_physical_coordinates_of_z_plane(
                zplane_to_z(selectors[Axes.ZPLANE])), selectors[Axes.ZPLANE])
Esempio n. 5
0
def test_crop_rcz():
    """Build an imagestack that contains a crop in r/c/z.  Verify that the appropriate tiles are
    loaded.
    """
    rounds = [1]
    chs = [2, 3]

    crop_parameters = CropParameters(
        permitted_rounds=rounds,
        permitted_chs=chs,
    )
    stack = setup_imagestack(crop_parameters)

    assert stack.axis_labels(Axes.ROUND) == rounds
    assert stack.axis_labels(Axes.CH) == chs
    assert stack.axis_labels(Axes.ZPLANE) == Z_LABELS

    for round_ in stack.axis_labels(Axes.ROUND):
        for ch in stack.axis_labels(Axes.CH):
            for zplane in stack.axis_labels(Axes.ZPLANE):
                expected_data = data(round_, ch, zplane)

                verify_stack_data(
                    stack,
                    {
                        Axes.ROUND: round_,
                        Axes.CH: ch,
                        Axes.ZPLANE: zplane
                    },
                    expected_data,
                )
    expected_z_coordinates = get_physical_coordinates_of_z_plane(Z_COORDS)
    verify_physical_coordinates(
        stack,
        X_COORDS,
        Y_COORDS,
        expected_z_coordinates,
    )
Esempio n. 6
0
def test_scalar_coordinates():
    """Set up an ImageStack where only a single scalar physical coordinate is provided per axis.
    Internally, this should be converted to a range where the two endpoints are identical to the
    physical coordinate provided.
    """
    stack = ImageStack.synthetic_stack(NUM_ROUND,
                                       NUM_CH,
                                       NUM_Z,
                                       HEIGHT,
                                       WIDTH,
                                       tile_fetcher=tile_fetcher_factory(
                                           ScalarTiles,
                                           True,
                                       ))

    expected_x = X_COORDS[0]
    expected_y = Y_COORDS[0]

    for selectors in stack._iter_axes({Axes.ZPLANE}):
        expected_z = zplane_to_z(selectors[Axes.ZPLANE])[0]
        verify_physical_coordinates(
            stack, (expected_x, expected_x), (expected_y, expected_y),
            get_physical_coordinates_of_z_plane((expected_z, expected_z)),
            selectors[Axes.ZPLANE])
Esempio n. 7
0
    def __init__(
            self,
            tile_data: TileCollectionData,
    ) -> None:
        axes_sizes = {
            Axes.ROUND: len(set(tilekey.round for tilekey in tile_data.keys())),
            Axes.CH: len(set(tilekey.ch for tilekey in tile_data.keys())),
            Axes.ZPLANE: len(set(tilekey.z for tilekey in tile_data.keys())),
        }

        self._tile_data = tile_data

        # check for existing log info
        if STARFISH_EXTRAS_KEY in tile_data.extras and LOG in tile_data.extras[STARFISH_EXTRAS_KEY]:
            self._log = loads(tile_data.extras[STARFISH_EXTRAS_KEY])[LOG]
        else:
            self._log: List[dict] = list()

        data_shape: MutableSequence[int] = []
        data_dimensions: MutableSequence[str] = []
        data_tick_marks: MutableMapping[str, Sequence[int]] = dict()
        for ix in range(N_AXES):
            size_for_axis: Optional[int] = None
            dim_for_axis: Optional[Axes] = None

            for axis_name, axis_data in AXES_DATA.items():
                if ix == axis_data.order:
                    size_for_axis = axes_sizes[axis_name]
                    dim_for_axis = axis_name
                    break

            if size_for_axis is None or dim_for_axis is None:
                raise ValueError(
                    f"Could not find entry for the {ix}th axis in AXES_DATA")

            data_shape.append(size_for_axis)
            data_dimensions.append(dim_for_axis.value)
            data_tick_marks[dim_for_axis.value] = list(
                sorted(set(tilekey[dim_for_axis] for tilekey in self._tile_data.keys())))

        data_shape.extend([tile_data.tile_shape[Axes.Y], tile_data.tile_shape[Axes.X]])
        data_dimensions.extend([Axes.Y.value, Axes.X.value])

        # now that we know the tile data type (kind and size), we can allocate the data array.
        self._data = MPDataArray.from_shape_and_dtype(
            shape=data_shape,
            dtype=np.float32,
            initial_value=0,
            dims=data_dimensions,
            coords=data_tick_marks,
        )

        all_selectors = list(self._iter_axes({Axes.ROUND, Axes.CH, Axes.ZPLANE}))
        first_selector = all_selectors[0]
        tile = tile_data.get_tile(r=first_selector[Axes.ROUND],
                                  ch=first_selector[Axes.CH],
                                  z=first_selector[Axes.ZPLANE])

        # Set up coordinates
        self._data[Coordinates.X.value] = xr.DataArray(
            np.linspace(tile.coordinates[Coordinates.X][0], tile.coordinates[Coordinates.X][1],
                        self.xarray.sizes[Axes.X.value]), dims=Axes.X.value)
        self._data[Coordinates.Y.value] = xr.DataArray(
            np.linspace(tile.coordinates[Coordinates.Y][0], tile.coordinates[Coordinates.Y][1],
                        self.xarray.sizes[Axes.Y.value]), dims=Axes.Y.value)
        if Coordinates.Z in tile.coordinates:
            # Fill with zeros for now, then replace with calculated midpoints
            self._data[Coordinates.Z.value] = xr.DataArray(np.zeros(
                self.xarray.sizes[Axes.ZPLANE.value]),
                dims=Axes.ZPLANE.value)

        # Get coords on first tile, then verify all subsequent tiles are aligned
        starting_coords = [
            tile.coordinates[Coordinates.X][0], tile.coordinates[Coordinates.X][1],
            tile.coordinates[Coordinates.Y][0], tile.coordinates[Coordinates.Y][1],
        ]

        for selector in tqdm(all_selectors):
            tile = tile_data.get_tile(
                r=selector[Axes.ROUND], ch=selector[Axes.CH], z=selector[Axes.ZPLANE])

            data = img_as_float32(tile.numpy_array)
            self.set_slice(selector=selector, data=data)

            coordinates_values = [
                tile.coordinates[Coordinates.X][0], tile.coordinates[Coordinates.X][1],
                tile.coordinates[Coordinates.Y][0], tile.coordinates[Coordinates.Y][1],
            ]
            if starting_coords != coordinates_values:
                raise ValueError(
                    f"Tiles must be aligned")
            if Coordinates.Z in tile.coordinates:
                z_range = (tile.coordinates[Coordinates.Z][0], tile.coordinates[Coordinates.Z][1])
                # Use mid-point of the z range for a tile for the z-coordinate
                self._data[Coordinates.Z.value].loc[selector[Axes.ZPLANE]] = \
                    physical_coordinate_calculator.get_physical_coordinates_of_z_plane(z_range)
Esempio n. 8
0
def test_crop_xy():
    """Build an imagestack that contains a crop in x/y.  Verify that the data is sliced correctly.
    """
    X_SLICE = (10, 30)
    Y_SLICE = (15, 40)
    crop_parameters = CropParameters(
        x_slice=slice(*X_SLICE),
        y_slice=slice(*Y_SLICE),
    )
    stack = setup_imagestack(crop_parameters)

    assert stack.axis_labels(Axes.ROUND) == ROUND_LABELS
    assert stack.axis_labels(Axes.CH) == CH_LABELS
    assert stack.axis_labels(Axes.ZPLANE) == Z_LABELS

    assert stack.raw_shape[3] == Y_SLICE[1] - Y_SLICE[0]
    assert stack.raw_shape[4] == X_SLICE[1] - X_SLICE[0]

    for round_ in stack.axis_labels(Axes.ROUND):
        for ch in stack.axis_labels(Axes.CH):
            for zplane in stack.axis_labels(Axes.ZPLANE):
                expected_data = data(round_, ch, zplane)
                expected_data = expected_data[Y_SLICE[0]:Y_SLICE[1],
                                              X_SLICE[0]:X_SLICE[1]]

                verify_stack_data(
                    stack,
                    {
                        Axes.ROUND: round_,
                        Axes.CH: ch,
                        Axes.ZPLANE: zplane
                    },
                    expected_data,
                )

    # the coordinates should be rescaled.  verify that the coordinates on the ImageStack
    # are also rescaled.
    original_x_coordinates = X_COORDS
    expected_x_coordinates = recalculate_physical_coordinate_range(
        original_x_coordinates[0],
        original_x_coordinates[1],
        WIDTH,
        slice(*X_SLICE),
    )

    original_y_coordinates = Y_COORDS
    expected_y_coordinates = recalculate_physical_coordinate_range(
        original_y_coordinates[0],
        original_y_coordinates[1],
        HEIGHT,
        slice(*Y_SLICE),
    )

    expected_z_coordinates = get_physical_coordinates_of_z_plane(Z_COORDS)

    verify_physical_coordinates(
        stack,
        expected_x_coordinates,
        expected_y_coordinates,
        expected_z_coordinates,
    )