From 5a34adef7bf876b43a730acb1623471347d35c81 Mon Sep 17 00:00:00 2001 From: Wim Pomp Date: Mon, 20 Nov 2023 14:47:47 +0100 Subject: [PATCH] - Slicing bugfix. - Sort imports. - Make sitk-elastix optional again. --- README.md | 1 - ndbioimage/__init__.py | 3 ++- ndbioimage/jvm.py | 2 +- ndbioimage/readers/__init__.py | 1 + ndbioimage/readers/bfread.py | 5 +++-- ndbioimage/readers/cziread.py | 10 ++++++---- ndbioimage/readers/fijiread.py | 6 ++++-- ndbioimage/readers/ndread.py | 8 +++++--- ndbioimage/readers/seqread.py | 14 ++++++++------ ndbioimage/readers/tifread.py | 10 ++++++---- ndbioimage/transforms.py | 34 +++++++++++++++++++++++----------- pyproject.toml | 5 ++++- tests/test_open.py | 5 +++-- tests/test_slicing.py | 23 +++++++++++++++++++++++ tests/test_ufuncs.py | 6 +++--- 15 files changed, 92 insertions(+), 41 deletions(-) create mode 100644 tests/test_slicing.py diff --git a/README.md b/README.md index 1617bed..24fc65c 100644 --- a/README.md +++ b/README.md @@ -77,4 +77,3 @@ for example: any file handles # TODO - more image formats -- re-implement transforms diff --git a/ndbioimage/__init__.py b/ndbioimage/__init__.py index 4b39ff3..3bfe301 100755 --- a/ndbioimage/__init__.py +++ b/ndbioimage/__init__.py @@ -277,7 +277,8 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC): new_slice.append(s[e]) # TODO: check output dimensionality when requested shape in some dimension is 1 - if all([isinstance(s, Number) or s.size == 1 for s in new_slice]): + if (all([isinstance(s, Number) for s in new_slice[:len(self.axes)]]) + and all([isinstance(s, Number) or s.size == 1 for s in new_slice[len(self.axes):]])): return self.block(*new_slice).item() else: new = View(self) diff --git a/ndbioimage/jvm.py b/ndbioimage/jvm.py index 85ecacf..0230caa 100644 --- a/ndbioimage/jvm.py +++ b/ndbioimage/jvm.py @@ -36,9 +36,9 @@ try: try: import jpype.imports from loci.common import DebugTools # noqa - from loci.formats import ImageReader # noqa from loci.formats import ChannelSeparator # noqa from loci.formats import FormatTools # noqa + from loci.formats import ImageReader # noqa from loci.formats import MetadataTools # noqa DebugTools.setRootLevel("ERROR") diff --git a/ndbioimage/readers/__init__.py b/ndbioimage/readers/__init__.py index 4546d51..b632126 100644 --- a/ndbioimage/readers/__init__.py +++ b/ndbioimage/readers/__init__.py @@ -1,3 +1,4 @@ from pathlib import Path + __all__ = [file.stem for file in Path(__file__).parent.iterdir() if file.suffix == ".py" and not file == Path(__file__) and not file.stem.startswith('.')] diff --git a/ndbioimage/readers/bfread.py b/ndbioimage/readers/bfread.py index dc62689..fca41b6 100644 --- a/ndbioimage/readers/bfread.py +++ b/ndbioimage/readers/bfread.py @@ -1,10 +1,11 @@ import multiprocessing -import numpy as np from abc import ABC from multiprocessing import queues from traceback import print_exc -from .. import AbstractReader, JVM +import numpy as np + +from .. import JVM, AbstractReader jars = {'bioformats_package.jar': 'https://downloads.openmicroscopy.org/bio-formats/latest/artifacts/bioformats_package.jar'} diff --git a/ndbioimage/readers/cziread.py b/ndbioimage/readers/cziread.py index 9bb540f..a2eb426 100644 --- a/ndbioimage/readers/cziread.py +++ b/ndbioimage/readers/cziread.py @@ -1,12 +1,14 @@ -import czifile -import numpy as np import re -from lxml import etree -from ome_types import model from abc import ABC from functools import cached_property from itertools import product from pathlib import Path + +import czifile +import numpy as np +from lxml import etree +from ome_types import model + from .. import AbstractReader diff --git a/ndbioimage/readers/fijiread.py b/ndbioimage/readers/fijiread.py index 3d513fd..5534b7a 100644 --- a/ndbioimage/readers/fijiread.py +++ b/ndbioimage/readers/fijiread.py @@ -1,12 +1,14 @@ from abc import ABC -from tifffile import TiffFile from functools import cached_property from itertools import product -from ome_types import model from pathlib import Path from struct import unpack from warnings import warn + import numpy as np +from ome_types import model +from tifffile import TiffFile + from .. import AbstractReader diff --git a/ndbioimage/readers/ndread.py b/ndbioimage/readers/ndread.py index 9c64525..717f9bc 100644 --- a/ndbioimage/readers/ndread.py +++ b/ndbioimage/readers/ndread.py @@ -1,9 +1,11 @@ +from abc import ABC +from functools import cached_property +from itertools import product + import numpy as np from ome_types import model -from functools import cached_property -from abc import ABC + from .. import AbstractReader -from itertools import product class Reader(AbstractReader, ABC): diff --git a/ndbioimage/readers/seqread.py b/ndbioimage/readers/seqread.py index 07971a4..7b9f57e 100644 --- a/ndbioimage/readers/seqread.py +++ b/ndbioimage/readers/seqread.py @@ -1,13 +1,15 @@ +import re +from abc import ABC +from datetime import datetime +from functools import cached_property +from itertools import product +from pathlib import Path + import tifffile import yaml -import re -from pathlib import Path -from functools import cached_property from ome_types import model from ome_types.units import _quantity_property # noqa -from itertools import product -from datetime import datetime -from abc import ABC + from .. import AbstractReader diff --git a/ndbioimage/readers/tifread.py b/ndbioimage/readers/tifread.py index 6ea2934..69ae39a 100644 --- a/ndbioimage/readers/tifread.py +++ b/ndbioimage/readers/tifread.py @@ -1,11 +1,13 @@ +from abc import ABC +from functools import cached_property +from itertools import product +from pathlib import Path + import numpy as np import tifffile import yaml -from abc import ABC -from functools import cached_property from ome_types import model -from pathlib import Path -from itertools import product + from .. import AbstractReader diff --git a/ndbioimage/transforms.py b/ndbioimage/transforms.py index 15c1df7..3a3d603 100644 --- a/ndbioimage/transforms.py +++ b/ndbioimage/transforms.py @@ -4,7 +4,7 @@ from pathlib import Path import numpy as np import yaml -from parfor import pmap, Chunks +from parfor import Chunks, pmap from skimage import filters from tiffwrite import IJTiffFile from tqdm.auto import tqdm @@ -255,9 +255,9 @@ class Transforms(dict): class Transform: def __init__(self): if sitk is None: - raise ImportError('SimpleElastix is not installed: ' - 'https://simpleelastix.readthedocs.io/GettingStarted.html') - self.transform = sitk.ReadTransform(str(Path(__file__).parent / 'transform.txt')) + self.transform = None + else: + self.transform = sitk.ReadTransform(str(Path(__file__).parent / 'transform.txt')) self.dparameters = [0., 0., 0., 0., 0., 0.] self.shape = [512., 512.] self.origin = [255.5, 255.5] @@ -275,6 +275,9 @@ class Transform: @classmethod def register(cls, fix, mov, kind=None): """ kind: 'affine', 'translation', 'rigid' """ + if sitk is None: + raise ImportError('SimpleElastix is not installed: ' + 'https://simpleelastix.readthedocs.io/GettingStarted.html') new = cls() kind = kind or 'affine' new.shape = fix.shape @@ -342,7 +345,7 @@ class Transform: @staticmethod def cast_image(im): - if not isinstance(im, sitk.Image): + if isinstance(im, sitk.Image): im = sitk.GetImageFromArray(im) return im @@ -376,24 +379,30 @@ class Transform: @property def parameters(self): - return list(self.transform.GetParameters()) + if self.transform is not None: + return list(self.transform.GetParameters()) @parameters.setter def parameters(self, value): - value = np.asarray(value) - self.transform.SetParameters(value.tolist()) + if self.transform is not None: + value = np.asarray(value) + self.transform.SetParameters(value.tolist()) @property def origin(self): - return self.transform.GetFixedParameters() + if self.transform is not None: + return self.transform.GetFixedParameters() @origin.setter def origin(self, value): - value = np.asarray(value) - self.transform.SetFixedParameters(value.tolist()) + if self.transform is not None: + value = np.asarray(value) + self.transform.SetFixedParameters(value.tolist()) @property def inverse(self): + if self.is_unity(): + return self if self._last is None or self._last != self.asdict(): self._last = self.asdict() self._inverse = Transform.from_dict(self.asdict()) @@ -414,6 +423,9 @@ class Transform: if self.is_unity(): return im else: + if sitk is None: + raise ImportError('SimpleElastix is not installed: ' + 'https://simpleelastix.readthedocs.io/GettingStarted.html') dtype = im.dtype im = im.astype('float') intp = sitk.sitkBSpline if np.issubdtype(dtype, np.floating) else sitk.sitkNearestNeighbor diff --git a/pyproject.toml b/pyproject.toml index 9282498..b4970e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ndbioimage" -version = "2023.10.3" +version = "2023.11.0" description = "Bio image reading, metadata and some affine registration." authors = ["W. Pomp "] license = "GPLv3" @@ -34,6 +34,9 @@ test = ["pytest-xdist"] [tool.poetry.scripts] ndbioimage = "ndbioimage:main" +[tool.pytest.ini_options] +filterwarnings = ["ignore:::(colorcet)"] + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/tests/test_open.py b/tests/test_open.py index ea1e0e3..b88e19c 100644 --- a/tests/test_open.py +++ b/tests/test_open.py @@ -1,7 +1,8 @@ import pickle -import pytest -from pathlib import Path from multiprocessing import active_children +from pathlib import Path + +import pytest from ndbioimage import Imread, ReaderNotFoundError diff --git a/tests/test_slicing.py b/tests/test_slicing.py new file mode 100644 index 0000000..f69f38f --- /dev/null +++ b/tests/test_slicing.py @@ -0,0 +1,23 @@ +from itertools import combinations_with_replacement +from numbers import Number + +import numpy as np +import pytest +from ndbioimage import Imread + +r = np.random.randint(0, 255, (64, 64, 2, 3, 4)) +im = Imread(r) +a = np.array(im) + + +@pytest.mark.parametrize('s', combinations_with_replacement( + (0, -1, 1, slice(None), slice(0, 1), slice(-1, 0), slice(1, 1)), 5)) +def test_slicing(s): + s_im, s_a = im[s], a[s] + if isinstance(s_a, Number): + assert isinstance(s_im, Number) + assert s_im == s_a + else: + assert isinstance(s_im, Imread) + assert s_im.shape == s_a.shape + assert np.all(s_im == s_a) diff --git a/tests/test_ufuncs.py b/tests/test_ufuncs.py index 1825f20..a492f1e 100644 --- a/tests/test_ufuncs.py +++ b/tests/test_ufuncs.py @@ -1,8 +1,8 @@ -import pytest -import numpy as np -from ndbioimage import Imread from itertools import product +import numpy as np +import pytest +from ndbioimage import Imread r = np.random.randint(0, 255, (64, 64, 2, 3, 4)) im = Imread(r)