Exemplo n.º 1
0
 def get_tile(self, r: int, ch: int, z: int) -> TileData:
     return SlicedImageTile(
         self.tiles[TileKey(round=r, ch=ch, zplane=z)],
         r,
         ch,
         z,
     )
Exemplo n.º 2
0
 def keys(self) -> Collection[TileKey]:
     """Returns a Collection of the TileKey's for all the tiles."""
     return [
         TileKey(round=round_label, ch=ch_label, zplane=zplane_label)
         for round_label in self._rounds for ch_label in self._chs
         for zplane_label in self._zplanes
     ]
Exemplo n.º 3
0
 def keys(self) -> Collection[TileKey]:
     """Returns a Collection of the TileKey's for all the tiles."""
     axes_sizes = join_axes_labels(
         self._axes_order, rounds=self._rounds, chs=self._chs, zplanes=self._zplanes)
     return [
         TileKey(round=selector[Axes.ROUND], ch=selector[Axes.CH], zplane=selector[Axes.ZPLANE])
         for selector in ordered_iterator(axes_sizes)
     ]
Exemplo n.º 4
0
    def tile_metadata(self) -> pd.DataFrame:
        """return a table containing Tile metadata

        Returns
        -------
        pd.DataFrame :
            dataframe containing per-tile metadata information for each image. Guaranteed to
            include information on channel, imaging round, z plane, and barcode index. Also
            contains any information stored in the extras field for each tile.

        """

        data: collections.defaultdict = collections.defaultdict(list)
        extras_keys: Set[str] = set()
        if self._tile_data is not None:
            tilekeys = self._tile_data.keys()
            extras_keys = set(
                key
                for tilekey in tilekeys
                for key in self._tile_data[tilekey].keys())
        index_keys = set(
            key.value
            for key in AXES_DATA.keys()
        )
        duplicate_keys = index_keys.intersection(extras_keys)
        if len(duplicate_keys) > 0:
            duplicate_keys_str = ", ".join([str(key) for key in duplicate_keys])
            raise ValueError(
                f"keys ({duplicate_keys_str}) was found in both the Tile specification and extras "
                f"field. Tile specification keys may not be duplicated in the extras field.")

        for selector in self._iter_axes({Axes.ROUND, Axes.CH, Axes.ZPLANE}):
            tilekey = TileKey(
                round=selector[Axes.ROUND],
                ch=selector[Axes.CH],
                zplane=selector[Axes.ZPLANE])
            extras = self._tile_data[tilekey] if self._tile_data else {}

            for index, index_value in selector.items():
                data[index.value].append(index_value)

            for k in extras_keys:
                data[k].append(extras.get(k, None))

            if 'barcode_index' not in extras:
                barcode_index = ((((selector[Axes.ZPLANE]
                                    * self.num_rounds) + selector[Axes.ROUND])
                                  * self.num_chs) + selector[Axes.CH])

                data['barcode_index'].append(barcode_index)

        return pd.DataFrame(data)
Exemplo n.º 5
0
    def __init__(self, tileset: TileSet) -> None:
        self._tile_shape = tileset.default_tile_shape

        self.tiles: MutableMapping[TileKey, Tile] = dict()
        for tile in tileset.tiles():
            key = TileKey(round=tile.indices[Axes.ROUND],
                          ch=tile.indices[Axes.CH],
                          zplane=tile.indices.get(Axes.ZPLANE, 0))
            self.tiles[key] = tile

            # if we don't have the tile shape, then we peek at the tile and get its shape.
            if self._tile_shape is None:
                self._tile_shape = tile.tile_shape

        self._extras = tileset.extras
Exemplo n.º 6
0
    def keys(self) -> Collection[TileKey]:
        """Returns a Collection of the TileKey's for all the tiles."""
        keys: MutableSequence[TileKey] = list()
        axis_names: MutableSequence[Axes] = list()
        labels: MutableSequence[Sequence[int]] = list()
        for index_name, index_labels in self.index_labels.items():
            axis_names.append(index_name)
            labels.append(index_labels)

        for indices in product(*labels):
            selector: MutableMapping[Axes, int] = dict()
            for index_name, index_value in zip(axis_names, indices):
                selector[index_name] = index_value

            keys.append(
                TileKey(
                    round=selector[Axes.ROUND],
                    ch=selector[Axes.CH],
                    zplane=selector[Axes.ZPLANE],
                ))

        return keys
