Skip to content

Commit 511012f

Browse files
committed
refactor: improved log message and doc of methods in WSI, refactored and typing in utils functions
1 parent 32c337d commit 511012f

File tree

4 files changed

+44
-41
lines changed

4 files changed

+44
-41
lines changed

src/prismtoolbox/utils/data_utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
from __future__ import annotations
2+
from typing import Any
23

34
import json
45
import pickle
5-
from typing import Any, Tuple
6-
76
import geopandas as gpd
87
import h5py
98
import numpy as np
@@ -57,7 +56,7 @@ def load_obj_with_json(file_path: str) -> Any:
5756
return json.load(f)
5857

5958

60-
def read_h5_file(file_path: str, key: str) -> Tuple[np.ndarray, dict]:
59+
def read_h5_file(file_path: str, key: str) -> tuple[np.ndarray, dict]:
6160
"""Read an object from a h5 file.
6261
6362
Args:

src/prismtoolbox/utils/qupath_utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
import logging
44
import os
55
import uuid
6-
from typing import List, Optional, Tuple, Union
76

87
import numpy as np
98
from shapely import MultiPolygon, Polygon, box
109
from shapely.affinity import translate
11-
from shapely.geometry import mapping, shape
10+
from shapely.geometry import mapping
1211
from shapely.ops import unary_union
1312

1413
from .data_utils import load_obj_with_json, read_json_with_geopandas, save_obj_with_json
@@ -204,7 +203,7 @@ def patchesToPolygons(
204203
patches: np.ndarray,
205204
patch_size: int,
206205
patch_downsample: int,
207-
merge: Optional[bool] = False,
206+
merge: bool = False,
208207
) -> MultiPolygon:
209208
"""Converts patches to shapely polygons.
210209

src/prismtoolbox/utils/torch_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
from typing import Any
23

34
import logging
45
import os
@@ -251,7 +252,7 @@ def get_torchvision_transforms() -> dict[str, transformsv2.Transform]:
251252
**get_torchvision_transforms(),
252253
}
253254

