From 4a0c9c5e79fd8e3e6ff163f403d37ab12114ed96 Mon Sep 17 00:00:00 2001 From: Tim-Oliver Buchholz Date: Wed, 13 Dec 2023 16:49:32 +0100 Subject: [PATCH] Add doc-strings. --- src/faim_hcs/hcs/acquisition.py | 51 ++++++++++++++++++- .../cellvoyager/CellVoyagerWellAcquisition.py | 4 ++ src/faim_hcs/hcs/converter.py | 39 ++++++++++++++ .../ImageXpressPlateAcquisition.py | 4 +- .../hcs/imagexpress/MixedAcquisition.py | 30 +++++++++++ .../hcs/imagexpress/StackAcquisition.py | 5 -- src/faim_hcs/stitching/DaskTileStitcher.py | 14 ++++- src/faim_hcs/stitching/stitching_utils.py | 38 ++++++++++++++ 8 files changed, 176 insertions(+), 9 deletions(-) diff --git a/src/faim_hcs/hcs/acquisition.py b/src/faim_hcs/hcs/acquisition.py index 05da2783..61579bca 100644 --- a/src/faim_hcs/hcs/acquisition.py +++ b/src/faim_hcs/hcs/acquisition.py @@ -61,10 +61,20 @@ def get_channel_metadata(self) -> dict[int, ChannelMetadata]: raise NotImplementedError() def get_well_names(self) -> Iterable[str]: + """ + Get the names of all wells in the acquisition. + """ for well in self.get_well_acquisitions(): yield well.name def get_omero_channel_metadata(self) -> list[dict]: + """ + Get the channel metadata in OMERO format. + + Returns + ------- + List of channel metadata. + """ ome_channels = [] ch_metadata = self.get_channel_metadata() max_channel = max(list(ch_metadata.keys())) @@ -115,7 +125,6 @@ def get_common_well_shape(self) -> tuple[int, int, int, int, int]: Returns ------- - tuple[int, int, int, int, int] (time, channel, z, y, x) """ well_shapes = [] @@ -126,6 +135,10 @@ def get_common_well_shape(self) -> tuple[int, int, int, int, int]: class WellAcquisition(ABC): + """ + A single well of a plate acquisition. + """ + name: str = None _files = None _alignment: TileAlignmentOptions = None @@ -157,6 +170,13 @@ def _assemble_tiles(self) -> list[Tile]: raise NotImplementedError() def get_dtype(self) -> np.dtype: + """ + Get the data type of the well acquisition. + + Returns + ------- + type + """ return self._tiles[0].load_data().dtype def _align_tiles(self, tiles: list[Tile]) -> list[Tile]: @@ -177,23 +197,52 @@ def get_tiles(self) -> list[Tile]: return self._tiles def get_row_col(self) -> tuple[str, str]: + """ + Get the row and column of the well acquisition. + + Returns + ------- + row, column + """ return self.name[0], self.name[1:] @abstractmethod def get_axes(self) -> list[str]: + """ + Get the axes of the well acquisition. + """ raise NotImplementedError() @abstractmethod def get_yx_spacing(self) -> tuple[float, float]: + """ + Get the yx spacing of the well acquisition. + """ raise NotImplementedError() @abstractmethod def get_z_spacing(self) -> Optional[float]: + """ + Get the z spacing of the well acquisition. + """ raise NotImplementedError() def get_coordinate_transformations( self, max_layer: int, yx_binning: int ) -> list[dict[str, Any]]: + """ + Get the NGFF conform coordinate transformations for the well + acquisition. + + Parameters + ---------- + max_layer : Maximum layer of the resolution pyramid. + yx_binning : Bin factor of the yx resolution. + + Returns + ------- + List of coordinate transformations. + """ transformations = [] for s in range(max_layer + 1): if self.get_z_spacing() is not None: diff --git a/src/faim_hcs/hcs/cellvoyager/CellVoyagerWellAcquisition.py b/src/faim_hcs/hcs/cellvoyager/CellVoyagerWellAcquisition.py index 228fbe16..591e838c 100644 --- a/src/faim_hcs/hcs/cellvoyager/CellVoyagerWellAcquisition.py +++ b/src/faim_hcs/hcs/cellvoyager/CellVoyagerWellAcquisition.py @@ -9,6 +9,10 @@ class CellVoyagerWellAcquisition(WellAcquisition): + """ + Data structure for a CellVoyager well acquisition. + """ + def __init__( self, files: pd.DataFrame, diff --git a/src/faim_hcs/hcs/converter.py b/src/faim_hcs/hcs/converter.py index 5007b11e..255eb850 100644 --- a/src/faim_hcs/hcs/converter.py +++ b/src/faim_hcs/hcs/converter.py @@ -27,6 +27,10 @@ class NGFFPlate(BaseModel): class ConvertToNGFFPlate: + """ + Convert a plate acquisition to an NGFF plate. + """ + _ngff_plate: NGFFPlate def __init__( @@ -37,6 +41,21 @@ def __init__( warp_func: Callable = stitching_utils.translate_tiles_2d, fuse_func: Callable = stitching_utils.fuse_mean, ): + """ + Parameters + ---------- + ngff_plate : + NGFF plate information. + yx_binning : + YX binning factor. + dask_chunk_size_factor : + Dask chunk size factor. Increasing this will increase the memory + usage. + warp_func : + Function used to warp tile images. + fuse_func : + Function used to fuse tile images. + """ assert ( isinstance(yx_binning, int) and yx_binning >= 1 ), "yx_binning must be an integer >= 1." @@ -84,6 +103,26 @@ def run( max_layer: int = 3, storage_options: dict = None, ) -> zarr.Group: + """ + Convert a plate acquisition to an NGFF plate. + + Parameters + ---------- + plate_acquisition : + A single plate acquisition. + well_sub_group : + Name of the well sub-group. + chunks : + Chunk size in (Z)YX. + max_layer : + Maximum layer of the resolution pyramid layers. + storage_options : + Zarr storage options. + + Returns + ------- + zarr.Group of the plate. + """ assert 2 <= len(chunks) <= 3, "Chunks must be 2D or 3D." plate = self._create_zarr_plate(plate_acquisition) for well_acquisition in tqdm(plate_acquisition.get_well_acquisitions()): diff --git a/src/faim_hcs/hcs/imagexpress/ImageXpressPlateAcquisition.py b/src/faim_hcs/hcs/imagexpress/ImageXpressPlateAcquisition.py index c3d027a8..0b958e91 100644 --- a/src/faim_hcs/hcs/imagexpress/ImageXpressPlateAcquisition.py +++ b/src/faim_hcs/hcs/imagexpress/ImageXpressPlateAcquisition.py @@ -43,15 +43,15 @@ def _parse_files(self) -> pd.DataFrame: Table of all files in the acquisition. """ return pd.DataFrame( - self._list_and_match_files( + ImageXpressPlateAcquisition._list_and_match_files( root_dir=self._acquisition_dir, root_re=self._get_root_re(), filename_re=self._get_filename_re(), ) ) + @staticmethod def _list_and_match_files( - self, root_dir: Union[Path, str], root_re: re.Pattern, filename_re: re.Pattern, diff --git a/src/faim_hcs/hcs/imagexpress/MixedAcquisition.py b/src/faim_hcs/hcs/imagexpress/MixedAcquisition.py index f8337111..58e42529 100644 --- a/src/faim_hcs/hcs/imagexpress/MixedAcquisition.py +++ b/src/faim_hcs/hcs/imagexpress/MixedAcquisition.py @@ -9,6 +9,36 @@ class MixedAcquisition(StackAcquisition): + """Image stack acquisition with Projectsion acquired with a Molecular + Devices ImageXpress Micro Confocal system. + + MIP-2P-2sub-Stack --> {name} [Optional] + └── 2023-02-21 --> {date} + └── 1334 --> {acquisition id} + ├── Projection-Mix_E07_s1_w1E94C24BD-45E4-450A-9919-257C714278F7.tif + ├── Projection-Mix_E07_s1_w1_thumb4BFD4018-E675-475E-B5AB-2E959E6B6DA1.tif + ├── ... + ├── Projection-Mix_E08_s2_w3CCE83D85-0912-429E-9F18-716A085BB5BC.tif + ├── Projection-Mix_E08_s2_w3_thumb4D88636E-181E-4AF6-BC53-E7A435959C8F.tif + ├── ZStep_1 + │   ├── Projection-Mix_E07_s1_w1E78EB128-BD0D-4D94-A6AD-3FF28BB1B105.tif + │   ├── Projection-Mix_E07_s1_w1_thumb187DE64B-038A-4671-BF6B-683721723769.tif + │   ├── Projection-Mix_E07_s1_w2C0A49256-E289-4C0F-ADC9-F7728ABDB141.tif + │   ├── Projection-Mix_E07_s1_w2_thumb57D4B151-71BF-480E-8CC4-C23A2690B763.tif + │   ├── Projection-Mix_E07_s1_w427CCB2E4-1BF4-45E7-8BC7-264B48EF9C4A.tif + │   ├── Projection-Mix_E07_s1_w4_thumb555647D0-77F1-4A43-9472-AE509F95E236.tif + │   ├── ... + │   └── Projection-Mix_E08_s2_w4_thumbD2785594-4F49-464F-9F80-1B82E30A560A.tif + ├── ... + └── ZStep_9 + ├── Projection-Mix_E07_s1_w1091EB8A5-272A-466D-B8A0-7547C6BA392B.tif + ├── ... + └── Projection-Mix_E08_s2_w2_thumb210C0D5D-C20E-484D-AFB2-EFE669A56B84.tif + + Image data is stored in {name}_{well}_{field}_w{channel}{md_id}.tif. + The *_thumb*.tif files, used by Molecular Devices as preview, are ignored. + """ + def __init__( self, acquisition_dir: Union[Path, str], diff --git a/src/faim_hcs/hcs/imagexpress/StackAcquisition.py b/src/faim_hcs/hcs/imagexpress/StackAcquisition.py index 0d440516..a3fe128c 100644 --- a/src/faim_hcs/hcs/imagexpress/StackAcquisition.py +++ b/src/faim_hcs/hcs/imagexpress/StackAcquisition.py @@ -17,11 +17,6 @@ class StackAcquisition(ImageXpressPlateAcquisition): MIP-2P-2sub-Stack --> {name} [Optional] └── 2023-02-21 --> {date} └── 1334 --> {acquisition id} - ├── Projection-Mix_E07_s1_w1E94C24BD-45E4-450A-9919-257C714278F7.tif - ├── Projection-Mix_E07_s1_w1_thumb4BFD4018-E675-475E-B5AB-2E959E6B6DA1.tif - ├── ... - ├── Projection-Mix_E08_s2_w3CCE83D85-0912-429E-9F18-716A085BB5BC.tif - ├── Projection-Mix_E08_s2_w3_thumb4D88636E-181E-4AF6-BC53-E7A435959C8F.tif ├── ZStep_1 │   ├── Projection-Mix_E07_s1_w1E78EB128-BD0D-4D94-A6AD-3FF28BB1B105.tif │   ├── Projection-Mix_E07_s1_w1_thumb187DE64B-038A-4671-BF6B-683721723769.tif diff --git a/src/faim_hcs/stitching/DaskTileStitcher.py b/src/faim_hcs/stitching/DaskTileStitcher.py index 25802529..e387e0b5 100644 --- a/src/faim_hcs/stitching/DaskTileStitcher.py +++ b/src/faim_hcs/stitching/DaskTileStitcher.py @@ -21,6 +21,18 @@ def __init__( output_shape: Optional[tuple[int, int, int, int, int]] = None, dtype: np.dtype = np.uint16, ): + """ + Parameters + ---------- + tiles : + Tiles to stitch. + yx_chunk_shape : + Chunk shape in y and x. + output_shape : + Shape of the output image. If None, the shape is computed from the tiles. + dtype : + Data type of the output image. + """ self.tiles: list[Tile] = stitching_utils.shift_to_origin(tiles) self.chunk_shape = ( 1, @@ -96,7 +108,7 @@ def get_stitched_dask_array( Returns ------- - + Dask array of the stitched image. """ func = partial( stitching_utils.assemble_chunk, diff --git a/src/faim_hcs/stitching/stitching_utils.py b/src/faim_hcs/stitching/stitching_utils.py index c6269ac0..de37fd0a 100644 --- a/src/faim_hcs/stitching/stitching_utils.py +++ b/src/faim_hcs/stitching/stitching_utils.py @@ -95,6 +95,24 @@ def fuse_sum(warped_tiles: NDArray, warped_masks: NDArray) -> NDArray: @threadpool_limits.wrap(limits=1, user_api="blas") def translate_tiles_2d(block_info, yx_chunk_shape, dtype, tiles): + """ + Translate tiles to their relative position inside the given block. + + Parameters + ---------- + block_info : + da.map_blocks block_info. + yx_chunk_shape : + shape of the chunk in yx. + dtype : + dtype of the tiles. + tiles : + list of tiles. + + Returns + ------- + translated tiles, translated masks + """ array_location = block_info[None]["array-location"] chunk_yx_origin = np.array([array_location[3][0], array_location[4][0]]) warped_tiles = [] @@ -126,6 +144,26 @@ def translate_tiles_2d(block_info, yx_chunk_shape, dtype, tiles): def assemble_chunk( block_info=None, tile_map=None, warp_func=None, fuse_func=None, dtype=None ): + """ + Assemble a chunk of the stitched image. + + Parameters + ---------- + block_info : + da.map_blocks block_info. + tile_map : + map of block positions to tiles. + warp_func : + function used to warp tiles. + fuse_func : + function used to fuse tiles. + dtype : + tile data type. + + Returns + ------- + fused tiles corresponding to this block/chunk + """ chunk_location = block_info[None]["chunk-location"] chunk_shape = block_info[None]["chunk-shape"] tiles = tile_map[chunk_location]