impy-array 2.4.1__py3-none-any.whl → 2.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
impy/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "2.4.1"
1
+ __version__ = "2.4.3"
2
2
  __author__ = "Hanjin Liu"
3
3
  __email__ = "liuhanjin-sc@g.ecc.u-tokyo.ac.jp"
4
4
 
impy/arrays/_imshow.py CHANGED
@@ -177,4 +177,33 @@ def _imshow_matplotlib(self: LabeledArray, label, dims, **kwargs) -> LabeledArra
177
177
  def _imshow_ipywidgets(arr: LabeledArray, label: bool, dims, **kwargs) -> LabeledArray:
178
178
  from ipywidgets import interact
179
179
 
180
- raise NotImplementedError()
180
+ raise NotImplementedError()
181
+
182
+ @register("ndv")
183
+ def _imshow_ndv(self: LabeledArray, label: bool, dims, **kwargs) -> LabeledArray:
184
+ from ndv import NDViewer
185
+
186
+ app, should_exec = _get_app()
187
+ if "c" in self.axes:
188
+ channel_axis = self.axes.index("c")
189
+ else:
190
+ channel_axis = None
191
+ viewer = NDViewer(self, channel_axis=channel_axis)
192
+ viewer.show()
193
+ if should_exec:
194
+ app.exec()
195
+ return self
196
+
197
+ def _get_app():
198
+ # ported from ndv
199
+ import sys
200
+ from qtpy.QtWidgets import QApplication
201
+
202
+ is_ipython = False
203
+ if (app := QApplication.instance()) is None:
204
+ app = QApplication([])
205
+ app.setApplicationName("ndv")
206
+ elif (ipy := sys.modules.get("IPython")) and (shell := ipy.get_ipython()):
207
+ is_ipython = str(shell.active_eventloop).startswith("qt")
208
+
209
+ return app, not is_ipython
@@ -130,4 +130,4 @@ def check_glcm(self, bins, rescale_max):
130
130
  raise ValueError(f"`bins` must be a divisor of {imax+1} (max value of {self.dtype}).")
131
131
  self = self // ((imax+1) // bins)
132
132
 
133
- return self, bins, rescale_max
133
+ return self, bins, rescale_max
@@ -37,4 +37,4 @@ def ball_like_odd(radius, ndim):
37
37
  l = xc*2 + 1
38
38
  coords = xp.indices((l,)*ndim)
39
39
  s = xp.sum((a-xc)**2 for a in coords)
40
- return xp.array(s <= radius*radius, dtype=bool)
40
+ return xp.array(s <= radius*radius, dtype=bool)
@@ -119,7 +119,7 @@ class MetaArray(AxesMixin, np.ndarray):
119
119
  return self.axes.tuple(super().shape)
120
120
 
121
121
  def __getitem__(self, key: SupportSlicing) -> Self:
122
- key = slicer.solve_slicer(key, self.axes)
122
+ key = slicer.solve_slicer(key, self.axes, self.shape)
123
123
 
124
124
  if isinstance(key, np.ndarray):
125
125
  key = self._broadcast(key)
@@ -133,7 +133,7 @@ class MetaArray(AxesMixin, np.ndarray):
133
133
  return out
134
134
 
135
135
  def __setitem__(self, key: SupportSlicing, value):
136
- key = slicer.solve_slicer(key, self.axes)
136
+ key = slicer.solve_slicer(key, self.axes, self.shape)
137
137
 
138
138
  if isinstance(key, MetaArray) and key.dtype == bool:
139
139
  key = axesop.add_axes(self.axes, self.shape, key, key.axes)
@@ -181,7 +181,7 @@ class MetaArray(AxesMixin, np.ndarray):
181
181
  if indexer is not None:
182
182
  kwargs.update(indexer)
183
183
 
184
- key = slicer.solve_slicer(kwargs, self.axes)
184
+ key = slicer.solve_slicer(kwargs, self.axes, self.shape)
185
185
  out = super().__getitem__(key) # get item as np.ndarray
186
186
 
187
187
  if isinstance(out, self.__class__): # cannot set attribution to such as numpy.int32
impy/arrays/imgarray.py CHANGED
@@ -6,13 +6,13 @@ from functools import partial
6
6
  from scipy import ndimage as ndi
7
7
  from typing import TYPE_CHECKING, Literal, Sequence, Iterable, Callable, overload, Any
8
8
 
9
- from .labeledarray import LabeledArray
10
- from .label import Label
11
- from .phasearray import PhaseArray
12
- from .specials import PropArray
13
- from .tiled import TiledAccessor
9
+ from impy.arrays.labeledarray import LabeledArray
10
+ from impy.arrays.label import Label
11
+ from impy.arrays.phasearray import PhaseArray
12
+ from impy.arrays.specials import PropArray
13
+ from impy.arrays.tiled import TiledAccessor
14
14
 
15
- from ._utils import _filters, _linalg, _deconv, _misc, _glcm, _docs, _transform, _structures, _corr
15
+ from impy.arrays._utils import _filters, _linalg, _deconv, _misc, _glcm, _docs, _transform, _structures, _corr
16
16
 