254-
def create_transforms(transforms_dict: dict[str, dict[str, any]]) -> transformsv2.Compose:
255+
def create_transforms(transforms_dict: dict[str, dict[str, Any]]) -> transformsv2.Compose:
255256
"""Create a torchvision.transforms.Compose object from a dictionary of transforms.
256257
257258
Args:

src/prismtoolbox/wsicore/wsi.py

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,19 @@ def __init__(self, slide_path: str, engine: str = "openslide"):
7777
Set by the [set_slide_attributes][prismtoolbox.wsicore.WSI.set_slide_attributes] method.
7878
offset (tuple[int, int]): The offset of the slide image.
7979
Set by the [set_slide_attributes][prismtoolbox.wsicore.WSI.set_slide_attributes] method.
80-
ROI (ndarray): The region of interest in the slide image.
80+
ROI (ndarray | None): The region of interest in the slide image.
8181
Please use the [set_roi][prismtoolbox.wsicore.WSI.set_roi] method to set the ROI.
82-
ROI_width (int): The width of the region of interest.
82+
ROI_width (int | None): The width of the region of interest.
8383
Set by the [set_roi][prismtoolbox.wsicore.WSI.set_roi] method.
84-
ROI_height (int): The height of the region of interest.
84+
ROI_height (int | None): The height of the region of interest.
8585
Set by the [set_roi][prismtoolbox.wsicore.WSI.set_roi] method.
86-
tissue_contours (list[ndarray]): The contours of the tissue in the slide image.
86+
tissue_contours (list[ndarray] | None): The contours of the tissue in the slide image.
8787
Please use the [detect_tissue][prismtoolbox.wsicore.WSI.detect_tissue]
8888
method to detect the tissue contours.
89-
coords (np.ndarray): The coordinates of patches extracted from slide image.
89+
coords (np.ndarray | None): The coordinates of patches extracted from slide image.
9090
Please use the [extract_patches][prismtoolbox.wsicore.WSI.extract_patches]
9191
method to extract patches.
92-
coords_attrs (dict): The attributes of the coordinates.
92+
coords_attrs (dict | None): The attributes of the coordinates.
9393
Set by the [extract_patches][prismtoolbox.wsicore.WSI.extract_patches] method.
9494
"""
9595
self.slide_path = slide_path
@@ -304,7 +304,7 @@ def convert_units(
304304
elif from_unit == to_unit:
305305
pass
306306
else:
307-
raise ValueError(f"Conversion from {from_unit} to {to_unit} not supported")
307+
raise ValueError(f"Conversion from {from_unit} to {to_unit} not supported.")
308308
return value
309309

310310
def save_tissue_contours(
@@ -346,13 +346,13 @@ def save_tissue_contours(
346346
if file_format == "pickle":
347347
file_path = os.path.join(save_dir, f"{self.slide_name}.pkl")
348348
log.info(
349-
f"Saving tissue contours for slide {self.slide_name} at {file_path} with pickle."
349+
f"Saving tissue contours for slide {self.slide_name} at {file_path} as pickle file."
350350
)
351351
save_obj_with_pickle(tissue_contours, file_path)
352352
elif file_format == "geojson":
353353
file_path = os.path.join(save_dir, f"{self.slide_name}.geojson")
354354
log.info(
355-
f"Saving {selected_idx} tissue contours for slide {self.slide_name} at {file_path} with geojson."
355+
f"Saving {selected_idx} tissue contours for slide {self.slide_name} at {file_path} as geojson file."
356356
)
357357
polygons = contoursToPolygons(tissue_contours, merge, make_valid)
358358
export_polygons_to_qupath(
@@ -418,7 +418,7 @@ def save_patches(
418418
attr_dict = {"coords": self.coords_attrs}
419419
file_path = os.path.join(save_dir, f"{self.slide_name}.h5")
420420
log.info(
421-
f"Saving patches for slide {self.slide_name} at {file_path} with hdf5."
421+
f"Saving patches for slide {self.slide_name} at {file_path} as h5 file."
422422
)
423423
save_patches_with_hdf5(file_path, asset_dict, attr_dict)
424424
elif file_format == "geojson":
@@ -430,7 +430,7 @@ def save_patches(
430430
coords, self.coords_attrs["patch_size"], patch_downsample, merge
431431
)
432432
log.info(
433-
f"Saving {len(coords)} patches for slide {self.slide_name} at {file_path} with geojson."
433+
f"Saving {len(coords)} patches for slide {self.slide_name} at {file_path} as geojson file."
434434
)
435435
export_polygons_to_qupath(
436436
polygons,
@@ -457,7 +457,7 @@ def save_patches(
457457
).convert("RGB")
458458
patch.save(os.path.join(save_dir, f"{coord[0]}_{coord[1]}.{file_format}"))
459459
else:
460-
raise ValueError(f"format {file_format} not supported")
460+
raise ValueError(f"Format {file_format} not supported.")
461461

462462
def load_patches(self, file_path: str) -> None:
463463
"""Load the patches from a hdf5 file.
@@ -481,7 +481,7 @@ def set_slide_attributes(self):
481481
self.level_downsamples = self.slide.level_downsamples
482482
self.properties = self.slide.properties
483483
else:
484-
raise NotImplementedError(f"engine {self.engine} not supported")
484+
raise NotImplementedError(f"Engine {self.engine} not supported.")
485485
if (
486486
f"{self.engine}.bounds-x" in self.properties.keys()
487487
and self.properties[f"{self.engine}.bounds-x"] is not None
@@ -578,7 +578,7 @@ def set_roi(
578578
self.ROI = ROI
579579
self.ROI_width = ROI[2] - ROI[0]
580580
self.ROI_height = ROI[3] - ROI[1]
581-
print(f"ROI for slide {self.slide_name} has been set to {self.ROI}.")
581+
log.info(f"ROI for slide {self.slide_name} has been set to {self.ROI}.")
582582
return ROI
583583

584584
def detect_tissue(
@@ -622,8 +622,9 @@ def detect_tissue(
622622
final_contours.append(contour)
623623
if len(final_contours) == 0:
624624
self.tissue_contours = []
625-
print(f"No contours found for slide {self.slide_name}.")
626-
return
625+
log.warning(
626+
f"No tissue contours found for the slide {self.slide_name}."
627+
)
627628
else:
628629
scale = self.level_downsamples[seg_level]
629630
offset = np.array(self.ROI[:2]) if self.ROI is not None else np.array([0, 0])
@@ -638,10 +639,10 @@ def detect_tissue(
638639
]
639640
)
640641
self.tissue_contours = final_contours
641-
print(
642-
f"Identified {len(final_contours)} contours for slide {self.slide_name}."
642+
log.info(
643+
f"Identified {len(final_contours)} contours for the slide {self.slide_name}."
643644
)
644-
return
645+
return
645646

646647
def apply_pathologist_annotations(
647648
self,
@@ -792,15 +793,18 @@ def extract_patches(
792793
"level_dim": self.level_dimensions[patch_level],
793794
"name": self.slide_name,
794795
}
795-
796+
796797
if len(valid_coords) == 0:
797-
log.info(f"No valid coordinates found for slide {self.slide_name}.")
798+
log.warning(
799+
f"No valid coordinates found for the slide {self.slide_name}."
800+
)
798801
else:
799-
print(
800-
f"Identified a total of {len(valid_coords)} valid coordinates in the slide {self.slide_name}."
802+
log.info(
803+
f"Identified a total of {len(valid_coords)} valid coordinates for the slide {self.slide_name}."
801804
)
802-
self.coords = valid_coords
803-
self.coords_attrs = attr
805+
806+
self.coords = valid_coords
807+
self.coords_attrs = attr
804808

805809
def extract_patches_roi(
806810
self,
@@ -847,7 +851,7 @@ def extract_patches_roi(
847851
if coord_candidates is None:
848852
if roi_dim is None or step_size is None:
849853
raise ValueError(
850-
"roi_dim and step_size must be provided if coord_candidates is not set"
854+
"roi_dim and step_size must be provided if coord_candidates is not set."
851855
)
852856
start_x, start_y, w, h = roi_dim
853857

@@ -872,7 +876,7 @@ def extract_patches_roi(
872876
if contour is not None:
873877
if contours_mode is None:
874878
raise ValueError(
875-
"A contour mode must be provided if patch extraction mode is set to contours"
879+
"A contour mode must be provided if patch extraction mode is set to contours."
876880
)
877881
cont_check_fn = IsInContour(
878882
contour, patch_size=ref_patch_size, center_shift=0.5, mode=contours_mode
@@ -953,7 +957,7 @@ def visualize(
953957
if not view_slide_only:
954958
if self.tissue_contours is None:
955959
raise RuntimeError(
956-
"No tissue contours found for the slide, please run the detect_tissue method first"
960+
f"No tissue contours found for the slide {self.slide_name}, please run the detect_tissue method first."
957961
)
958962
if crop_roi:
959963
if self.ROI is None:
@@ -1046,11 +1050,11 @@ def stitch(
10461050
"""
10471051
if self.coords_attrs is None:
10481052
raise RuntimeError(
1049-
"No attributes set for the patches of the slide, please check if patches were correctly extracted."
1053+
f"No attributes set for the patches of the slide {self.slide_name}, please check if patches were correctly extracted."
10501054
)
10511055
assert self.coords is not None, (
1052-
"no coordinates provided for the patches to visualize, please run the "
1053-
"extract_patches method first or load the coordinates from a file"
1056+
"No coordinates provided for the patches to visualize, please run the "
1057+
"extract_patches method first or load the coordinates from a file."
10541058
)
10551059
if crop_roi:
10561060
if self.ROI is None or self.ROI_width is None or self.ROI_height is None:
@@ -1099,8 +1103,8 @@ def stitch(
10991103
)
11001104
if colors is not None:
11011105
assert len(colors) == len(idxs), (
1102-
"the number of colors provided must match "
1103-
"the number of selected coordinates"
1106+
"The number of colors provided must match "
1107+
"the number of selected coordinates."
11041108
)
11051109
color = colors[idx]
11061110
color_patch = (
@@ -1129,4 +1133,4 @@ def stitch(
11291133
return img
11301134

11311135
def __repr__(self):
1132-
return f"WSI({self.slide_path}, {self.engine}) with level {self.level_dimensions}"
1136+
return f"WSI({self.slide_path}, {self.engine}) with levels {self.level_dimensions}."

0 commit comments

Comments
 (0)