From 62bc8d47ebb4dc6c07ff36991ea56eab1abbc9f5 Mon Sep 17 00:00:00 2001 From: Dani Bodor Date: Wed, 8 Nov 2023 15:17:45 +0100 Subject: [PATCH 1/3] simplify type checking loop through attributes rather than sending indivudally to helper function. also, allow whole number floats instead for ints --- eitprocessing/roi_selection/gridselection.py | 28 +++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/eitprocessing/roi_selection/gridselection.py b/eitprocessing/roi_selection/gridselection.py index f01e2a12b..cf889927f 100644 --- a/eitprocessing/roi_selection/gridselection.py +++ b/eitprocessing/roi_selection/gridselection.py @@ -4,6 +4,7 @@ from dataclasses import dataclass from dataclasses import field from typing import Literal +from typing import get_type_hints import numpy as np from numpy.typing import NDArray from . import ROISelection @@ -97,29 +98,24 @@ class GridSelection(ROISelection): ignore_nan_rows: bool = True ignore_nan_columns: bool = True - def _check_attribute_type(self, name, type_): - """Checks whether an attribute is an instance of the given type.""" - attr = getattr(self, name) - if not isinstance(attr, type_): - message = f"Invalid type for `{name}`." - message += f"Should be {type_}, not {type(attr)}." - raise TypeError(message) - def __post_init__(self): - self._check_attribute_type("v_split", int) - self._check_attribute_type("h_split", int) + try: + if self.v_split == int(self.v_split): + self.v_split = int(self.v_split) + if self.h_split == int(self.h_split): + self.h_split = int(self.h_split) + finally: + for attr, type_ in get_type_hints(self).items(): + if not isinstance(getattr(self, attr), type_): + raise TypeError( + f"Invalid type for `{attr}`. Should be {type_}, not {type(attr)}." + ) if self.v_split < 1: raise InvalidVerticalDivision("`v_split` can't be smaller than 1.") - if self.h_split < 1: raise InvalidHorizontalDivision("`h_split` can't be smaller than 1.") - self._check_attribute_type("split_columns", bool) - self._check_attribute_type("split_rows", bool) - self._check_attribute_type("ignore_nan_columns", bool) - self._check_attribute_type("ignore_nan_rows", bool) - def find_grid(self, data: NDArray) -> list[NDArray]: """ Create 2D arrays to split a grid into regions. From 4f78ebbe2a213841b5952c965469fe335efba4bd Mon Sep 17 00:00:00 2001 From: Dani Bodor Date: Wed, 8 Nov 2023 16:00:44 +0100 Subject: [PATCH 2/3] docstring example --- eitprocessing/roi_selection/gridselection.py | 46 +++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/eitprocessing/roi_selection/gridselection.py b/eitprocessing/roi_selection/gridselection.py index cf889927f..1a2ccc9c4 100644 --- a/eitprocessing/roi_selection/gridselection.py +++ b/eitprocessing/roi_selection/gridselection.py @@ -58,37 +58,51 @@ class GridSelection(ROISelection): split_columns: Allows columns to be split over two regions. Examples: - >>> pixel_map = array([[ 1, 2, 3], - [ 4, 5, 6], - [ 7, 8, 9], - [10, 11, 12], - [13, 14, 15], - [16, 17, 18]]) - >>> gs = GridSelection(3, 1, split_pixels=False) - >>> matrices = gs.find_grid(pixel_map) - >>> matrices[0] * pixel_map + >>> pixel_map = np.array([[ 1, 2, 3], + [ 4, 5, 6], + [ 7, 8, 9], + [10, 11, 12], + [13, 14, 15], + [16, 17, 18]]) + >>> gs = GridSelection(3, 1, split_rows=False) + >>> rois = gs.find_grid(pixel_map) + >>> gs.matrix_layout() + array([[0], + [1], + [2]]) + >>> rois[0] * pixel_map array([[1, 2, 3], [4, 5, 6], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]) - >>> gs.matrix_layout() - array([[0], - [1], - [2]]) - >>> gs2 = GridSelection(2, 2, split_pixels=True) - >>> matrices2 = gs.find_grid(pixel_map) + >>> rois[1] * pixel_map + array([[0, 0, 0], + [0, 0, 0], + [7, 8, 9], + [10, 11, 12], + [0, 0, 0], + [0, 0, 0]]) + >>> gs2 = GridSelection(2, 2, split_columns=True) + >>> rois2 = gs.find_grid(pixel_map) >>> gs2.matrix_layout() array([[0, 1], [2, 3]]) - >>> matrices2[2] + >>> rois2[2] array([[0. , 0. , 0. ], [0. , 0. , 0. ], [0. , 0. , 0. ], [1. , 0.5, 0. ], [1. , 0.5, 0. ], [1. , 0.5, 0. ]]) + >>> rois2[3] + array([[0. , 0. , 0. ], + [0. , 0. , 0. ], + [0. , 0. , 0. ], + [0. , 0.5, 1. ], + [0. , 0.5, 1. ], + [0. , 0.5, 1. ]]) """ v_split: int From 33905eeaa08ac9d7d261381f062494241a0fb1c0 Mon Sep 17 00:00:00 2001 From: Dani Bodor Date: Wed, 8 Nov 2023 16:44:24 +0100 Subject: [PATCH 3/3] make `matrix_layout` a property --- eitprocessing/roi_selection/gridselection.py | 14 +++++++++----- tests/test_gridselection.py | 5 ++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/eitprocessing/roi_selection/gridselection.py b/eitprocessing/roi_selection/gridselection.py index 1a2ccc9c4..f77028c49 100644 --- a/eitprocessing/roi_selection/gridselection.py +++ b/eitprocessing/roi_selection/gridselection.py @@ -41,8 +41,8 @@ class GridSelection(ROISelection): `split_columns` has the same effect on columns as `split_rows` has on rows. - Regions are ordered according to C indexing order. The `matrix_layout()` method provides a map - showing how the regions are ordered. + Regions are ordered according to C indexing order. The `matrix_layout` attribute provides a map + showing how these regions are ordered. Common grids are pre-defined: - VentralAndDorsal: vertically divided into ventral and dorsal; @@ -66,7 +66,7 @@ class GridSelection(ROISelection): [16, 17, 18]]) >>> gs = GridSelection(3, 1, split_rows=False) >>> rois = gs.find_grid(pixel_map) - >>> gs.matrix_layout() + >>> gs.matrix_layout array([[0], [1], [2]]) @@ -86,7 +86,7 @@ class GridSelection(ROISelection): [0, 0, 0]]) >>> gs2 = GridSelection(2, 2, split_columns=True) >>> rois2 = gs.find_grid(pixel_map) - >>> gs2.matrix_layout() + >>> gs2.matrix_layout array([[0, 1], [2, 3]]) >>> rois2[2] @@ -316,11 +316,15 @@ def _create_grouping_vector_split_pixels( # pylint: disable=too-many-locals return final - def matrix_layout(self) -> NDArray: + @property + def _matrix_layout(self) -> NDArray: """Returns a 2D array showing the layout of the matrices returned by `find_grid`.""" n_regions = self.v_split * self.h_split return np.reshape(np.arange(n_regions), (self.v_split, self.h_split)) + @_matrix_layout.getter # private attribute with getter avoids users overriding this property + def matrix_layout(self): + return self._matrix_layout class InvalidDivision(Exception): diff --git a/tests/test_gridselection.py b/tests/test_gridselection.py index 24f98bdb4..21b5a866b 100644 --- a/tests/test_gridselection.py +++ b/tests/test_gridselection.py @@ -465,7 +465,7 @@ def test_split_pixels_nans(data_string, split_vh, result): ) def test_matrix_layout(split_vh: tuple[int, int], result: list[list[int]]): """ - Test `matrix_layout()` method. + Test `matrix_layout` method. Args: split_vh (tuple[int, int]): `v_split` and `h_split`. @@ -474,6 +474,5 @@ def test_matrix_layout(split_vh: tuple[int, int], result: list[list[int]]): """ gs = GridSelection(*split_vh) - layout = gs.matrix_layout() - assert np.array_equal(layout, np.array(result)) + assert np.array_equal(gs.matrix_layout, np.array(result))