17
17
  from impy.arrays.bases.metaarray import _NoValue
18
18
  from impy.utils.axesop import add_axes, switch_slice, complement_axes, find_first_appeared
@@ -217,6 +217,44 @@ class ImgArray(LabeledArray):
217
217
  c_axes=complement_axes(dims, self.axes),
218
218
  kwargs=dict(matrix=mx, order=order, mode=mode, cval=cval),
219
219
  )
220
+
221
+ @_docs.write_docs
222
+ @dims_to_spatial_axes
223
+ @same_dtype(asfloat=True)
224
+ @check_input_and_output
225
+ def shift(
226
+ self, translation, order: int = 3, mode: PaddingMode = "constant",
227
+ cval: float = 0, prefilter: bool | None = None, dims: Dims = None,
228
+ update: bool = False,
229
+ ) -> ImgArray:
230
+ """
231
+ 2D stretching of an image from a point.
232
+
233
+ Parameters
234
+ ----------
235
+ translation : array-like
236
+ Translation in pixels. Must match the length of spatial dimensions.
237
+ {mode}{cval}{dims}{order}
238
+
239
+ Returns
240
+ -------
241
+ ImgArray
242
+ Stretched image.
243
+ """
244
+ if isinstance(cval, str) and hasattr(np, cval):
245
+ cval = getattr(np, cval)(self.value)
246
+ elif callable(cval):
247
+ cval = cval(self.value)
248
+
249
+ prefilter = prefilter or order > 1
250
+ mtx = _transform.compose_affine_matrix(translation=translation)
251
+
252
+ return self._apply_dask(
253
+ _transform.warp,
254
+ c_axes=complement_axes(dims, self.axes),
255
+ kwargs=dict(matrix=mtx, order=order, mode=mode, cval=cval,
256
+ prefilter=prefilter)
257
+ )
220
258
 
221
259
  @_docs.write_docs
222
260
  @dims_to_spatial_axes
@@ -2836,7 +2874,7 @@ class ImgArray(LabeledArray):
2836
2874
  if key is None:
2837
2875
  slices = (slice(None),) * ndim
2838
2876
  else:
2839
- slices = solve_slicer(key, Axes(dims))
2877
+ slices = solve_slicer(key, Axes(dims), self.shape)
2840
2878
  dtype = np.complex128 if double_precision else np.complex64
2841
2879
 
2842
2880
  # Calculate exp(-ikx)
@@ -3957,8 +3995,8 @@ class ImgArray(LabeledArray):
3957
3995
  @check_input_and_output