Exemplo n.º 7
0
    def export(self,
               filepath: str,
               tile_opener=None,
               tile_format: ImageFormat = ImageFormat.NUMPY) -> None:
        """write the image tensor to disk in spaceTx format

        Parameters
        ----------
        filepath : str
            Path + prefix for the images and primary_images.json written by this function
        tile_opener : TODO ttung: doc me.
        tile_format : ImageFormat
            Format in which each 2D plane should be written.

        """
        # Add log data to extras
        self._tile_data.extras[STARFISH_EXTRAS_KEY] = logging.LogEncoder(
        ).encode({LOG: self.log})
        tileset = TileSet(
            dimensions={
                Axes.ROUND,
                Axes.CH,
                Axes.ZPLANE,
                Axes.Y,
                Axes.X,
            },
            shape={
                Axes.ROUND: self.num_rounds,
                Axes.CH: self.num_chs,
                Axes.ZPLANE: self.num_zplanes,
            },
            default_tile_shape={
                Axes.Y: self.tile_shape[0],
                Axes.X: self.tile_shape[1]
            },
            extras=self._tile_data.extras,
        )
        for axis_val_map in self._iter_axes({Axes.ROUND, Axes.CH,
                                             Axes.ZPLANE}):
            tilekey = TileKey(round=axis_val_map[Axes.ROUND],
                              ch=axis_val_map[Axes.CH],
                              zplane=axis_val_map[Axes.ZPLANE])
            round_, ch, zplane = tilekey.round, tilekey.ch, tilekey.z
            extras: dict = self._tile_data[tilekey]

            selector = {
                Axes.ROUND: round_,
                Axes.CH: ch,
                Axes.ZPLANE: zplane,
            }

            coordinates: MutableMapping[Coordinates, Union[Tuple[Number,
                                                                 Number],
                                                           Number]] = dict()
            x_coordinates = (float(self.xarray[Coordinates.X.value][0]),
                             float(self.xarray[Coordinates.X.value][-1]))
            y_coordinates = (float(self.xarray[Coordinates.Y.value][0]),
                             float(self.xarray[Coordinates.Y.value][-1]))
            coordinates[Coordinates.X] = x_coordinates
            coordinates[Coordinates.Y] = y_coordinates
            if Coordinates.Z in self.xarray.coords:
                # set the z coord to the calculated value from the associated z plane
                z_coordinates = float(self.xarray[Coordinates.Z.value][zplane])
                coordinates[Coordinates.Z] = z_coordinates

            tile = Tile(
                coordinates=coordinates,
                indices=selector,
                extras=extras,
            )
            tile.numpy_array, _ = self.get_slice(selector={
                Axes.ROUND: round_,
                Axes.CH: ch,
                Axes.ZPLANE: zplane
            })
            tileset.add_tile(tile)

        if tile_opener is None:

            def tile_opener(tileset_path: Path, tile, ext):
                base = tileset_path.parent / tileset_path.stem
                if Axes.ZPLANE in tile.indices:
                    zval = tile.indices[Axes.ZPLANE]
                    zstr = "-Z{}".format(zval)
                else:
                    zstr = ""
                return open(
                    "{}-H{}-C{}{}.{}".format(
                        str(base),
                        tile.indices[Axes.ROUND],
                        tile.indices[Axes.CH],
                        zstr,
                        ext,
                    ), "wb")

        if not filepath.endswith('.json'):
            filepath += '.json'
        Writer.write_to_path(tileset,
                             filepath,
                             pretty=True,
                             tile_opener=tile_opener,
                             tile_format=tile_format)
Exemplo n.º 8
0
    def export(self,
               filepath: str,
               tile_opener: Optional[Callable[[PurePath, Tile, str], BinaryIO]] = None,
               tile_format: ImageFormat=ImageFormat.NUMPY) -> None:
        """write the image tensor to disk in spaceTx format

        Parameters
        ----------
        filepath : str
            Path + prefix for the images and primary_images.json written by this function
        tile_opener : Optional[Callable[[PurePath, Tile, str], BinaryIO]]
            A callable responsible for opening the file that a tile's data is to be written to. The
            callable should accept three arguments -- the path of the tileset, the tile data, and
            the expected file extension. If this is not specified, a reasonable default is provided.
        tile_format : ImageFormat
            Format in which each 2D plane should be written.

        """
        # Add log data to extras
        tileset_extras = self._tile_data.extras if self._tile_data else {}
        tileset_extras[STARFISH_EXTRAS_KEY] = self.log.encode()
        tileset = TileSet(
            dimensions={
                Axes.ROUND,
                Axes.CH,
                Axes.ZPLANE,
                Axes.Y,
                Axes.X,
            },
            shape={
                Axes.ROUND: self.num_rounds,
                Axes.CH: self.num_chs,
                Axes.ZPLANE: self.num_zplanes,
            },
            default_tile_shape={Axes.Y: self.tile_shape[0], Axes.X: self.tile_shape[1]},
            extras=tileset_extras,
        )
        for selector in self._iter_axes({Axes.ROUND, Axes.CH, Axes.ZPLANE}):
            tilekey = TileKey(
                round=selector[Axes.ROUND],
                ch=selector[Axes.CH],
                zplane=selector[Axes.ZPLANE])
            extras: dict = self._tile_data[tilekey] if self._tile_data else {}

            coordinates: MutableMapping[Coordinates, Union[Tuple[Number, Number], Number]] = dict()
            x_coordinates = (float(self.xarray[Coordinates.X.value][0]),
                             float(self.xarray[Coordinates.X.value][-1]))
            y_coordinates = (float(self.xarray[Coordinates.Y.value][0]),
                             float(self.xarray[Coordinates.Y.value][-1]))
            coordinates[Coordinates.X] = x_coordinates
            coordinates[Coordinates.Y] = y_coordinates
            if Coordinates.Z in self.xarray.coords:
                # set the z coord to the calculated value from the associated z plane
                z_coordinates = float(self.xarray[Coordinates.Z.value][selector[Axes.ZPLANE]])
                coordinates[Coordinates.Z] = z_coordinates

            tile = Tile(
                coordinates=coordinates,
                indices=selector,
                extras=extras,
            )
            tile.numpy_array, _ = self.get_slice(selector)
            tileset.add_tile(tile)

        if tile_opener is None:
            def tile_opener(tileset_path: PurePath, tile: Tile, ext: str):
                base = tileset_path.parent / tileset_path.stem
                if Axes.ZPLANE in tile.indices:
                    zval = tile.indices[Axes.ZPLANE]
                    zstr = "-Z{}".format(zval)
                else:
                    zstr = ""
                return open(
                    "{}-H{}-C{}{}.{}".format(
                        str(base),
                        tile.indices[Axes.ROUND],
                        tile.indices[Axes.CH],
                        zstr,
                        ext,
                    ),
                    "wb")

        if not filepath.endswith('.json'):
            filepath += '.json'
        Writer.write_to_path(
            tileset,
            filepath,
            pretty=True,
            tile_opener=tile_opener,
            tile_format=tile_format)