From 525faa2f4709fbd58d11fefca9d0f102142ae597 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 10:49:03 +0100 Subject: [PATCH 01/14] enh: type hinting for bright.py --- dclab/features/bright.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dclab/features/bright.py b/dclab/features/bright.py index f13004c6..cca59eab 100644 --- a/dclab/features/bright.py +++ b/dclab/features/bright.py @@ -3,9 +3,13 @@ RT-DC event image mask. """ import numpy as np +import numpy.typing as npt -def get_bright(mask, image, ret_data="avg,sd"): +def get_bright( + mask: npt.NDArray[np.bool] | list[npt.NDArray[np.bool]], + image: npt.NDArray | list[npt.NDArray], + ret_data: str = "avg,sd"): """Compute avg and/or std of the event brightness The event brightness is defined by the gray-scale values of the From fb0ed0bafa99dad54026830cc8043ea91c682566 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 11:28:42 +0100 Subject: [PATCH 02/14] test, docs: ensure get_bright returns expected types --- dclab/features/bright.py | 7 +++---- tests/test_feat_bright.py | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/dclab/features/bright.py b/dclab/features/bright.py index cca59eab..c5342cfb 100644 --- a/dclab/features/bright.py +++ b/dclab/features/bright.py @@ -6,10 +6,9 @@ import numpy.typing as npt -def get_bright( - mask: npt.NDArray[np.bool] | list[npt.NDArray[np.bool]], - image: npt.NDArray | list[npt.NDArray], - ret_data: str = "avg,sd"): +def get_bright(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], + image: npt.NDArray | list[npt.NDArray], + ret_data: str = "avg,sd") -> float | npt.NDArray: """Compute avg and/or std of the event brightness The event brightness is defined by the gray-scale values of the diff --git a/tests/test_feat_bright.py b/tests/test_feat_bright.py index 0f4a7b4a..79808ba2 100644 --- a/tests/test_feat_bright.py +++ b/tests/test_feat_bright.py @@ -77,3 +77,25 @@ def test_simple_bright(): avg, get_bright(mask=mask, image=image, ret_data="avg")) assert np.allclose( std, get_bright(mask=mask, image=image, ret_data="sd")) + + +def test_list_input_bright(): + """Use the list of np.ndarray as input.""" + pytest.importorskip("nptdms") + ds = new_dataset(retrieve_data("fmt-tdms_fl-image-bright_2017.zip")) + # This stripped dataset has only 7 video frames / contours + image, mask, bright_avg, bright_sd = [], [], [], [] + for ii in range(2, 7): + image.append(ds["image"][ii]) + mask.append(ds["mask"][ii]) + bright_avg.append(ds["bright_avg"][ii]) + bright_sd.append(ds["bright_sd"][ii]) + + avg, std = get_bright(mask=mask, image=image, ret_data="avg,sd") + assert np.allclose(avg, bright_avg) + assert np.allclose(std, bright_sd) + # cover single `ret_data` input + assert np.allclose( + avg, get_bright(mask=mask, image=image, ret_data="avg")) + assert np.allclose( + std, get_bright(mask=mask, image=image, ret_data="sd")) From 1c4d9c18bca1dd8756ff4eb06ab4ed562d84acbe Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 12:01:55 +0100 Subject: [PATCH 03/14] test, docs: ensure get_bright_perc returns expected types --- dclab/features/bright_perc.py | 9 +++++++-- tests/test_feat_bright_perc.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/dclab/features/bright_perc.py b/dclab/features/bright_perc.py index 879ef908..bc5a6b1c 100644 --- a/dclab/features/bright_perc.py +++ b/dclab/features/bright_perc.py @@ -3,9 +3,14 @@ RT-DC event image mask with background-correction taken into account. """ import numpy as np +import numpy.typing as npt -def get_bright_perc(mask, image, image_bg, bg_off=None): +def get_bright_perc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], + image: npt.NDArray | list[npt.NDArray], + image_bg: npt.NDArray | list[npt.NDArray], + bg_off: float | npt.NDArray = None) -> \ + tuple[float, float] | tuple[npt.NDArray, npt.NDArray]: """Compute 10th and 90th percentile of the bg-corrected event brightness The background-corrected event brightness is defined by the @@ -29,7 +34,7 @@ def get_bright_perc(mask, image, image_bg, bg_off=None): ------- bright_perc_10: float or ndarray of size N 10th percentile of brightness - bright_perc_10: float or ndarray of size N + bright_perc_90: float or ndarray of size N 90th percentile of brightness """ if isinstance(mask, np.ndarray) and len(mask.shape) == 2: diff --git a/tests/test_feat_bright_perc.py b/tests/test_feat_bright_perc.py index 970b428e..dd0668bc 100644 --- a/tests/test_feat_bright_perc.py +++ b/tests/test_feat_bright_perc.py @@ -65,11 +65,35 @@ def test_af_brightness_bc_single(): p10 = np.percentile(image_corr[mask], 10) p90 = np.percentile(image_corr[mask], 90) assert np.max(np.abs(image_corr)) < 50, "sanity check" - assert dclab.features.bright_perc.get_bright_perc( + + p10_calc, p90_calc = dclab.features.bright_perc.get_bright_perc( ds["mask"][ii], ds["image"][ii], ds["image_bg"][ii], - ) == (p10, p90) + ) + assert (p10_calc, p90_calc) == (p10, p90) + + +@pytest.mark.filterwarnings( + "ignore::dclab.rtdc_dataset.config.WrongConfigurationTypeWarning") +def test_af_brightness_bc_list(): + path = retrieve_data("fmt-hdf5_image-bg_2020.zip") + ds = dclab.new_dataset(path) + # sanity checks + assert "bright_perc_10" not in ds.features_innate + assert "bright_perc_90" not in ds.features_innate + # ignore first event (no image data) + mask = list(ds["mask"][1:6]) + image = list(ds["image"][1:6]) + image_bg = list(ds["image_bg"][1:6]) + + p10_calc, p90_calc = dclab.features.bright_perc.get_bright_perc( + mask, image, image_bg, + ) + assert isinstance(p10_calc, np.ndarray) + assert isinstance(p90_calc, np.ndarray) + assert p10_calc.shape == (4,) + assert p90_calc.shape == (4,) @pytest.mark.filterwarnings( From 821b4b3bb39dae02bbee8f971f3c28259435c965 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 12:08:47 +0100 Subject: [PATCH 04/14] docs: add futures annotations import for older py versions --- dclab/features/bright.py | 2 ++ dclab/features/bright_bc.py | 9 ++++++++- dclab/features/bright_perc.py | 2 ++ dclab/features/contour.py | 9 ++++++--- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/dclab/features/bright.py b/dclab/features/bright.py index c5342cfb..a5e40931 100644 --- a/dclab/features/bright.py +++ b/dclab/features/bright.py @@ -2,6 +2,8 @@ Computation of mean and standard deviation of grayscale values inside the RT-DC event image mask. """ +from __future__ import annotations + import numpy as np import numpy.typing as npt diff --git a/dclab/features/bright_bc.py b/dclab/features/bright_bc.py index dba8c578..ec99e048 100644 --- a/dclab/features/bright_bc.py +++ b/dclab/features/bright_bc.py @@ -2,10 +2,17 @@ Computation of mean and standard deviation of grayscale values inside the RT-DC event image mask with background-correction taken into account. """ +from __future__ import annotations + import numpy as np +import numpy.typing as npt -def get_bright_bc(mask, image, image_bg, bg_off=None, ret_data="avg,sd"): +def get_bright_bc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], + image: npt.NDArray | list[npt.NDArray], + image_bg: npt.NDArray | list[npt.NDArray], + bg_off: float | npt.NDArray = None, + ret_data: str = "avg,sd"): """Compute avg and/or std of the background-corrected event brightness The background-corrected event brightness is defined by the diff --git a/dclab/features/bright_perc.py b/dclab/features/bright_perc.py index bc5a6b1c..6a9ced56 100644 --- a/dclab/features/bright_perc.py +++ b/dclab/features/bright_perc.py @@ -2,6 +2,8 @@ Computation of the 10th and 90th percentile of grayscale values inside the RT-DC event image mask with background-correction taken into account. """ +from __future__ import annotations + import numpy as np import numpy.typing as npt diff --git a/dclab/features/contour.py b/dclab/features/contour.py index 977b13da..c9e13fec 100644 --- a/dclab/features/contour.py +++ b/dclab/features/contour.py @@ -1,8 +1,11 @@ """Computation of event contour from event mask""" +from __future__ import annotations + from collections import deque import numbers import numpy as np +import numpy.typing as npt # equivalent to # from skimage.measure import find_contours @@ -14,15 +17,15 @@ class NoValidContourFoundError(BaseException): class LazyContourList(object): - def __init__(self, masks, max_events=1000): + def __init__(self, masks: npt.ArrayLike, max_events: int = 1000): """A list-like object that computes contours upon indexing Parameters ---------- - masks: array-like + masks 3D array of masks, may be an HDF5 dataset or any other structure that supports indexing - max_events: int + max_events maximum number of contours to keep in the contour list; set to 0/False/None to cache all contours From 6f92494077aea36054ea8419779f1f273058fcc3 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 14:59:33 +0100 Subject: [PATCH 05/14] docs: add type hints for contour --- dclab/features/bright.py | 7 ++++++- dclab/features/bright_bc.py | 7 ++++++- dclab/features/bright_perc.py | 6 ++++-- dclab/features/contour.py | 11 ++++++----- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/dclab/features/bright.py b/dclab/features/bright.py index a5e40931..9845ac2c 100644 --- a/dclab/features/bright.py +++ b/dclab/features/bright.py @@ -10,7 +10,12 @@ def get_bright(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: npt.NDArray | list[npt.NDArray], - ret_data: str = "avg,sd") -> float | npt.NDArray: + ret_data: str = "avg,sd") -> ( + float | + npt.NDArray | + tuple[float, float] | + tuple[npt.NDArray, npt.NDArray] +): """Compute avg and/or std of the event brightness The event brightness is defined by the gray-scale values of the diff --git a/dclab/features/bright_bc.py b/dclab/features/bright_bc.py index ec99e048..3feb89fd 100644 --- a/dclab/features/bright_bc.py +++ b/dclab/features/bright_bc.py @@ -12,7 +12,12 @@ def get_bright_bc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: npt.NDArray | list[npt.NDArray], image_bg: npt.NDArray | list[npt.NDArray], bg_off: float | npt.NDArray = None, - ret_data: str = "avg,sd"): + ret_data: str = "avg,sd") -> ( + float | + npt.NDArray | + tuple[float, float] | + tuple[npt.NDArray, npt.NDArray] +): """Compute avg and/or std of the background-corrected event brightness The background-corrected event brightness is defined by the diff --git a/dclab/features/bright_perc.py b/dclab/features/bright_perc.py index 6a9ced56..0fdc2c8e 100644 --- a/dclab/features/bright_perc.py +++ b/dclab/features/bright_perc.py @@ -11,8 +11,10 @@ def get_bright_perc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: npt.NDArray | list[npt.NDArray], image_bg: npt.NDArray | list[npt.NDArray], - bg_off: float | npt.NDArray = None) -> \ - tuple[float, float] | tuple[npt.NDArray, npt.NDArray]: + bg_off: float | npt.NDArray = None) -> ( + tuple[float, float] | + tuple[npt.NDArray, npt.NDArray] +): """Compute 10th and 90th percentile of the bg-corrected event brightness The background-corrected event brightness is defined by the diff --git a/dclab/features/contour.py b/dclab/features/contour.py index c9e13fec..b24a937d 100644 --- a/dclab/features/contour.py +++ b/dclab/features/contour.py @@ -17,7 +17,7 @@ class NoValidContourFoundError(BaseException): class LazyContourList(object): - def __init__(self, masks: npt.ArrayLike, max_events: int = 1000): + def __init__(self, masks: npt.ArrayLike, max_events: int = 1000) -> None: """A list-like object that computes contours upon indexing Parameters @@ -43,7 +43,7 @@ def __init__(self, masks: npt.ArrayLike, max_events: int = 1000): self.identifier = str(masks[0][:].tobytes()) self.shape = len(masks), np.nan, 2 - def __getitem__(self, idx): + def __getitem__(self, idx) -> npt.NDArray: """Compute contour(s) if not already in self.contours""" if not isinstance(idx, numbers.Integral): # slicing! @@ -77,7 +77,7 @@ def __len__(self): return len(self.masks) -def get_contour(mask): +def get_contour(mask: npt.NDArray[bool]) -> npt.NDArray | list[npt.NDArray]: """Compute the image contour from a mask The contour is computed in a very inefficient way using scikit-image @@ -130,7 +130,8 @@ def get_contour(mask): return contours[0] -def get_contour_lazily(mask): +def get_contour_lazily(mask: npt.NDArray[bool]) -> \ + npt.NDArray | LazyContourList: """Like :func:`get_contour`, but computes contours on demand Parameters @@ -156,7 +157,7 @@ def get_contour_lazily(mask): return cont -def remove_duplicates(cont): +def remove_duplicates(cont: npt.NDArray) -> npt.NDArray: """Remove duplicates in a circular contour""" x = np.resize(cont, (len(cont) + 1, 2)) selection = np.ones(len(x), dtype=bool) From 63cdca8fd7ba6b5d955157e451793ba3d9317df4 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 15:37:35 +0100 Subject: [PATCH 06/14] docs type hints for fl_crosstalk --- dclab/features/fl_crosstalk.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dclab/features/fl_crosstalk.py b/dclab/features/fl_crosstalk.py index 87937c9e..c4db8127 100644 --- a/dclab/features/fl_crosstalk.py +++ b/dclab/features/fl_crosstalk.py @@ -1,9 +1,13 @@ """Crosstalk-correction for fluorescence data""" +from __future__ import annotations import numpy as np +import numpy.typing as npt -def get_compensation_matrix(ct21, ct31, ct12, ct32, ct13, ct23): +def get_compensation_matrix( + ct21: float, ct31: float, ct12: float, + ct32: float, ct13: float, ct23: float) -> npt.NDArray: """Compute crosstalk inversion matrix The spillover matrix is @@ -55,8 +59,13 @@ def get_compensation_matrix(ct21, ct31, ct12, ct32, ct13, ct23): return np.linalg.inv(crosstalk) -def correct_crosstalk(fl1, fl2, fl3, fl_channel, - ct21=0, ct31=0, ct12=0, ct32=0, ct13=0, ct23=0): +def correct_crosstalk( + fl1: int | float | npt.NDArray, + fl2: int | float | npt.NDArray, + fl3: int | float | npt.NDArray, + fl_channel: int, + ct21: float = 0, ct31: float = 0, ct12: float = 0, + ct32: float = 0, ct13: float = 0, ct23: float = 0) -> npt.NDArray: """Perform crosstalk correction Parameters From a2862a302a1917a0e50327dc0498f795f29c94df Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 15:52:49 +0100 Subject: [PATCH 07/14] docs: type hints for volume and inert_ratio --- dclab/features/inert_ratio.py | 21 ++++++++++++++------- dclab/features/volume.py | 22 +++++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/dclab/features/inert_ratio.py b/dclab/features/inert_ratio.py index b5a7db81..a70b7b29 100644 --- a/dclab/features/inert_ratio.py +++ b/dclab/features/inert_ratio.py @@ -1,11 +1,14 @@ """Computation of inertia ratio from contour data""" +from __future__ import annotations + import numpy as np +import numpy.typing as npt import scipy.spatial as ssp -def cont_moments_cv(cont, - flt_epsilon=1.19209e-07, - dbl_epsilon=2.2204460492503131e-16): +def cont_moments_cv(cont: npt.NDArray, + flt_epsilon: float = 1.19209e-07, + dbl_epsilon: float = 2.2204460492503131e-16) -> dict: """Compute the moments of a contour The moments are computed in the same way as they are computed @@ -120,7 +123,8 @@ def cont_moments_cv(cont, return None -def get_inert_ratio_cvx(cont): +def get_inert_ratio_cvx( + cont: npt.NDArray | list[npt.NDArray]) -> float | npt.NDArray: """Compute the inertia ratio of the convex hull of a contour The inertia ratio is computed from the central second order of moments @@ -190,7 +194,8 @@ def get_inert_ratio_cvx(cont): return inert_ratio_cvx -def get_inert_ratio_prnc(cont): +def get_inert_ratio_prnc( + cont: npt.NDArray | list[npt.NDArray]) -> float | npt.NDArray: """Compute principal inertia ratio of a contour The principal inertia ratio is rotation-invariant, which @@ -256,7 +261,8 @@ def get_inert_ratio_prnc(cont): return inert_ratio_prnc -def get_inert_ratio_raw(cont): +def get_inert_ratio_raw( + cont: npt.NDArray | list[npt.NDArray]) -> float | npt.NDArray: """Compute the inertia ratio of a contour The inertia ratio is computed from the central second order of moments @@ -321,7 +327,8 @@ def get_inert_ratio_raw(cont): return inert_ratio_raw -def get_tilt(cont): +def get_tilt( + cont: npt.NDArray | list[npt.NDArray]) -> float | npt.NDArray: """Compute tilt of raw contour relative to channel axis Parameters diff --git a/dclab/features/volume.py b/dclab/features/volume.py index b4fa904a..873b859c 100644 --- a/dclab/features/volume.py +++ b/dclab/features/volume.py @@ -1,8 +1,16 @@ """Volume computation based on contour revolution""" +from __future__ import annotations + import numpy as np +import numpy.typing as npt -def get_volume(cont, pos_x, pos_y, pix, fix_orientation=False): +def get_volume( + cont: npt.NDArray | list[npt.NDArray], + pos_x: float | npt.NDArray, + pos_y: float | npt.NDArray, + pix: float, + fix_orientation: bool = False) -> float | npt.NDArray: """Calculate the volume of a polygon revolved around an axis The volume estimation assumes rotational symmetry. @@ -43,7 +51,7 @@ def get_volume(cont, pos_x, pos_y, pix, fix_orientation=False): upper and the lower halves of the contour from which the average is then used. - The volume is computed radially from the the center position + The volume is computed radially from the center position given by (`pos_x`, `pos_y`). For sufficiently smooth contours, such as densely sampled ellipses, the center position does not play an important role. For contours that are given on a coarse @@ -125,7 +133,7 @@ def get_volume(cont, pos_x, pos_y, pix, fix_orientation=False): return v_avg -def counter_clockwise(cx, cy): +def counter_clockwise(cx: npt.NDArray, cy: npt.NDArray) -> float: """Put contour coordinates into counter-clockwise order Parameters @@ -152,7 +160,7 @@ def counter_clockwise(cx, cy): return cx, cy -def vol_revolve(r, z, point_scale=1.): +def vol_revolve(r: npt.NDArray, z: npt.NDArray, point_scale: float = 1.): r"""Calculate the volume of a polygon revolved around the Z-axis This implementation yields the same results as the volRevolve @@ -222,9 +230,9 @@ def vol_revolve(r, z, point_scale=1.): # dr = R - r and dz = h, then we get three terms for the volume # (as opposed to four terms in Olynyk's script). Those three terms # all resemble area slices multiplied by the z-distance dz. - a1 = 3 * rp**2 - a2 = 3 * rp*dr - a3 = dr**2 + a1 = 3 * rp ** 2 + a2 = 3 * rp * dr + a3 = dr ** 2 # Note that the formula for computing the volume is symmetric # with respect to r and R. This means that it does not matter From c695331c5f937702d7928b9891eaaf6689d7b74f Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 16:06:17 +0100 Subject: [PATCH 08/14] docs: add type hints to emodulus load --- dclab/features/emodulus/load.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dclab/features/emodulus/load.py b/dclab/features/emodulus/load.py index 68992cfc..94e5daa9 100644 --- a/dclab/features/emodulus/load.py +++ b/dclab/features/emodulus/load.py @@ -12,6 +12,7 @@ import warnings import numpy as np +import numpy.typing as npt from ... import definitions as dfn @@ -24,7 +25,7 @@ @functools.lru_cache() -def get_internal_lut_names_dict(): +def get_internal_lut_names_dict() -> dict: """Return list of internal lut names""" lutfiles = {} for pp in importlib_resources.files('dclab.features.emodulus').iterdir(): @@ -34,7 +35,7 @@ def get_internal_lut_names_dict(): return lutfiles -def get_lut_path(path_or_id): +def get_lut_path(path_or_id: str | pathlib.Path) -> pathlib.Path: """Find the path to a LUT path_or_id: str or pathlib.Path @@ -63,7 +64,8 @@ def get_lut_path(path_or_id): return lut_path -def load_lut(lut_data: str | pathlib.Path | np.ndarray = "LE-2D-FEM-19"): +def load_lut(lut_data: str | pathlib.Path | tuple[npt.NDArray, dict] = + "LE-2D-FEM-19") -> tuple[npt.NDArray, dict]: """Load LUT data from disk Parameters @@ -98,7 +100,7 @@ def load_lut(lut_data: str | pathlib.Path | np.ndarray = "LE-2D-FEM-19"): return lut, meta -def load_mtext(path): +def load_mtext(path: str | pathlib.Path) -> tuple[npt.NDArray, dict]: """Load column-based data from text files with metadata This file format is used for isoelasticity lines and look-up @@ -217,7 +219,7 @@ def load_mtext(path): return data, meta -def register_lut(path, identifier=None): +def register_lut(path: str | pathlib.Path, identifier: str = None) -> None: """Register an external LUT file in dclab This will add it to :const:`EXTERNAL_LUTS`, which is required From ea1ad64c1fe27aaa53e338f711a224c93de4ddad Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Tue, 26 Nov 2024 16:15:40 +0100 Subject: [PATCH 09/14] docs: type hints for emod pxcorr --- dclab/features/emodulus/pxcorr.py | 39 ++++++++++++++++++++----------- tests/test_feat_emodulus.py | 9 ++++++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/dclab/features/emodulus/pxcorr.py b/dclab/features/emodulus/pxcorr.py index e4b33af5..a430ef2f 100644 --- a/dclab/features/emodulus/pxcorr.py +++ b/dclab/features/emodulus/pxcorr.py @@ -1,9 +1,12 @@ """Pixelation correction definitions""" +from __future__ import annotations import numpy as np +import numpy.typing as npt -def corr_deform_with_area_um(area_um, px_um=0.34): +def corr_deform_with_area_um(area_um: float | npt.NDArray, + px_um: float = 0.34) -> float | npt.NDArray: """Deformation correction for area_um-deform data The contour in RT-DC measurements is computed on a @@ -14,14 +17,14 @@ def corr_deform_with_area_um(area_um, px_um=0.34): Parameters ---------- - area_um: float or ndarray + area_um Apparent (2D image) area in µm² of the event(s) - px_um: float + px_um The detector pixel size in µm. Returns ------- - deform_delta: float or ndarray + deform_delta Error of the deformation of the event(s) that must be subtracted from `deform`. deform_corr = deform - deform_delta @@ -46,7 +49,8 @@ def corr_deform_with_area_um(area_um, px_um=0.34): return delta -def corr_deform_with_volume(volume, px_um=0.34): +def corr_deform_with_volume(volume: float | npt.NDArray, + px_um: float = 0.34) -> float | npt.NDArray: """Deformation correction for volume-deform data The contour in RT-DC measurements is computed on a @@ -57,14 +61,14 @@ def corr_deform_with_volume(volume, px_um=0.34): Parameters ---------- - volume: float or ndarray + volume The "volume" feature (rotation of raw contour) [µm³] - px_um: float + px_um The detector pixel size in µm. Returns ------- - deform_delta: float or ndarray + deform_delta Error of the deformation of the event(s) that must be subtracted from `deform`. deform_corr = deform - deform_delta @@ -78,7 +82,13 @@ def corr_deform_with_volume(volume, px_um=0.34): return delta -def get_pixelation_delta_pair(feat1, feat2, data1, data2, px_um=0.34): +def get_pixelation_delta_pair( + feat1: str, + feat2: str, + data1: float | npt.NDArray, + data2: float | npt.NDArray, + px_um: float = 0.34) -> (tuple[float, float] | + tuple[npt.NDArray, npt.NDArray]): """Convenience function that returns pixelation correction pair""" # determine feature that defines abscissa feat_absc = feat1 if feat1 in ["area_um", "volume"] else feat2 @@ -97,17 +107,20 @@ def get_pixelation_delta_pair(feat1, feat2, data1, data2, px_um=0.34): return delt1, delt2 -def get_pixelation_delta(feat_corr, feat_absc, data_absc, px_um=0.34): +def get_pixelation_delta(feat_corr: str, + feat_absc: str, + data_absc: float | npt.NDArray, + px_um: float = 0.34) -> float | npt.NDArray: """Convenience function for obtaining pixelation correction Parameters ---------- - feat_corr: str + feat_corr Feature for which to compute the pixelation correction (e.g. "deform") - feat_absc: str + feat_absc Feature with which to compute the correction (e.g. "area_um"); - data_absc: ndarray or float + data_absc Corresponding data for `feat_absc` px_um: float Detector pixel size [µm] diff --git a/tests/test_feat_emodulus.py b/tests/test_feat_emodulus.py index 922ba0ad..31ee8d08 100644 --- a/tests/test_feat_emodulus.py +++ b/tests/test_feat_emodulus.py @@ -298,7 +298,6 @@ def test_af_emodulus_temp_feat_with_basin(): ) with dclab.new_dataset(path) as ds: - ds.config["calculation"] = {"emodulus lut": "LE-2D-FEM-19", "emodulus viscosity model": "herold-2017", "emodulus medium": "CellCarrier", @@ -585,6 +584,14 @@ def test_pixelation_correction_volume(): assert np.allclose(ddelt, 0.011464479831134636) +def test_pixelation_correction_volume_ndarray_input(): + ddelt = emodulus.get_pixelation_delta(feat_corr="deform", + feat_absc="volume", + data_absc=np.array([100, 100, 90]), + px_um=0.34) + assert np.allclose(ddelt, np.array([0.01146448, 0.01146448, 0.01199665])) + + def test_register_external_lut(): """Load an external LUT and compute YM data""" identifier = "test-test_register_external_lut" From 392b57cd9bf606d850b7817ffb1e7e43cd1303c9 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Wed, 27 Nov 2024 11:08:56 +0100 Subject: [PATCH 10/14] docs: add type hints for emod __init__ functions --- dclab/features/emodulus/__init__.py | 58 ++++++++++++++++------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/dclab/features/emodulus/__init__.py b/dclab/features/emodulus/__init__.py index c4767972..b6cc9a2b 100644 --- a/dclab/features/emodulus/__init__.py +++ b/dclab/features/emodulus/__init__.py @@ -7,6 +7,7 @@ import warnings import numpy as np +import numpy.typing as npt import scipy.interpolate as spint from ...warn import PipelineWarning @@ -18,7 +19,6 @@ from .scale_linear import scale_emodulus, scale_feature from .viscosity import get_viscosity - #: Set this to True to globally enable spline extrapolation when the #: `area_um`/`deform` data are outside the LUT. This is discouraged and #: a :class:`KnowWhatYouAreDoingWarning` warning will be issued. @@ -33,8 +33,13 @@ class YoungsModulusLookupTableExceededWarning(PipelineWarning): pass -def extrapolate_emodulus(lut, datax, deform, emod, deform_norm, - deform_thresh=.05, inplace=True): +def extrapolate_emodulus(lut: npt.NDArray, + datax: npt.NDArray, + deform: npt.NDArray, + emod: npt.NDArray, + deform_norm: float, + deform_thresh: float = .05, + inplace: bool = True) -> npt.NDArray: """Use spline interpolation to fill in nan-values When points (`datax`, `deform`) are outside the convex @@ -56,21 +61,21 @@ def extrapolate_emodulus(lut, datax, deform, emod, deform_norm, points, second axis enumerates datax, deform, and emodulus) datax: ndarray of size N The normalized x data (corresponding to `lut[:, 0]`) - deform: ndarray of size N - The normalized deform (corresponding to `lut[:, 1]`) emod: ndarray of size N The emodulus (corresponding to `lut[:, 2]`); If `emod` does not contain nan-values, there is nothing to do here. - deform_norm: float + deform: ndarray of size N + The normalized deform (corresponding to `lut[:, 1]`) + deform_norm The normalization value used to normalize `lut[:, 1]` and `deform`. - deform_thresh: float + deform_thresh Not the entire LUT is used for bivariate spline interpolation. Only the points where `lut[:, 1] > deform_thresh/deform_norm` are used. This is necessary, because for small deformations, the LUT has an extreme slope that kills any meaningful spline interpolation. - inplace: bool + inplace If True (default), replaces nan values in `emod` in-place. If False, `emod` is not modified. """ @@ -99,48 +104,49 @@ def extrapolate_emodulus(lut, datax, deform, emod, deform_norm, return emod -def get_emodulus(deform: float | np.array, - area_um: float | np.array | None = None, - volume: float | np.array | None = None, +def get_emodulus(deform: float | npt.NDArray, + area_um: float | npt.NDArray | None = None, + volume: float | npt.NDArray | None = None, medium: float | str = "0.49% MC-PBS", channel_width: float = 20.0, flow_rate: float = 0.16, px_um: float = 0.34, - temperature: float | np.ndarray | None = 23.0, - lut_data: str | pathlib.Path | np.ndarray = "LE-2D-FEM-19", + temperature: float | npt.NDArray | None = 23.0, + lut_data: (str | pathlib.Path | + tuple[npt.NDArray, dict]) = "LE-2D-FEM-19", visc_model: Literal['herold-2017', 'herold-2017-fallback', 'buyukurganci-2022', 'kestin-1978', None] = "herold-2017-fallback", extrapolate: bool = INACCURATE_SPLINE_EXTRAPOLATION, - copy: bool = True): + copy: bool = True) -> npt.NDArray: """Compute apparent Young's modulus using a look-up table Parameters ---------- - area_um: float or ndarray + area_um Apparent (2D image) area [µm²] of the event(s) - deform: float or ndarray + deform Deformation (1-circularity) of the event(s) - volume: float or ndarray + volume Apparent volume of the event(s). It is not possible to define `volume` and `area_um` at the same time (makes no sense). .. versionadded:: 0.25.0 - medium: str or float + medium The medium to compute the viscosity for. If a string is given, the viscosity is computed. If a float is given, this value is used as the viscosity in mPa*s (Note that `temperature` and `visc_model` must be set to None in this case). - channel_width: float + channel_width The channel width [µm] - flow_rate: float + flow_rate Flow rate [µL/s] - px_um: float + px_um The detector pixel size [µm] used for pixelation correction. Set to zero to disable. - temperature: float, ndarray, or None + temperature Temperature [°C] of the event(s) lut_data: path, str, or tuple of (np.ndarray of shape (N, 3), dict) The LUT data to use. If it is a built-in identifier, @@ -150,13 +156,13 @@ def get_emodulus(deform: float | np.array, (e.g. `area_um` and `deform`) are valid interpolation choices. .. versionadded:: 0.25.0 - visc_model: str + visc_model The viscosity model to use, see :func:`dclab.features.emodulus.viscosity.get_viscosity` - extrapolate: bool + extrapolate Perform extrapolation using :func:`extrapolate_emodulus`. This is discouraged! - copy: bool + copy Copy input arrays. If set to false, input arrays are overridden. @@ -326,7 +332,7 @@ def get_emodulus(deform: float | np.array, return emod -def normalize(data, dmax): +def normalize(data: npt.NDArray, dmax: float) -> npt.NDArray: """Perform normalization in-place for interpolation Note that :func:`scipy.interpolate.griddata` has a `rescale` From 35bdbd843fe1374f7f509311012b316267090fce Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Wed, 27 Nov 2024 11:39:03 +0100 Subject: [PATCH 11/14] docs: add type hints for emod scale_linear --- dclab/features/emodulus/scale_linear.py | 129 ++++++++++++++---------- 1 file changed, 78 insertions(+), 51 deletions(-) diff --git a/dclab/features/emodulus/scale_linear.py b/dclab/features/emodulus/scale_linear.py index c0128898..41dee13a 100644 --- a/dclab/features/emodulus/scale_linear.py +++ b/dclab/features/emodulus/scale_linear.py @@ -1,47 +1,60 @@ """Scale conversion applicable to a linear elastic model""" +from __future__ import annotations import warnings import numpy as np - - -def convert(area_um, deform, channel_width_in, channel_width_out, - emodulus=None, flow_rate_in=None, flow_rate_out=None, - viscosity_in=None, viscosity_out=None, inplace=False): +import numpy.typing as npt + + +def convert(area_um: npt.NDArray, + deform: npt.NDArray, + channel_width_in: float, + channel_width_out: float, + emodulus: npt.NDArray = None, + flow_rate_in: float = None, + flow_rate_out: float = None, + viscosity_in: float = None, + viscosity_out: float | npt.NDArray = None, + inplace: bool = False + ) -> ( + tuple[npt.NDArray, npt.NDArray] | + tuple[npt.NDArray, npt.NDArray, npt.NDArray] +): """convert area-deformation-emodulus triplet The conversion formula is described in :cite:`Mietke2015`. Parameters ---------- - area_um: ndarray + area_um Convex cell area [µm²] - deform: ndarray + deform Deformation - channel_width_in: float + channel_width_in Original channel width [µm] - channel_width_out: float + channel_width_out Target channel width [µm] - emodulus: ndarray + emodulus Young's Modulus [kPa] - flow_rate_in: float + flow_rate_in Original flow rate [µL/s] - flow_rate_out: float + flow_rate_out Target flow rate [µL/s] - viscosity_in: float + viscosity_in Original viscosity [mPa*s] - viscosity_out: float or ndarray + viscosity_out Target viscosity [mPa*s]; This can be an array - inplace: bool + inplace If True, override input arrays with corrected data Returns ------- - area_um_corr: ndarray + area_um_corr Corrected cell area [µm²] - deform_corr: ndarray + deform_corr Deformation (a copy if `inplace` is False) - emodulus_corr: ndarray + emodulus_corr Corrected emodulus [kPa]; only returned if `emodulus` is given. Notes @@ -81,8 +94,11 @@ def convert(area_um, deform, channel_width_in, channel_width_out, return area_um_corr, deform_corr, emodulus_corr -def scale_area_um(area_um, channel_width_in, channel_width_out, inplace=False, - **kwargs): +def scale_area_um(area_um: npt.NDArray, + channel_width_in: float, + channel_width_out: float, + inplace: bool = False, + **kwargs) -> npt.NDArray: """Perform scale conversion for area_um (linear elastic model) The area scales with the characteristic length @@ -94,20 +110,20 @@ def scale_area_um(area_um, channel_width_in, channel_width_out, inplace=False, Parameters ---------- - area_um: ndarray + area_um Convex area [µm²] - channel_width_in: float + channel_width_in Original channel width [µm] - channel_width_out: float + channel_width_out Target channel width [µm] - inplace: bool + inplace If True, override input arrays with corrected data - kwargs: + kwargs not used Returns ------- - area_um_corr: ndarray + area_um_corr Scaled area [µm²] """ copy = not inplace @@ -120,9 +136,14 @@ def scale_area_um(area_um, channel_width_in, channel_width_out, inplace=False, return area_um_corr -def scale_emodulus(emodulus, channel_width_in, channel_width_out, - flow_rate_in, flow_rate_out, viscosity_in, - viscosity_out, inplace=False): +def scale_emodulus(emodulus: npt.NDArray, + channel_width_in: float, + channel_width_out: float, + flow_rate_in: float, + flow_rate_out: float, + viscosity_in: float, + viscosity_out: float | npt.NDArray, + inplace: bool = False) -> npt.NDArray: """Perform scale conversion for area_um (linear elastic model) The conversion formula is described in :cite:`Mietke2015`. @@ -131,26 +152,26 @@ def scale_emodulus(emodulus, channel_width_in, channel_width_out, Parameters ---------- - emodulus: ndarray + emodulus Young's Modulus [kPa] - channel_width_in: float + channel_width_in Original channel width [µm] - channel_width_out: float + channel_width_out Target channel width [µm] - flow_rate_in: float + flow_rate_in Original flow rate [µL/s] - flow_rate_out: float + flow_rate_out Target flow rate [µL/s] - viscosity_in: float + viscosity_in Original viscosity [mPa*s] - viscosity_out: float or ndarray + viscosity_out Target viscosity [mPa*s]; This can be an array - inplace: bool + inplace If True, override input arrays with corrected data Returns ------- - emodulus_corr: ndarray + emodulus_corr Scaled emodulus [kPa] """ copy = not inplace @@ -182,7 +203,10 @@ def scale_emodulus(emodulus, channel_width_in, channel_width_out, return emodulus_corr -def scale_feature(feat, data, inplace=False, **scale_kw): +def scale_feature(feat: str, + data: float | npt.NDArray, + inplace: bool = False, + **scale_kw) -> npt.NDArray: """Convenience function for scale conversions (linear elastic model) This method wraps around all the other scale_* methods and also @@ -190,13 +214,13 @@ def scale_feature(feat, data, inplace=False, **scale_kw): Parameters ---------- - feat: str + feat Valid scalar feature name - data: float or ndarray + data Feature data - inplace: bool + inplace If True, override input arrays with corrected data - **scale_kw: + **scale_kw Scale keyword arguments for the wrapped methods """ if feat == "area_um": @@ -212,8 +236,11 @@ def scale_feature(feat, data, inplace=False, **scale_kw): raise KeyError("No recipe to scale feature '{}'!".format(feat)) -def scale_volume(volume, channel_width_in, channel_width_out, inplace=False, - **kwargs): +def scale_volume(volume: npt.NDArray, + channel_width_in: float, + channel_width_out: float, + inplace: bool = False, + **kwargs) -> npt.NDArray: """Perform scale conversion for volume (linear elastic model) The volume scales with the characteristic length @@ -223,20 +250,20 @@ def scale_volume(volume, channel_width_in, channel_width_out, inplace=False, Parameters ---------- - volume: ndarray + volume Volume [µm³] - channel_width_in: float + channel_width_in Original channel width [µm] - channel_width_out: float + channel_width_out Target channel width [µm] - inplace: bool + inplace If True, override input arrays with corrected data - kwargs: + kwargs not used Returns ------- - volume_corr: ndarray + volume_corr Scaled volume [µm³] """ copy = not inplace From 63905bf70ec5eff4b193fd482332bf1c24259472 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Wed, 27 Nov 2024 11:52:48 +0100 Subject: [PATCH 12/14] docs: add type hints for emod viscosity --- dclab/features/emodulus/viscosity.py | 50 +++++++++++++++++----------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/dclab/features/emodulus/viscosity.py b/dclab/features/emodulus/viscosity.py index 40353a5a..23e3299b 100644 --- a/dclab/features/emodulus/viscosity.py +++ b/dclab/features/emodulus/viscosity.py @@ -5,6 +5,7 @@ import warnings import numpy as np +import numpy.typing as npt from ...warn import PipelineWarning @@ -45,10 +46,17 @@ class TemperatureOutOfRangeWarning(PipelineWarning): def check_temperature(model: str, - temperature: float | np.array, + temperature: float | npt.NDArray, tmin: float, - tmax: float): - """Raise a TemperatureOutOfRangeWarning if applicable""" + tmax: float) -> None: + """Raise a TemperatureOutOfRangeWarning if applicable + + Raises + ------ + TemperatureOutOfRangeWarning + If the given temperature is out of the given range. + + """ if np.min(temperature) < tmin or np.max(temperature) > tmax: warnings.warn( f"For the {model} model, the temperature should be " @@ -60,11 +68,12 @@ def check_temperature(model: str, def get_viscosity(medium: str = "0.49% MC-PBS", channel_width: float = 20.0, flow_rate: float = 0.16, - temperature: float | np.ndarray = 23.0, + temperature: float | npt.NDArray = 23.0, model: Literal['herold-2017', 'herold-2017-fallback', 'buyukurganci-2022', - 'kestin-1978'] = 'herold-2017-fallback'): + 'kestin-1978'] = 'herold-2017-fallback' + ) -> float | npt.NDArray: """Returns the viscosity for RT-DC-specific media Media that are not pure (e.g. ketchup or polymer solutions) @@ -83,16 +92,16 @@ def get_viscosity(medium: str = "0.49% MC-PBS", Parameters ---------- - medium: str + medium The medium to compute the viscosity for; Valid values are defined in :const:`KNOWN_MEDIA`. - channel_width: float + channel_width The channel width in µm - flow_rate: float + flow_rate Flow rate in µL/s - temperature: float or ndarray + temperature Temperature in °C - model: str + model The model name to use for computing the medium viscosity. For water, this value is ignored, as there is only the 'kestin-1978' model :cite:`Kestin_1978`. For MC-PBS media, @@ -101,7 +110,7 @@ def get_viscosity(medium: str = "0.49% MC-PBS", Returns ------- - viscosity: float or ndarray + viscosity Viscosity in mPa*s Notes @@ -148,21 +157,23 @@ def get_viscosity(medium: str = "0.49% MC-PBS", return eta -def shear_rate_square_channel(flow_rate, channel_width, flow_index): +def shear_rate_square_channel(flow_rate: float, + channel_width: float, + flow_index: float) -> float: """Returns The wall shear rate of a power law liquid in a squared channel. Parameters ---------- - flow_rate: float + flow_rate Flow rate in µL/s - channel_width: float + channel_width The channel width in µm - flow_index: float + flow_index Flow behavior index aka the power law exponent of the shear thinning Returns ------- - shear_rate: float + shear_rate Shear rate in 1/s. """ # convert channel width to mm @@ -176,7 +187,7 @@ def get_viscosity_mc_pbs_buyukurganci_2022( "0.83% MC-PBS"] = "0.49% MC-PBS", channel_width: float = 20.0, flow_rate: float = 0.16, - temperature: float = 23.0): + temperature: float = 23.0) -> float | npt.NDArray: """Compute viscosity of MC-PBS according to :cite:`Buyukurganci2022` This viscosity model was derived in :cite:`Buyukurganci2022` @@ -211,7 +222,7 @@ def get_viscosity_mc_pbs_herold_2017( medium: Literal["0.49% MC-PBS", "0.59% MC-PBS"] = "0.49% MC-PBS", channel_width: float = 20.0, flow_rate: float = 0.16, - temperature: float = 23.0): + temperature: float = 23.0) -> float | npt.NDArray: r"""Compute viscosity of MC-PBS according to :cite:`Herold2017` Note that all the factors in equation 5.2 in :cite:`Herold2017` @@ -242,7 +253,8 @@ def get_viscosity_mc_pbs_herold_2017( return eta -def get_viscosity_water_kestin_1978(temperature: float = 23.0): +def get_viscosity_water_kestin_1978( + temperature: float = 23.0) -> float | npt.NDArray: """Compute the viscosity of water according to :cite:`Kestin_1978`""" # see equation (15) in Kestin et al, J. Phys. Chem. 7(3) 1978 check_temperature("'kestin-1978' water", temperature, 0, 40) From e49eba0366533c620a4a9399413f4c25b38fc230 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Wed, 27 Nov 2024 16:36:53 +0100 Subject: [PATCH 13/14] ref: docstrings - remove duplicate info but keep array shape info --- dclab/features/bright.py | 13 ++++++------- dclab/features/bright_bc.py | 13 ++++++------- dclab/features/bright_perc.py | 7 +++---- dclab/features/fl_crosstalk.py | 14 +++++++------- dclab/features/inert_ratio.py | 8 ++++---- dclab/features/volume.py | 22 ++++++++++++---------- 6 files changed, 38 insertions(+), 39 deletions(-) diff --git a/dclab/features/bright.py b/dclab/features/bright.py index 9845ac2c..221af38d 100644 --- a/dclab/features/bright.py +++ b/dclab/features/bright.py @@ -10,12 +10,11 @@ def get_bright(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: npt.NDArray | list[npt.NDArray], - ret_data: str = "avg,sd") -> ( - float | - npt.NDArray | - tuple[float, float] | - tuple[npt.NDArray, npt.NDArray] -): + ret_data: str = "avg,sd" + ) -> (float | + npt.NDArray | + tuple[float, float] | + tuple[npt.NDArray, npt.NDArray]): """Compute avg and/or std of the event brightness The event brightness is defined by the gray-scale values of the @@ -28,7 +27,7 @@ def get_bright(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: ndarray or list of ndarrays of shape (M,N) A 2D array that holds the image in form of grayscale values of an event. - ret_data: str + ret_data A comma-separated list of metrices to compute - "avg": compute the average - "sd": compute the standard deviation diff --git a/dclab/features/bright_bc.py b/dclab/features/bright_bc.py index 3feb89fd..59b8ef97 100644 --- a/dclab/features/bright_bc.py +++ b/dclab/features/bright_bc.py @@ -12,12 +12,11 @@ def get_bright_bc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: npt.NDArray | list[npt.NDArray], image_bg: npt.NDArray | list[npt.NDArray], bg_off: float | npt.NDArray = None, - ret_data: str = "avg,sd") -> ( - float | - npt.NDArray | - tuple[float, float] | - tuple[npt.NDArray, npt.NDArray] -): + ret_data: str = "avg,sd" + ) -> (float | + npt.NDArray | + tuple[float, float] | + tuple[npt.NDArray, npt.NDArray]): """Compute avg and/or std of the background-corrected event brightness The background-corrected event brightness is defined by the @@ -36,7 +35,7 @@ def get_bright_bc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], bg_off: float or 1D ndarray Additional offset value that is added to `image_bg` before background correction - ret_data: str + ret_data A comma-separated list of metrices to compute - "avg": compute the average - "sd": compute the standard deviation diff --git a/dclab/features/bright_perc.py b/dclab/features/bright_perc.py index 0fdc2c8e..f7d267cd 100644 --- a/dclab/features/bright_perc.py +++ b/dclab/features/bright_perc.py @@ -11,10 +11,9 @@ def get_bright_perc(mask: npt.NDArray[bool] | list[npt.NDArray[bool]], image: npt.NDArray | list[npt.NDArray], image_bg: npt.NDArray | list[npt.NDArray], - bg_off: float | npt.NDArray = None) -> ( - tuple[float, float] | - tuple[npt.NDArray, npt.NDArray] -): + bg_off: float | npt.NDArray = None + ) -> (tuple[float, float] | + tuple[npt.NDArray, npt.NDArray]): """Compute 10th and 90th percentile of the bg-corrected event brightness The background-corrected event brightness is defined by the diff --git a/dclab/features/fl_crosstalk.py b/dclab/features/fl_crosstalk.py index c4db8127..fa6dee67 100644 --- a/dclab/features/fl_crosstalk.py +++ b/dclab/features/fl_crosstalk.py @@ -22,12 +22,12 @@ def get_compensation_matrix( Parameters ---------- - cij: float + cij Spill from channel i to channel j Returns ------- - inv: np.ndarray + inv Compensation matrix (inverted spillover matrix) """ ct11 = 1 @@ -70,12 +70,12 @@ def correct_crosstalk( Parameters ---------- - fli: int, float, or np.ndarray + fli Measured fluorescence signals - fl_channel: int (1, 2, or 3) - The channel number for which the crosstalk-corrected signal - should be computed - cij: float + fl_channel + The channel number (1, 2, or 3) for which the crosstalk-corrected + signal should be computed + cij Spill (crosstalk or bleed-through) from channel i to channel j This spill is computed from the fluorescence signal of e.g. single-stained positive control cells; It is defined by the diff --git a/dclab/features/inert_ratio.py b/dclab/features/inert_ratio.py index a70b7b29..a895716f 100644 --- a/dclab/features/inert_ratio.py +++ b/dclab/features/inert_ratio.py @@ -16,11 +16,11 @@ def cont_moments_cv(cont: npt.NDArray, Parameters ---------- - cont: array of shape (N,2) + cont: shape (N,2) The contour for which to compute the moments. - flt_epsilon: float + flt_epsilon The value of ``FLT_EPSILON`` in OpenCV/gcc. - dbl_epsilon: float + dbl_epsilon The value of ``DBL_EPSILON`` in OpenCV/gcc. .. versionchanged:: 0.48.2 @@ -31,7 +31,7 @@ def cont_moments_cv(cont: npt.NDArray, Returns ------- - moments: dict + moments A dictionary of moments. If the moment `m00` is smaller than half of `flt_epsilon`, `None` is returned. """ diff --git a/dclab/features/volume.py b/dclab/features/volume.py index 873b859c..b441e641 100644 --- a/dclab/features/volume.py +++ b/dclab/features/volume.py @@ -28,10 +28,10 @@ def get_volume( pos_y: float or ndarray of length N The y coordinate(s) of the centroid of the event(s) [µm] e.g. obtained using `mm.pos_y` - pix: float + pix The detector pixel size in µm. e.g. obtained using: `mm.config["imaging"]["pixel size"]` - fix_orientation: bool + fix_orientation If set to True, make sure that the orientation of the contour is counter-clockwise in the r-z plane (see :func:`vol_revolve`). This is False by default, because @@ -42,7 +42,7 @@ def get_volume( Returns ------- - volume: float or ndarray + volume volume in um^3 Notes @@ -133,17 +133,17 @@ def get_volume( return v_avg -def counter_clockwise(cx: npt.NDArray, cy: npt.NDArray) -> float: +def counter_clockwise(cx: npt.NDArray, cy: npt.NDArray) -> tuple[float, float]: """Put contour coordinates into counter-clockwise order Parameters ---------- - cx, cy: 1d ndarrays + cx, cy The x- and y-coordinates of the contour Returns ------- - cx_cc, cy_cc: + cx_cc, cy_cc The x- and y-coordinates of the contour in counter-clockwise orientation. @@ -160,7 +160,9 @@ def counter_clockwise(cx: npt.NDArray, cy: npt.NDArray) -> float: return cx, cy -def vol_revolve(r: npt.NDArray, z: npt.NDArray, point_scale: float = 1.): +def vol_revolve(r: npt.NDArray, + z: npt.NDArray, + point_scale: float = 1.) -> float | npt.NDArray: r"""Calculate the volume of a polygon revolved around the Z-axis This implementation yields the same results as the volRevolve @@ -191,11 +193,11 @@ def vol_revolve(r: npt.NDArray, z: npt.NDArray, point_scale: float = 1.): Parameters ---------- - r: 1d np.ndarray + r radial coordinates (perpendicular to the z axis) - z: 1d np.ndarray + z coordinate along the axis of rotation - point_scale: float + point_scale point size in your preferred units; The volume is multiplied by a factor of `point_scale**3`. From 4d48eabb8a5d8cc0bf5eccd04eb86afcdb090b89 Mon Sep 17 00:00:00 2001 From: Eoghan O'Connell Date: Thu, 28 Nov 2024 15:45:12 +0100 Subject: [PATCH 14/14] updated CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index c583b896..06dbe365 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ 0.62.7 + - docs: type hinted the features sub-module - fix: IntegrityChecker must not load basins - tests: avoid architecture and Python-version dependent test 0.62.6