3958
3996
  def drift_correction(
3959
3997
  self,
3960
- shift: Coords = None,
3961
- ref: ImgArray = None,
3998
+ shift: Coords | None = None,
3999
+ ref: ImgArray | Any | None = None,
3962
4000
  *,
3963
4001
  zero_ave: bool = True,
3964
4002
  along: AxisLike | None = None,
@@ -3977,8 +4015,10 @@ class ImgArray(LabeledArray):
3977
4015
  shift : DataFrame or (N, D) array, optional
3978
4016
  Translation vectors. If DataFrame, it must have columns named with all the symbols
3979
4017
  contained in ``dims``.
3980
- ref : ImgArray, optional
3981
- The reference n-D image to determine drift, if ``shift`` was not given.
4018
+ ref : ImgArray or slicer, optional
4019
+ The reference n-D image to determine drift, if ``shift`` was not given. This
4020
+ parameter can be a slicer, which will be used to slice the image to make a
4021
+ reference.
3982
4022
  zero_ave : bool, default is True
3983
4023
  If True, average shift will be zero.
3984
4024
  along : AxisLike, optional
@@ -4008,7 +4048,7 @@ class ImgArray(LabeledArray):
4008
4048
  if ref is None:
4009
4049
  ref = self
4010
4050
  elif not isinstance(ref, ImgArray):
4011
- raise TypeError(f"'ref' must be an ImgArray object, but got {type(ref)}")
4051
+ ref = self[ref]
4012
4052
  if ref.axes != [along] + dims:
4013
4053
  from itertools import product
4014
4054
  _c_axes = complement_axes([along] + dims, str(ref.axes))
impy/arrays/lazy.py CHANGED
@@ -129,7 +129,7 @@ class LazyImgArray(AxesMixin):
129
129
  return xp.asnumpy(self.value.compute())
130
130
 
131
131
  def __getitem__(self, key):
132
- key = slicer.solve_slicer(key, self.axes)
132
+ key = slicer.solve_slicer(key, self.axes, self.shape)
133
133
 
134
134
  new_axes = slice_axes(self.axes, key)
135
135
  out = self.__class__(
@@ -281,6 +281,12 @@ class LazyImgArray(AxesMixin):
281
281
  chunk_info = ", ".join([f"{s}({o})" for s, o in zip(self.chunksize, self.axes)])
282
282
  return chunk_info
283
283
 
284
+ def astype(self, dtype: DTypeLike, copy: bool = True) -> LazyImgArray:
285
+ """Convert the array to the specified data type."""
286
+ out = self.__class__(self.value.astype(dtype, copy=copy))
287
+ out._set_info(self)
288
+ return out
289
+
284
290
  def _repr_dict_(self):
285
291
  return {
286
292
  "name": self.name,
@@ -555,9 +561,9 @@ class LazyImgArray(AxesMixin):
555
561
  dtype = self.dtype
556
562
  all_axes = str(self.axes)
557
563
  def _func(input: xp.ndarray, *args, **kwargs):
558
- out = xp.empty(input.shape, input.dtype)
564
+ out = xp.empty(input.shape, dtype=dtype)
559
565
  for sl in iter_slice(input.shape, c_axes, all_axes):
560
- out[sl] = func(input[sl], *args, **kwargs)
566
+ out[sl] = func(input[sl], *args, **kwargs).astype(dtype, copy=False)
561
567
  return out
562
568
  depth = switch_slice(c_axes, self.axes, 0, depth)
563
569
  return da.map_overlap(
@@ -1143,10 +1149,11 @@ class LazyImgArray(AxesMixin):
1143
1149
  @same_dtype(asfloat=True)
1144
1150
  @check_input_and_output_lazy
1145
1151
  @dims_to_spatial_axes
1146
- def drift_correction(self, shift: Coords = None, ref: ImgArray = None, *,
1147
- zero_ave: bool = True, along: str = None, dims: Dims = 2,
1148
- update: bool = False, **affine_kwargs) -> LazyImgArray:
1149
-
1152
+ def drift_correction(
1153
+ self, shift: Coords | None = None, ref: ImgArray | Any | None = None, *,
1154
+ zero_ave: bool = True, along: str = None, dims: Dims = 2,
1155
+ update: bool = False, **affine_kwargs,
1156
+ ) -> LazyImgArray:
1150
1157
  if along is None:
1151
1158
  along = find_first_appeared("tpzcia", include=self.axes, exclude=dims)
1152
1159
  elif len(along) != 1:
@@ -1165,8 +1172,8 @@ class LazyImgArray(AxesMixin):
1165
1172
  UserWarning)
1166
1173
  dims = _dims
1167
1174
  elif not isinstance(ref, self.__class__):
1168
- raise TypeError(f"'ref' must be LazyImgArray object, but got {type(ref)}")
1169
- elif ref.axes != along + dims:
1175
+ ref = self[ref]
1176
+ if ref.axes != along + dims:
1170
1177
  raise ValueError(f"Arguments `along`({along}) + `dims`({dims}) do not match "
1171
1178
  f"axes of `ref`({ref.axes})")
1172
1179
 
impy/arrays/tiled.py CHANGED
@@ -94,9 +94,12 @@ class TiledImage(Generic[_T]):
94
94
  from dask import array as da
95
95
 
96
96
  input = da.from_array(img.value, chunks=self._chunks)
97
+
98
+ def _func(arr: np.ndarray, *args, **kwargs) -> np.ndarray:
99
+ return func(arr, *args, **kwargs).astype(arr.dtype, copy=False)
97
100
  out: np.ndarray = xp.asnumpy(
98
101
  da.map_overlap(
99
- func,
102
+ _func,
100
103
  input,
101
104
  *args,
102
105
  depth=self.depth,
@@ -114,6 +117,7 @@ class TiledImage(Generic[_T]):
114
117
  c_axes="",
115
118
  depth=self.depth,
116
119
  boundary=self.boundary,
120
+ dtype=img.dtype,
117
121
  args=args,
118
122
  kwargs=kwargs,
119
123
  )
impy/core.py CHANGED
@@ -121,8 +121,11 @@ def array(
121
121
  dtype = arr.dtype
122
122
 
123
123
  axes, name = _normalize_params(axes, name, like)
124
-
125
- _arr = np.array(arr, dtype=dtype, copy=copy)
124
+
125
+ if copy:
126
+ _arr = np.array(arr, dtype=dtype)
127
+ else:
128
+ _arr = np.asarray(arr, dtype=dtype)
126
129
 
127
130
  # Automatically determine axes
128
131
  if axes is None:
@@ -567,7 +570,7 @@ def imread(
567
570
  scale_unit = {a: scale_unit for a in "zyx"}
568
571
 
569
572
  if is_memmap and axes is not None:
570
- sl = solve_slicer(key, Axes(axes))
573
+ sl = solve_slicer(key, Axes(axes), img.shape)
571
574
  axes = "".join(a for a, k in zip(axes, sl) if not isinstance(k, int))
572
575
  img = np.asarray(img[sl], dtype=dtype)
573
576
 
impy/correlation.py CHANGED
@@ -817,8 +817,8 @@ def manders_coloc(
817
817
 
818
818
  :math:`r = \frac{\sum_{i \in I_{ref}} I_i}{\sum_{i} I_i}`
819
819
 
820
- This value is NOT independent of background intensity. You need to correctly subtract
821
- background from self. This value is NOT interchangable between channels.
820
+ This value is NOT independent of background intensity. You need to correctly
821
+ subtract background from self. This value is NOT interchangable between channels.
822
822
 
823
823
  Parameters
824
824
  ----------
@@ -832,13 +832,19 @@ def manders_coloc(
832
832
  Correlation coefficient(s).
833
833
  """
834
834
  if img1.dtype != bool:
835
- raise TypeError("`ref` must be a binary image.")
835
+ raise TypeError("`img1` must be a binary image.")
836
836
  if img0.shape != img1.shape:
837
837
  raise ValueError(f"Shape mismatch. `img0` has shape {img0.shape} but `img1` "
838
838
  f"has shape {img1.shape}")
839
- if img0.axes != img1.axes:
840
- warn(f"Axes mismatch. `img0` has axes {img0.axes} but `img1` has axes {img1.axes}. "
841
- "Result may be wrong due to this mismatch.", UserWarning)
839
+ if not isinstance(img1, ImgArray):
840
+ img1 = ip_asarray(img1, axes=img0.axes)
841
+ elif img0.axes != img1.axes:
842
+ warn(
843
+ f"Axes mismatch. `img0` has axes {img0.axes} but `img1` has axes "
844
+ f"{img1.axes}. Result may be wrong due to this mismatch.",
845
+ UserWarning,
846
+ stacklevel=2,
847
+ )
842
848
  img0 = img0.as_float()
843
849
  total = np.sum(img0, axis=dims)
844
850
  img0 = img0.copy()
impy/io.py CHANGED
@@ -365,8 +365,9 @@ def _(path: str, memmap: bool = False) -> ImageData:
365
365
  @IO.mark_writer(".tif", ".tiff")
366
366
  def _(path: str, img: ImpyArray, lazy: bool = False):
367
367
  """The TIFF writer."""
368
+ from tifffile import imwrite, memmap
369
+
368
370
  if lazy:
369
- from tifffile import memmap
370
371
  from dask import array as da
371
372
  kwargs = _get_ijmeta_from_img(img, update_lut=False)
372
373
  mmap = memmap(str(path), shape=img.shape, dtype=img.dtype, **kwargs)
@@ -375,7 +376,6 @@ def _(path: str, img: ImpyArray, lazy: bool = False):
375
376
  da.store(img_dask, writer)
376
377
  return
377
378
 
378
- from tifffile import imwrite
379
379
  rest_axes = complement_axes(img.axes, "tzcyx")
380
380
  new_axes = ""
381
381
  for a in img.axes:
@@ -394,11 +394,11 @@ def _(path: str, img: ImpyArray, lazy: bool = False):
394
394
  img_new.set_scale(img)
395
395
  img = img_new
396
396
 
397
- warnings.warn("Image axes changed", UserWarning, stacklevel=2)
397
+ warnings.warn(f"Image axes changed", UserWarning, stacklevel=2)
398
398
 
399
399
  img = img.sort_axes()
400
400
  if img.dtype == "bool":
401
- img = img.astype(np.uint8)
401
+ img = img.astype(np.uint8) # tif does not support bool
402
402
  imsave_kwargs = _get_ijmeta_from_img(img, update_lut=True)
403
403
  imwrite(path, img, **imsave_kwargs)
404
404
  return None
impy/utils/gauss.py CHANGED
@@ -156,4 +156,4 @@ class GaussianBackground(DiagonalGaussian):
156
156
  self.sg = np.array(data.shape, dtype="float32")
157
157
  self.b, p95 = np.percentile(data, [5, 95])
158
158
  self.a = p95 - self.b
159
- return None
159
+ return None
impy/utils/slicer.py CHANGED
@@ -1,49 +1,79 @@
1
1
  from __future__ import annotations
2
- import re
2
+
3
+ from abc import ABC, abstractmethod
3
4
  from functools import lru_cache
5
+ import math
4
6
  from typing import Any, Mapping
5
- from .._types import Slices
6
- from ..axes import Slicer, Axes
7
+ from impy._types import Slices
8
+ from impy.axes import Slicer, Axes
7
9
 
8
- __all__ = ["str_to_slice", "axis_targeted_slicing", "solve_slicer"]
10
+ __all__ = ["str_to_slice", "solve_slicer"]
9
11
 
10
- def _range_to_list(v: str) -> list[int]:
11
- """
12
- "1,3,5" -> [1,3,5]
13
- "2,4:6,9" -> [2,4,5,6,9]
14
- """
15
- if ":" in v:
16
- s, e = v.split(":")
17
- return list(range(int(s), int(e)))
18
- else:
19
- return [int(v)]
12
+ class _Slicer(ABC):
13
+ def str_to_slice(self, v: str) -> list[int] | slice | int:
14
+ v = v.replace(" ", "")
15
+ if "," in v:
16
+ sl = sum((self._range_to_list(v) for v in v.split(",")), [])
17
+ elif ":" in v:
18
+ sl = slice(*map(self._int_or_none, v.split(":")))
19
+ else:
20
+ sl = self._int(v)
21
+ return sl
22
+
23
+ def _range_to_list(self, v: str) -> list[int]:
24
+ if ":" in v:
25
+ s, e = v.split(":")
26
+ return list(range(self._int(s), self._int(e)))
27
+ else:
28
+ return [self._int(v)]
29
+
30
+ def _int_or_none(self, v: str) -> int | None:
31
+ if v:
32
+ return self._int(v)
33
+ else:
34
+ return None
35
+
36
+ @abstractmethod
37
+ def _int(self, v: str) -> int:
38
+ """Convert a string to an integer."""
20
39
 
21
- def _int_or_none(v: str) -> int | None:
22
- if v:
23
- return int(v)
24
- else:
25
- return None
26
40
 
27
41
  def str_to_slice(v: str) -> list[int] | slice | int:
28
- v = re.sub(" ", "", v)
29
- if "," in v:
30
- sl = sum((_range_to_list(v) for v in v.split(",")), [])
31
- elif ":" in v:
32
- sl = slice(*map(_int_or_none, v.split(":")))
33
- else:
34
- sl = int(v)
35
- return sl
42
+ return ConstSlicer().str_to_slice(v)
36
43
 
44
+ class ConstSlicer(_Slicer):
45
+ def _int(self, v: str) -> int:
46
+ return int(v)
37
47
 
38
- @lru_cache
39
- def axis_targeted_slicing(axes: tuple[str, ...], string: str) -> Slices:
48
+ class EvalSlicer(_Slicer):
49
+ def __init__(self, size: int):
50
+ self._size = size
51
+
52
+ def _int(self, v: str) -> int:
53
+ ns = {
54
+ "N": self._size,
55
+ "int": int,
56
+ "ceil": math.ceil,
57
+ "floor": math.floor,
58
+ "round": round,
59
+ "__builtins__": {},
60
+ }
61
+ out = eval(v, ns)
62
+ if not hasattr(out, "__index__"):
63
+ raise ValueError(f"Invalid index: {v!r}.")
64
+ return out.__index__()
65
+
66
+
67
+ def axis_targeted_slicing(
68
+ axes: tuple[str, ...],
69
+ string: str,
70
+ shape: tuple[int, ...] | None = None,
71
+ ) -> Slices:
40
72
  """
41
73
  Make a conventional slices from an axis-targeted slicing string.
42
74
 
43
75
  Parameters
44
76
  ----------
45
- ndim : int
46
- Number of dimension of the array which will be sliced.
47
77
  axes : str
48
78
  Axes of input ndarray.
49
79
  string : str
@@ -54,7 +84,14 @@ def axis_targeted_slicing(axes: tuple[str, ...], string: str) -> Slices:
54
84
  -------
55
85
  slices
56
86
  """
57
- keylist = re.sub(" ", "", string).split(";")
87
+ if "N" in string:
88
+ return axis_targeted_slicing_eval(axes, string, shape)
89
+ else:
90
+ return axis_targeted_slicing_const(axes, string)
91
+
92
+ @lru_cache
93
+ def axis_targeted_slicing_const(axes: tuple[str, ...], string: str) -> Slices:
94
+ keylist = string.replace(" ", "").split(";")
58
95
  dict_slicer: dict[str, Any] = {}
59
96
 
60
97
  for k in keylist:
@@ -68,9 +105,31 @@ def axis_targeted_slicing(axes: tuple[str, ...], string: str) -> Slices:
68
105
  else:
69
106
  dict_slicer[axis] = sl
70
107
 
71
- return dict_to_slice(dict_slicer, axes)
108
+ return _dict_to_slice(dict_slicer, axes)
109
+
110
+ def axis_targeted_slicing_eval(
111
+ axes: tuple[str, ...],
112
+ string: str,
113
+ shape: tuple[int, ...] | None = None,
114
+ ) -> Slices:
115
+ keylist = string.replace(" ", "").split(";")
116
+ dict_slicer: dict[str, Any] = {}
117
+
118
+ for k in keylist:
119
+ if k.count("=") != 1:
120
+ raise ValueError(f"Informal axis-targeted slicing: {k!r}.")
121
+ axis, sl_str = k.split("=")
122
+ try:
123
+ size = shape[axes.index(axis)]
124
+ sl = EvalSlicer(size).str_to_slice(sl_str)
125
+ except ValueError:
126
+ raise ValueError(f"Informal axis-targeted slicing: {k!r}.")
127
+ else:
128
+ dict_slicer[axis] = sl
129
+
130
+ return _dict_to_slice(dict_slicer, axes)
72
131
 
73
- def dict_to_slice(sl: dict[str, Any], axes: tuple[str, ...]):
132
+ def _dict_to_slice(sl: dict[str, Any], axes: tuple[str, ...]):
74
133
  sl_list = [slice(None)] * len(axes)
75
134
 
76
135
  for k, v in sl.items():
@@ -79,11 +138,11 @@ def dict_to_slice(sl: dict[str, Any], axes: tuple[str, ...]):
79
138
 
80
139
  return tuple(sl_list)
81
140
 
82
- def solve_slicer(key: Any, axes: Axes) -> Slices:
141
+ def solve_slicer(key: Any, axes: Axes, shape: tuple[int, ...] | None = None) -> Slices:
83
142
  if isinstance(key, str):
84
- key = axis_targeted_slicing(tuple(axes), key)
143
+ key = axis_targeted_slicing(tuple(axes), key, shape)
85
144
 
86
145
  elif isinstance(key, (Mapping, Slicer)):
87
146
  key = axes.create_slice(key)
88
147
 
89
- return key
148
+ return key
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: impy-array
3
- Version: 2.4.1
3
+ Version: 2.4.3
4
4
  Summary: Speed up coding/extending image analysis in Python.
5
5
  Project-URL: Download, https://github.com/hanjinliu/impy
6
6
  Author-email: Hanjin Liu <liuhanjin-sc@g.ecc.u-tokyo.ac.jp>
@@ -120,8 +120,9 @@ or where to save the image. As a result, **your code will be very concise**:
120
120
  import impy as ip
121
121
  import numpy as np
122
122
 
123
- img = ip.imread("path/to/image") # Read images with metadata.
123
+ img = ip.imread("path/to/image.tif") # Read images with metadata.
124
124
  img["z=3;t=0"].imshow() # Plot image slice at z=3 and t=0.
125
+ img["y=N//4:N//4*3"].imshow() # `N` for the size of the axis.
125
126
  img_fil = img.gaussian_filter(sigma=2) # Paralell batch denoising. No more for loop!
126
127
  img_prj = np.max(img_fil, axis="z") # Z-projection (numpy is aware of image axes!).
127
128
  img_prj.imsave(f"Max-{img.name}") # Save in the same place. Don't spend time on searching for the directory!
@@ -134,6 +135,7 @@ img_prj.imsave(f"Max-{img.name}") # Save in the same place. Don't spend tim
134
135
  - Tiff file (".tif", ".tiff")
135
136
  - MRC file (".mrc", ".rec", ".st", ".map", ".map.gz")
136
137
  - Zarr file (".zarr")
138
+ - ND2 file (".nd2")
137
139
  - Other image file (".png", ".jpg")
138
140
 
139
141
  ### Lazy loading
@@ -162,7 +164,10 @@ ip.Const["RESOURCE"] = "cupy" # <- globally use GPU
162
164
 
163
165
  ### Seamless interface between `napari`
164
166
 
165
- [napari](https://github.com/napari/napari) is an interactive viewer for multi-dimensional images. `impy` has a **simple and efficient interface** with it, via the object `ip.gui`. Since `ImgArray` is tagged with image metadata, you don't have to care about axes or scales. Just run
167
+ [napari](https://github.com/napari/napari) is an interactive viewer for multi-dimensional
168
+ images. `impy` has a **simple and efficient interface** with it, via the object `ip.gui`.
169
+ Since `ImgArray` is tagged with image metadata, you don't have to care about axes or
170
+ scales. Just run
166
171
 
167
172
  ```python
168
173
  ip.gui.add(img)
@@ -1,41 +1,41 @@
1
- impy/__init__.py,sha256=Dd8i53lTgoq40fXeqOhduClsprYXWdeDZM_0Ug7i5Ys,1156
1
+ impy/__init__.py,sha256=fAct8g-glCo45fXgbMEOELJGsVvtUkBZx5nXfOQMmm0,1156
2
2
  impy/__main__.py,sha256=BAQkQ4X8EFo42pbNx__EqpZ5KL4MTfTUWsVbJIQF0O0,4974
3
3
  impy/_const.py,sha256=XFkgkyqs_clQJDqr2vdh5rCyfM83iMFChOLJjwNWHtM,3736
4
4
  impy/_types.py,sha256=gO4l0hx9qxe6eI0PyC4ukW3k4IYxCEZ9gT-rQ3jj3zU,808
5
5
  impy/array_api.py,sha256=ADhMON5xTpjBG5MDOjUTthXzYSvm9zJNy8bL8RliI64,5843
6
6
  impy/binder.py,sha256=CTMb11g6uYDVVQV5Wtef865IO0G2V3vGXc8SiGYRD5k,9651
7
7
  impy/collections.py,sha256=2e55bLjZN7W4LFUCkyxekcDfLwZodMaU4JG5NQ3RS54,10946
8
- impy/core.py,sha256=q-9QZLKRqIKsI2knkxu5P4Tacq3FUIvFHjjUThZDuiM,25580
9
- impy/correlation.py,sha256=CoNboXiZjO1VYqA0rHe4Jp6gDYt6hyJtSgI3TWepxKk,28398
10
- impy/io.py,sha256=TFdGD3sGfmbkFI4FwfsemiTmk6cIgksbvhnFt7F24ac,22269
8
+ impy/core.py,sha256=5FPiEksz7EpV8lKpNkPv0oZ9Yhs-bwIsnzQ9VFmYHHo,25650
9
+ impy/correlation.py,sha256=aeQLfLAm8LnuKa4LtG_UWBamyi8SNMeDIs-lH5vYz9s,28555
10
+ impy/io.py,sha256=SIGHJqCh6xfu8jDZ9BE0oWpVOoA5KAxgrI7u_v1ry5s,22272
11
11
  impy/random.py,sha256=TqPL8oFYGtZlr4phWyMSgP7KLqsXLH9LM3Fx1LxQWjA,6973
12
12
  impy/roi.py,sha256=p9ttjBl5SGHHXj0xg5UjPlg_V9cY3MnNZxFfYIjTYsg,14164
13
13
  impy/arrays/__init__.py,sha256=kbvvCRwdTck6b3gd3MBhD7L8Cp6XlmjX2HfSdPplhBo,377
14
- impy/arrays/_imshow.py,sha256=9MBwa6LwnuTcYbeJc5PwR_6VAdcn9K0JFx87BA6g-Po,6098
14
+ impy/arrays/_imshow.py,sha256=6mJ_PDqmE4UZO9e9SUgyY_YrzQdR2QKlTG7KF_aC_tI,6949
15
15
  impy/arrays/axesmixin.py,sha256=9PK6kMZAfNVipTL65aF5-yR3qt2fy4ATl1OACXLYrAE,10596
16
16
  impy/arrays/big.py,sha256=0KPG_V7yKiVYLFwzGfHRxyFD2kysIyVppsq6hh7TFPg,2809
17
- impy/arrays/imgarray.py,sha256=oqFXASNXJ2neVy3HWp8uaPdncojgvLNsc5UvaW4tbWE,155622
17
+ impy/arrays/imgarray.py,sha256=c1R0NG-SnC7i45JEnevfC3SvgzuFLoT8khT-1jIL_1E,157018
18
18
  impy/arrays/label.py,sha256=l0SZXcZxU8qwUgj0QZPZ32XsNaoBtenlrn6hNR03SPI,6406
19
19
  impy/arrays/labeledarray.py,sha256=4WBzorvLM9mmrkuytjMJb7ucqJqK62ioY6eTZlbNh3M,56540
20
- impy/arrays/lazy.py,sha256=r56r6_68BMopZoTG75L8JV3PA-vtR6l-jBzhDTaZLGY,55151
20
+ impy/arrays/lazy.py,sha256=w3yeMokY62xAoqmfrr8_qh4LYDVnJdF0Jg4E3lZBHFg,55380
21
21
  impy/arrays/phasearray.py,sha256=IojWaNs5sEujn6Lhgqe00H0xF-4CZEFWt5cVW6U_DWQ,13981
22
22
  impy/arrays/specials.py,sha256=4sNg_zeJUce_rwnasPoyL2eZ0-gx_4Z-KwitmLB4a5k,7896
23
- impy/arrays/tiled.py,sha256=eYbFOJ2sI9d6PqH83t1WdA8l2dmYb-1FMViGPl4_Lus,7565
23
+ impy/arrays/tiled.py,sha256=4uGQKmZ0w2ZHlZNB1kl_4XP4hU1AftO21k6DgyJ1cUw,7767
24
24
  impy/arrays/_utils/__init__.py,sha256=M5HogfyUBvV8kp-X1ZthS8vDLUP7-O2f9Gvsc1ZXdT8,271
25
25
  impy/arrays/_utils/_corr.py,sha256=8RM_OeaDsrewhiYhf6wFkDYRfl1gQ8Sg2TTK4CT22K4,10031
26
26
  impy/arrays/_utils/_deconv.py,sha256=dCFWDPY6pkJxmqec5H0i1wtJECACvnz5vv1YIVLbnSY,2985
27
27
  impy/arrays/_utils/_docs.py,sha256=AT6tRxXcX433FCfPXhE9wsaeduy_Um44KOqrYHYTFZE,4968
28
28
  impy/arrays/_utils/_filters.py,sha256=aigQnaURbUnmOXGDxkWksISWQbKAUdwtS8kzbaMzgoQ,7226
29
- impy/arrays/_utils/_glcm.py,sha256=X499c4QMwdQAZas8rQbfdEpt5moosxNkTgyayTRJMvU,4149
29
+ impy/arrays/_utils/_glcm.py,sha256=AoUP-p1MPtAzP0Eyt_DEE_wZYwezNICzdkXMBY-OEBo,4150
30
30
  impy/arrays/_utils/_linalg.py,sha256=06jnv-P6nwUjYVTHX2f9i-KDSYZ0bxwNfWWP8A8e_Vw,3233
31
31
  impy/arrays/_utils/_misc.py,sha256=jB16bZOYPEx_3JHGA-EIVziBjmaySPv66oyT_PZg_cI,2839
32
32
  impy/arrays/_utils/_plot.py,sha256=AzY33TBzQ97DaTZu_EIu5GpN-sUTLKY1tY2qu76Ro10,5077
33
33
  impy/arrays/_utils/_process_numba.py,sha256=1WjNRwqggSMYyKLeXo6W97lm93A47cAFvR6sBF086PI,3428
34
34
  impy/arrays/_utils/_skimage.py,sha256=p10aiqIgXvPH8j_7iy_fbWD08jMolHSd1WJZAemDAEk,808
35
- impy/arrays/_utils/_structures.py,sha256=GSwroP5CPP9MUuZHhrbJhO_Q9fc8u1hwBqiz-2koGJY,1300
35
+ impy/arrays/_utils/_structures.py,sha256=K0gHjv9lF90wizAvFZQyHF02l2TC-texdYJTfB5I2H8,1301
36
36
  impy/arrays/_utils/_transform.py,sha256=fdee-qTWbdnQec-o9f2Z9HPjfsJVaVNn5sDPcNeVyLg,12682
37
37
  impy/arrays/bases/__init__.py,sha256=aHsAYta5CQkEDlbFShEtEGYN89N2qYedg99SM6Oo7wk,99
38
- impy/arrays/bases/metaarray.py,sha256=2ob-t2bZqOgMYdt0AN02p3eAGtcQPhehuOLtoDs442k,29832
38
+ impy/arrays/bases/metaarray.py,sha256=wD9bDgqIgEqYkdyP_HlGY8vw_ETv7qsjkfG7A-sS83c,29868
39
39
  impy/arrays/bases/overload.py,sha256=ECLxRCumEUJb4KEu1K8k4vZWbufyPEPBj-Atzv4AosU,9359
40
40
  impy/axes/__init__.py,sha256=qzhWAJMT_mc-MXcuaMEDjVd_n0dFRmZxaphh6x_Wzb4,239
41
41
  impy/axes/_axes.py,sha256=lpTPzcs_hHslbxSUBGTjicIu4XLUs79zXPfDi5ZyGLI,12134
@@ -50,15 +50,15 @@ impy/lazy/random.py,sha256=2rwHRsHPOvi8tI9kTtGuZ5SzN0MA7yn-30bZSvHeLVc,7713
50
50
  impy/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  impy/utils/axesop.py,sha256=c86XdNlUBFLrwHhAT2j0eELxopNe2QEVaNeOQhXr2do,3076
52
52
  impy/utils/deco.py,sha256=lItN0UdadZsjI9eW3fI402k7DNR9jcnD6ZgjdkYsDdg,5946
53
- impy/utils/gauss.py,sha256=735vYhSVrgZGiZeHYrwjVkRsQ-Zx5dYghOSrtfD3s4o,4712
53
+ impy/utils/gauss.py,sha256=_jvmaUYSRB8KvX9Qp36rhNaNw9lllf68g_43wshpAMo,4713
54
54
  impy/utils/misc.py,sha256=zV_NeqEaiTW4Rki5fqWfspQjczRaoTJ5MxTOUx6qstY,622
55
- impy/utils/slicer.py,sha256=OR-PMILYBihY0jE38wIpS4QI30fk1c7D6LxaG_fDi_w,2423
55
+ impy/utils/slicer.py,sha256=otDrizWdzoUjFUMlsha0zNFSS4TkgAmLPOAotaTVaUA,4316
56
56
  impy/utils/utilcls.py,sha256=3Td9G2ZkU4C0BiW2LH0sq7RBjdco_BtyxNr-s-seLhs,437
57
57
  impy/viewer/__init__.py,sha256=NTVonxd7HMfbRXHhjLBMG_07NjFia-O1QCv5IOKdbgw,286
58
58
  impy/viewer/utils.py,sha256=BUQ-hUN_j_hNON9F3B63670b-h6fIPxOB4fbAJnbSGg,12236
59
59
  impy/viewer/viewer.py,sha256=Sfq-obSLoHkBkIW0NDWCxEEaX7-YsC4ifAJ-nxpvJws,17632
60
- impy_array-2.4.1.dist-info/METADATA,sha256=5C3Nzq36x3irOWynCznvnNrSYu6lVEfDWtaw-ji0Y48,7526
61
- impy_array-2.4.1.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
62
- impy_array-2.4.1.dist-info/entry_points.txt,sha256=reyrgy4odXvi1CcPOIIyRYBmsNGG2tO7ZkFOdG5CBkU,44
63
- impy_array-2.4.1.dist-info/licenses/LICENSE,sha256=rpxKafH9r42sxLLYYB5VbZBHOdtYeLuYJjVU1LBwrxk,1546
64
- impy_array-2.4.1.dist-info/RECORD,,
60
+ impy_array-2.4.3.dist-info/METADATA,sha256=NHJ2pIQ5d456uKCt19xcYqwwE1iLZabtBAr20clV_go,7619
61
+ impy_array-2.4.3.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
62
+ impy_array-2.4.3.dist-info/entry_points.txt,sha256=reyrgy4odXvi1CcPOIIyRYBmsNGG2tO7ZkFOdG5CBkU,44
63
+ impy_array-2.4.3.dist-info/licenses/LICENSE,sha256=rpxKafH9r42sxLLYYB5VbZBHOdtYeLuYJjVU1LBwrxk,1546
64
+ impy_array-2.4.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.21.1
2
+ Generator: hatchling 1.24.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any