impy-array 2.5.0__py3-none-any.whl → 2.5.2__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 +1 -1
- impy/arrays/imgarray.py +3 -7
- impy/arrays/labeledarray.py +0 -10
- impy/arrays/lazy.py +5 -17
- impy/arrays/specials.py +32 -33
- impy/core.py +29 -7
- impy/frame/frames.py +49 -60
- impy/lazy/core.py +1 -1
- impy/viewer/utils.py +61 -61
- {impy_array-2.5.0.dist-info → impy_array-2.5.2.dist-info}/METADATA +1 -1
- {impy_array-2.5.0.dist-info → impy_array-2.5.2.dist-info}/RECORD +14 -14
- {impy_array-2.5.0.dist-info → impy_array-2.5.2.dist-info}/WHEEL +0 -0
- {impy_array-2.5.0.dist-info → impy_array-2.5.2.dist-info}/entry_points.txt +0 -0
- {impy_array-2.5.0.dist-info → impy_array-2.5.2.dist-info}/licenses/LICENSE +0 -0
impy/__init__.py
CHANGED
impy/arrays/imgarray.py
CHANGED
|
@@ -2675,7 +2675,7 @@ class ImgArray(LabeledArray):
|
|
|
2675
2675
|
out = pd.concat(out, axis=0)
|
|
2676
2676
|
|
|
2677
2677
|
out = MarkerFrame(out.reindex(columns=list(coords._axes)),
|
|
2678
|
-
columns=str(coords._axes), dtype=np.float32)
|
|
2678
|
+
columns=str(coords._axes), dtype=np.float32)
|
|
2679
2679
|
out.set_scale(coords.scale)
|
|
2680
2680
|
|
|
2681
2681
|
return out
|
|
@@ -3801,7 +3801,7 @@ class ImgArray(LabeledArray):
|
|
|
3801
3801
|
|
|
3802
3802
|
def regionprops(
|
|
3803
3803
|
self,
|
|
3804
|
-
properties: Iterable[str] | str = ("
|
|
3804
|
+
properties: Iterable[str] | str = ("intensity_mean",),
|
|
3805
3805
|
*,
|
|
3806
3806
|
extra_properties: Iterable[Callable] | None = None,
|
|
3807
3807
|
) -> DataDict[str, PropArray]:
|
|
@@ -4111,8 +4111,6 @@ class ImgArray(LabeledArray):
|
|
|
4111
4111
|
|
|
4112
4112
|
if along is None:
|
|
4113
4113
|
along = find_first_appeared("tpzcia", include=self.axes)
|
|
4114
|
-
elif len(along) != 1:
|
|
4115
|
-
raise ValueError("`along` must be single character.")
|
|
4116
4114
|
if not isinstance(upsample_factor, int):
|
|
4117
4115
|
raise TypeError(f"upsample-factor must be integer but got {type(upsample_factor)}")
|
|
4118
4116
|
if max_shift is not None:
|
|
@@ -4122,7 +4120,7 @@ class ImgArray(LabeledArray):
|
|
|
4122
4120
|
c_axes = complement_axes(along, self.axes)
|
|
4123
4121
|
last_img = None
|
|
4124
4122
|
img_fft = self.fft(shift=False, dims=c_axes)
|
|
4125
|
-
for i, (_, img) in enumerate(img_fft.iter(along)):
|
|
4123
|
+
for i, (_, img) in enumerate(img_fft.iter([along])):
|
|
4126
4124
|
img = xp.asarray(img)
|
|
4127
4125
|
if last_img is not None:
|
|
4128
4126
|
result[i] = xp.asnumpy(
|
|
@@ -4198,8 +4196,6 @@ class ImgArray(LabeledArray):
|
|
|
4198
4196
|
|
|
4199
4197
|
if along is None:
|
|
4200
4198
|
along = find_first_appeared("tpzcia", include=self.axes, exclude=dims)
|
|
4201
|
-
elif len(along) != 1:
|
|
4202
|
-
raise ValueError("`along` must be single character.")
|
|
4203
4199
|
|
|
4204
4200
|
if shift is None:
|
|
4205
4201
|
# determine 'ref'
|
impy/arrays/labeledarray.py
CHANGED
|
@@ -302,16 +302,6 @@ class LabeledArray(MetaArray):
|
|
|
302
302
|
ext = ".tif"
|
|
303
303
|
save_path = save_path.parent / (save_path.name + ext)
|
|
304
304
|
|
|
305
|
-
if not Path(save_path).is_absolute():
|
|
306
|
-
if self.source is None:
|
|
307
|
-
raise ValueError(
|
|
308
|
-
"Image directory path is unknown. Set by \n"
|
|
309
|
-
" >>> img.source = \"...\"\n"
|
|
310
|
-
"or specify absolute path like\n"
|
|
311
|
-
" >>> img.imsave(\"/path/to/XXX.tif\")"
|
|
312
|
-
)
|
|
313
|
-
save_path = self.source.parent / save_path
|
|
314
|
-
|
|
315
305
|
if not overwrite and save_path.exists():
|
|
316
306
|
raise FileExistsError(f"File {save_path!r} already exists.")
|
|
317
307
|
if self.metadata is None:
|
impy/arrays/lazy.py
CHANGED
|
@@ -352,16 +352,6 @@ class LazyImgArray(AxesMixin):
|
|
|
352
352
|
ext = ".tif"
|
|
353
353
|
save_path = save_path.parent / (save_path.name + ext)
|
|
354
354
|
|
|
355
|
-
if not Path(save_path).is_absolute():
|
|
356
|
-
if self.source is None:
|
|
357
|
-
raise ValueError(
|
|
358
|
-
"Image directory path is unknown. Set by \n"
|
|
359
|
-
" >>> img.source = \"...\"\n"
|
|
360
|
-
"or specify absolute path like\n"
|
|
361
|
-
" >>> img.imsave(\"/path/to/XXX.tif\")"
|
|
362
|
-
)
|
|
363
|
-
save_path = self.source.parent / save_path
|
|
364
|
-
|
|
365
355
|
if not overwrite and save_path.exists():
|
|
366
356
|
raise FileExistsError(f"File {save_path!r} already exists.")
|
|
367
357
|
if dtype is None:
|
|
@@ -776,12 +766,13 @@ class LazyImgArray(AxesMixin):
|
|
|
776
766
|
sigma: nDFloat = 1.0,
|
|
777
767
|
*,
|
|
778
768
|
dims: Dims = None,
|
|
769
|
+
fourier: bool = False,
|
|
779
770
|
update: bool = False
|
|
780
771
|
) -> LazyImgArray:
|
|
781
772
|
c_axes = complement_axes(dims, self.axes)
|
|
782
773
|
depth = _ceilint(sigma*4)
|
|
783
774
|
return self._apply_map_overlap(
|
|
784
|
-
|
|
775
|
+
_filters.gaussian_filter_fourier if fourier else _filters.gaussian_filter,
|
|
785
776
|
c_axes=c_axes,
|
|
786
777
|
depth=depth,
|
|
787
778
|
kwargs=dict(sigma=sigma),
|
|
@@ -795,13 +786,14 @@ class LazyImgArray(AxesMixin):
|
|
|
795
786
|
low_sigma: nDFloat = 1.0,
|
|
796
787
|
high_sigma: nDFloat = 2.0,
|
|
797
788
|
*,
|
|
789
|
+
fourier: bool = False,
|
|
798
790
|
dims: Dims = None,
|
|
799
791
|
update: bool = False
|
|
800
792
|
) -> LazyImgArray:
|
|
801
793
|
c_axes = complement_axes(dims, self.axes)
|
|
802
794
|
depth = _ceilint(high_sigma*4)
|
|
803
795
|
return self._apply_map_overlap(
|
|
804
|
-
_filters.dog_filter,
|
|
796
|
+
_filters.dog_filter_fourier if fourier else _filters.dog_filter,
|
|
805
797
|
c_axes=c_axes,
|
|
806
798
|
depth=depth,
|
|
807
799
|
kwargs=dict(low_sigma=low_sigma, high_sigma=high_sigma),
|
|
@@ -1317,8 +1309,6 @@ class LazyImgArray(AxesMixin):
|
|
|
1317
1309
|
def track_drift(self, along: str = None, upsample_factor: int = 10) -> DaskArray:
|
|
1318
1310
|
if along is None:
|
|
1319
1311
|
along = find_first_appeared("tpzc<i", include=self.axes)
|
|
1320
|
-
elif len(along) != 1:
|
|
1321
|
-
raise ValueError("`along` must be single character.")
|
|
1322
1312
|
|
|
1323
1313
|
dims = complement_axes(along, self.axes)
|
|
1324
1314
|
chunks = switch_slice(dims, self.axes, ifin=self.shape, ifnot=1)
|
|
@@ -1370,8 +1360,6 @@ class LazyImgArray(AxesMixin):
|
|
|
1370
1360
|
) -> LazyImgArray:
|
|
1371
1361
|
if along is None:
|
|
1372
1362
|
along = find_first_appeared("tpzcia", include=self.axes, exclude=dims)
|
|
1373
|
-
elif len(along) != 1:
|
|
1374
|
-
raise ValueError("`along` must be single character.")
|
|
1375
1363
|
|
|
1376
1364
|
from impy.frame import MarkerFrame
|
|
1377
1365
|
|
|
@@ -1387,7 +1375,7 @@ class LazyImgArray(AxesMixin):
|
|
|
1387
1375
|
dims = _dims
|
|
1388
1376
|
elif not isinstance(ref, self.__class__):
|
|
1389
1377
|
ref = self[ref]
|
|
1390
|
-
if ref.axes != along + dims:
|
|
1378
|
+
if ref.axes != [along] + dims:
|
|
1391
1379
|
raise ValueError(f"Arguments `along`({along}) + `dims`({dims}) do not match "
|
|
1392
1380
|
f"axes of `ref`({ref.axes})")
|
|
1393
1381
|
|
impy/arrays/specials.py
CHANGED
|
@@ -20,23 +20,23 @@ SCALAR_PROP = (
|
|
|
20
20
|
class PropArray(MetaArray):
|
|
21
21
|
additional_props = ["_source", "_metadata", "_name", "propname"]
|
|
22
22
|
propname: str
|
|
23
|
-
def __new__(cls, obj, *, name=None, axes=None, source=None,
|
|
23
|
+
def __new__(cls, obj, *, name=None, axes=None, source=None,
|
|
24
24
|
metadata=None, propname=None, dtype=None):
|
|
25
25
|
if propname is None:
|
|
26
26
|
propname = "User_Defined"
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
if dtype is None and propname in SCALAR_PROP:
|
|
29
29
|
dtype = np.float32
|
|
30
30
|
elif dtype is None:
|
|
31
31
|
dtype = object
|
|
32
32
|
else:
|
|
33
33
|
dtype = dtype
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
self = super().__new__(cls, obj, name, axes, source, metadata, dtype=dtype)
|
|
36
36
|
self.propname = propname
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
return self
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
def _repr_dict_(self):
|
|
41
41
|
return {
|
|
42
42
|
"name": self.name,
|
|
@@ -44,7 +44,7 @@ class PropArray(MetaArray):
|
|
|
44
44
|
"dtype": self.dtype,
|
|
45
45
|
"source": self.source,
|
|
46
46
|
"property name": self.propname}
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
def plot(self, along=None, cmap="jet", cmap_range=(0, 1)):
|
|
49
49
|
"""
|
|
50
50
|
Plot all the results with x-axis defined by `along`.
|
|
@@ -57,7 +57,7 @@ class PropArray(MetaArray):
|
|
|
57
57
|
Colormap of each graph.
|
|
58
58
|
cmap_range : tuple, default is (0, 1)
|
|
59
59
|
Range of float for colormap iteration.
|
|
60
|
-
"""
|
|
60
|
+
"""
|
|
61
61
|
import matplotlib.pyplot as plt
|
|
62
62
|
if self.dtype == object:
|
|
63
63
|
raise TypeError(f"Cannot call plot_profile for {self.propname} "
|
|
@@ -67,21 +67,21 @@ class PropArray(MetaArray):
|
|
|
67
67
|
along = find_first_appeared("tzp<yxc", include=self.axes)
|
|
68
68
|
except ValueError:
|
|
69
69
|
along = self.axes[-1]
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
iteraxes = self.axes.drop(along)
|
|
72
72
|
cmap = plt.get_cmap(cmap)
|
|
73
73
|
positions = np.linspace(*cmap_range, self.size//self.sizeof(along), endpoint=False)
|
|
74
74
|
x = np.arange(self.sizeof(along))*self.scale[along]
|
|
75
75
|
for i, (sl, y) in enumerate(self.iter(iteraxes)):
|
|
76
76
|
plt.plot(x, y, color=cmap(positions[i]))
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
plt.title(f"{self.propname}")
|
|
79
79
|
plt.xlabel(along)
|
|
80
80
|
plt.show()
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
return self
|
|
83
|
-
|
|
84
|
-
def hist(self, along: str = "N", bins: int = None, cmap: str = "jet",
|
|
83
|
+
|
|
84
|
+
def hist(self, along: str = "N", bins: int = None, cmap: str = "jet",
|
|
85
85
|
cmap_range: tuple[float, float] = (0., 1.)) -> PropArray:
|
|
86
86
|
"""
|
|
87
87
|
Plot histogram.
|
|
@@ -96,31 +96,31 @@ class PropArray(MetaArray):
|
|
|
96
96
|
Colormap of each graph.
|
|
97
97
|
cmap_range : tuple, default is (0, 1)
|
|
98
98
|
Range of float for colormap iteration.
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
Returns
|
|
101
101
|
-------
|
|
102
102
|
self
|
|
103
|
-
"""
|
|
103
|
+
"""
|
|
104
104
|
import matplotlib.pyplot as plt
|
|
105
105
|
|
|
106
106
|
if self.dtype == object:
|
|
107
107
|
raise TypeError(f"Cannot call plot_profile for {self.propname} "
|
|
108
108
|
"because dtype == object.")
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
if along is None:
|
|
111
111
|
along = find_first_appeared("pxyzt<c", include=self.axes)
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
iteraxes = self.axes.drop(along)
|
|
114
114
|
cmap = plt.get_cmap(cmap)
|
|
115
115
|
positions = np.linspace(*cmap_range, self.size//self.sizeof(along), endpoint=False)
|
|
116
116
|
for i, (sl, y) in enumerate(self.iter(iteraxes)):
|
|
117
117
|
plt.hist(y, color=cmap(positions[i]), bins=bins, alpha=0.5)
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
plt.title(f"{self.propname}")
|
|
120
120
|
plt.show()
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
return self
|
|
123
|
-
|
|
123
|
+
|
|
124
124
|
def curve_fit(self, f: Callable, p0 = None, dims = "t", return_fit: bool = True) -> DataDict[str, PropArray]:
|
|
125
125
|
"""
|
|
126
126
|
Run scipy.optimize.curve_fit for each dimesion.
|
|
@@ -130,12 +130,12 @@ class PropArray(MetaArray):
|
|
|
130
130
|
f : callable
|
|
131
131
|
Model function.
|
|
132
132
|
p0 : array or callable, optional
|
|
133
|
-
Initial parameter. Callable object that estimate initial paramter can also
|
|
133
|
+
Initial parameter. Callable object that estimate initial paramter can also
|
|
134
134
|
be passed here.
|
|
135
135
|
dims : str, by default "t"
|
|
136
136
|
Along which axes fitting algorithms are conducted.
|
|
137
137
|
return_fit : bool, by default True
|
|
138
|
-
If fitting trajectories are returned. If the input array is large, this will
|
|
138
|
+
If fitting trajectories are returned. If the input array is large, this will
|
|
139
139
|
save much memory.
|
|
140
140
|
|
|
141
141
|
Returns
|
|
@@ -144,23 +144,23 @@ class PropArray(MetaArray):
|
|
|
144
144
|
params : Fitting parameters
|
|
145
145
|
covs : Covariances
|
|
146
146
|
fit : fitting trajectories (if return_fit==True)
|
|
147
|
-
"""
|
|
147
|
+
"""
|
|
148
148
|
from scipy import optimize as opt
|
|
149
149
|
|
|
150
150
|
c_axes = complement_axes(dims, all_axes=self.axes)
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
if len(dims)!=1:
|
|
153
153
|
raise NotImplementedError("Only 1-dimensional fitting is implemented.")
|
|
154
|
-
|
|
154
|
+
|
|
155
155
|
n_params = len(signature(f).parameters)-1
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
params = np.empty(self.sizesof(c_axes) + (n_params,), dtype=np.float32)
|
|
158
158
|
errs = np.empty(self.sizesof(c_axes) + (n_params,), dtype=np.float32)
|
|
159
159
|
if return_fit:
|
|
160
160
|
fit = np.empty(self.sizesof(c_axes) + (self.sizeof(dims),), dtype=self.dtype)
|
|
161
|
-
|
|
161
|
+
|
|
162
162
|
xdata = np.arange(self.sizeof(dims))*self.scale[dims]
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
for sl, data in self.iter(c_axes, exclude=dims):
|
|
165
165
|
p0_ = p0 if not callable(p0) else p0(data)
|
|
166
166
|
result = opt.curve_fit(f, xdata, data, p0_)
|
|
@@ -168,22 +168,22 @@ class PropArray(MetaArray):
|
|
|
168
168
|
errs[sl] = np.sqrt(np.diag(cov))
|
|
169
169
|
if return_fit:
|
|
170
170
|
fit[sl] = f(xdata, *(result[0]))
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
# set infos
|
|
173
173
|
params = params.view(self.__class__)
|
|
174
174
|
errs = errs.view(self.__class__)
|
|
175
175
|
params._set_info(self, new_axes=self.axes.drop(dims).extend("m"))
|
|
176
176
|
errs._set_info(self, new_axes=self.axes.drop(dims).extend("m"))
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
if return_fit:
|
|
179
179
|
fit = fit.view(self.__class__)
|
|
180
180
|
fit._set_info(self, new_axes=self.axes.drop(dims).extend(dims))
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
if return_fit:
|
|
183
183
|
return DataDict(params=params, errs=errs, fit=fit)
|
|
184
184
|
else:
|
|
185
185
|
return DataDict(params=params, errs=errs)
|
|
186
|
-
|
|
186
|
+
|
|
187
187
|
def as_frame(self, colname: str = "f") -> AxesFrame:
|
|
188
188
|
"""
|
|
189
189
|
N-dimensional data to DataFrame. The intensity data is stored in the `colname` column.
|
|
@@ -197,7 +197,7 @@ class PropArray(MetaArray):
|
|
|
197
197
|
-------
|
|
198
198
|
AxesFrame
|
|
199
199
|
DataFrame with PropArray data.
|
|
200
|
-
"""
|
|
200
|
+
"""
|
|
201
201
|
from ..frame import AxesFrame
|
|
202
202
|
if colname in self.axes:
|
|
203
203
|
raise ImageAxesError(f"Axis {colname} already exists.")
|
|
@@ -210,4 +210,3 @@ class PropArray(MetaArray):
|
|
|
210
210
|
df = AxesFrame(data_dict, columns=new_axes)
|
|
211
211
|
df.set_scale(self)
|
|
212
212
|
return df
|
|
213
|
-
|
impy/core.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
from contextlib import suppress
|
|
2
3
|
import os
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
import re
|
|
@@ -489,12 +490,12 @@ def broadcast_arrays(*arrays: MetaArray) -> list[MetaArray]:
|
|
|
489
490
|
out = [a.broadcast_to(shape, axes) for a in arrays]
|
|
490
491
|
return out
|
|
491
492
|
|
|
492
|
-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
493
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
493
494
|
# Imread functions
|
|
494
|
-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
495
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
495
496
|
|
|
496
497
|
def imread(
|
|
497
|
-
path: str,
|
|
498
|
+
path: str | Path,
|
|
498
499
|
dtype: DTypeLike = None,
|
|
499
500
|
key: AxesTargetedSlicer | None = None,
|
|
500
501
|
*,
|
|
@@ -502,6 +503,7 @@ def imread(
|
|
|
502
503
|
squeeze: bool = False,
|
|
503
504
|
) -> ImgArray:
|
|
504
505
|
"""Load image(s) from a path.
|
|
506
|
+
|
|
505
507
|
You can read list of images from directories with wildcards or ``"$"`` in ``path``.
|
|
506
508
|
|
|
507
509
|
Parameters
|
|
@@ -535,12 +537,30 @@ def imread(
|
|
|
535
537
|
Wall time: 3.01 ms
|
|
536
538
|
|
|
537
539
|
"""
|
|
538
|
-
|
|
540
|
+
if str(path).startswith("~"):
|
|
541
|
+
path = str(Path(path).expanduser())
|
|
542
|
+
else:
|
|
543
|
+
path = str(path)
|
|
544
|
+
|
|
545
|
+
# if a directory of a ome.tiff is given, read the first image (which will eventually
|
|
546
|
+
# read all the positions) and use the directory name as source/name.
|
|
547
|
+
if (_fp := Path(path)).is_dir() and _fp.suffix != ".zarr":
|
|
548
|
+
_first_tif = next(_fp.glob("*.ome.tif"), None)
|
|
549
|
+
if _first_tif is None:
|
|
550
|
+
raise ValueError(
|
|
551
|
+
"If a directory is given to imread, only directory of ome.tif is "
|
|
552
|
+
"supported. Please use wildcard like `path/to/dir/*.tif` to read "
|
|
553
|
+
"images in a directory."
|
|
554
|
+
)
|
|
555
|
+
out = imread(_first_tif, dtype=dtype, key=key, name=_fp.name, squeeze=squeeze)
|
|
556
|
+
out.source = _fp
|
|
557
|
+
return out
|
|
558
|
+
|
|
539
559
|
is_memmap = (key is not None)
|
|
540
560
|
|
|
541
561
|
if "$" in path:
|
|
542
562
|
return _imread_stack(path, dtype=dtype, key=key, squeeze=squeeze)
|
|
543
|
-
elif "*" in path:
|
|
563
|
+
elif "*" in path or "?" in path or "[" in path:
|
|
544
564
|
return _imread_glob(path, dtype=dtype, key=key, squeeze=squeeze)
|
|
545
565
|
elif not Path(path).exists():
|
|
546
566
|
raise FileNotFoundError(f"No such file or directory: {path}")
|
|
@@ -575,7 +595,8 @@ def imread(
|
|
|
575
595
|
# In case the image is in yxc-order. This sometimes happens.
|
|
576
596
|
self: ImgArray = np.moveaxis(self, -1, -3)
|
|
577
597
|
if labels is not None:
|
|
578
|
-
|
|
598
|
+
with suppress(ValueError):
|
|
599
|
+
self.set_axis_label(c=labels)
|
|
579
600
|
|
|
580
601
|
if dtype is None:
|
|
581
602
|
dtype = self.dtype
|
|
@@ -619,8 +640,9 @@ def _imread_glob(path: str, squeeze: bool = False, **kwargs) -> ImgArray:
|
|
|
619
640
|
out: ImgArray = np.stack(imgs, axis="p")
|
|
620
641
|
if squeeze:
|
|
621
642
|
out = np.squeeze(out)
|
|
643
|
+
sep = "*" if "*" in path else "?"
|
|
622
644
|
try:
|
|
623
|
-
base = os.path.split(path.split(
|
|
645
|
+
base = os.path.split(path.split(sep)[0])[0]
|
|
624
646
|
out.source = base
|
|
625
647
|
except Exception:
|
|
626
648
|
pass
|
impy/frame/frames.py
CHANGED
|
@@ -18,11 +18,11 @@ else:
|
|
|
18
18
|
|
|
19
19
|
class AxesFrame(pd.DataFrame):
|
|
20
20
|
_metadata = ["_axes"]
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
@property
|
|
23
23
|
def _constructor(self):
|
|
24
24
|
return AxesFrame
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
def __init__(self, data=None, columns=None, **kwargs):
|
|
27
27
|
if isinstance(columns, (str, Axes)):
|
|
28
28
|
kwargs["columns"] = [a for a in columns]
|
|
@@ -32,17 +32,17 @@ class AxesFrame(pd.DataFrame):
|
|
|
32
32
|
columns = str(data._axes)
|
|
33
33
|
else:
|
|
34
34
|
kwargs["columns"] = columns
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
super().__init__(data, **kwargs)
|
|
37
37
|
self._axes = Axes(self.columns)
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
def _get_coords_cols(self):
|
|
40
40
|
return [a for a in self.columns if len(a) == 1]
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
def get_coords(self):
|
|
43
43
|
return self[self.columns[self.columns.isin([a for a in self.columns if len(a) == 1])]]
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
|
|
45
|
+
|
|
46
46
|
def __getitem__(self, k):
|
|
47
47
|
# sl_tuple = solve_slicer(key, self.axes)
|
|
48
48
|
# drops: list[int] = []
|
|
@@ -56,7 +56,7 @@ class AxesFrame(pd.DataFrame):
|
|
|
56
56
|
# binary = np.logical_and(binary, (arr - s0) % step == 0)
|
|
57
57
|
# elif step < 0:
|
|
58
58
|
# raise NotImplementedError
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
# else:
|
|
61
61
|
# binary = arr == sl
|
|
62
62
|
# drops.append(i)
|
|
@@ -72,9 +72,9 @@ class AxesFrame(pd.DataFrame):
|
|
|
72
72
|
for each in k.split(";"):
|
|
73
73
|
self = self.__getitem__(each.strip())
|
|
74
74
|
return self
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
elif "=" in k:
|
|
77
|
-
axis, sl =
|
|
77
|
+
axis, sl = (a.strip() for a in k.split("="))
|
|
78
78
|
sl = str_to_slice(sl)
|
|
79
79
|
if isinstance(sl, int):
|
|
80
80
|
out = self[self[axis]==sl]
|
|
@@ -87,19 +87,19 @@ class AxesFrame(pd.DataFrame):
|
|
|
87
87
|
elif "" == k:
|
|
88
88
|
return self
|
|
89
89
|
else:
|
|
90
|
-
out = super().__getitem__(k)
|
|
90
|
+
out = super().__getitem__(k)
|
|
91
91
|
else:
|
|
92
92
|
out = super().__getitem__(k)
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
if isinstance(out, AxesFrame):
|
|
95
95
|
out._axes = Axes(out._get_coords_cols())
|
|
96
96
|
out.set_scale(self)
|
|
97
97
|
return out
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
@property
|
|
100
100
|
def col_axes(self):
|
|
101
101
|
return self._axes
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
@col_axes.setter
|
|
104
104
|
def col_axes(self, value):
|
|
105
105
|
naxes = self.shape[1]
|
|
@@ -113,11 +113,11 @@ class AxesFrame(pd.DataFrame):
|
|
|
113
113
|
f"array (ndim={naxes}) and axes ({value})"
|
|
114
114
|
)
|
|
115
115
|
self._axes = axes
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
@property
|
|
118
118
|
def scale(self):
|
|
119
119
|
return self._axes.scale
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
def set_scale(self, other=None, **kwargs) -> None:
|
|
122
122
|
"""
|
|
123
123
|
Set scales of each axis.
|
|
@@ -127,7 +127,7 @@ class AxesFrame(pd.DataFrame):
|
|
|
127
127
|
other : dict, AxesFrame or MetaArray, optional
|
|
128
128
|
New scales. If dict, it should be like {"x": 0.1, "y": 0.1}. If MetaArray, only
|
|
129
129
|
scales of common axes are copied.
|
|
130
|
-
kwargs :
|
|
130
|
+
kwargs :
|
|
131
131
|
This enables function call like set_scale(x=0.1, y=0.1).
|
|
132
132
|
|
|
133
133
|
"""
|
|
@@ -142,40 +142,29 @@ class AxesFrame(pd.DataFrame):
|
|
|
142
142
|
# check if all the keys are contained in axes.
|
|
143
143
|
for a, val in other.items():
|
|
144
144
|
if a not in self._axes:
|
|
145
|
-
raise ImageAxesError(f"Image does not have axis {a}.")
|
|
145
|
+
raise ImageAxesError(f"Image does not have axis {a}.")
|
|
146
146
|
elif not np.isscalar(val):
|
|
147
147
|
raise TypeError(f"Cannot set non-numeric value as scales.")
|
|
148
|
-
|
|
148
|
+
|
|
149
149
|
for k, v in other.items():
|
|
150
150
|
self.col_axes[k].scale = v
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
elif hasattr(other, "scale"):
|
|
153
153
|
self.set_scale({a: s for a, s in other.scale.items() if a in self._axes})
|
|
154
|
-
|
|
154
|
+
|
|
155
155
|
elif kwargs:
|
|
156
156
|
self.set_scale(dict(kwargs))
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
else:
|
|
159
159
|
raise TypeError(f"'other' must be str or MetaArray, but got {type(other)}")
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
return None
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
"""
|
|
165
|
-
t or c -> uint16
|
|
166
|
-
p -> uint32
|
|
167
|
-
z, y, x -> float32
|
|
168
|
-
"""
|
|
169
|
-
dtype = lambda a: np.uint16 if a in ["t", "c"] else (np.uint32 if a == Const["ID_AXIS"] else np.float32)
|
|
170
|
-
out = self.__class__(self.astype({a: dtype(a) for a in self.col_axes}))
|
|
171
|
-
out._axes = self._axes
|
|
172
|
-
return out
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
|
|
163
|
+
|
|
175
164
|
def split(self, axis="c") -> list[AxesFrame]:
|
|
176
165
|
"""
|
|
177
166
|
Split DataFrame according to its indices. For example, if self is an DataFrame with columns
|
|
178
|
-
"t", "c", "y", "x" and it is split along "c" axis, then output is a list of DataFrame with
|
|
167
|
+
"t", "c", "y", "x" and it is split along "c" axis, then output is a list of DataFrame with
|
|
179
168
|
columns "t", "y", "x".
|
|
180
169
|
|
|
181
170
|
Parameters
|
|
@@ -204,7 +193,7 @@ class AxesFrame(pd.DataFrame):
|
|
|
204
193
|
----------
|
|
205
194
|
axes : str
|
|
206
195
|
Along which axes to iterate.
|
|
207
|
-
|
|
196
|
+
|
|
208
197
|
Yields
|
|
209
198
|
-------
|
|
210
199
|
tuple and AxesFrame
|
|
@@ -214,10 +203,10 @@ class AxesFrame(pd.DataFrame):
|
|
|
214
203
|
outsl = [slice(None)] * len(self.col_axes)
|
|
215
204
|
cols = [a for a in self.col_axes if a not in axes]
|
|
216
205
|
groupkeys = [a for a in axes]
|
|
217
|
-
|
|
206
|
+
|
|
218
207
|
if len(groupkeys) == 0:
|
|
219
208
|
yield (slice(None),), self
|
|
220
|
-
|
|
209
|
+
|
|
221
210
|
else:
|
|
222
211
|
if len(groupkeys) == 1:
|
|
223
212
|
groupkeys = groupkeys[0]
|
|
@@ -227,21 +216,21 @@ class AxesFrame(pd.DataFrame):
|
|
|
227
216
|
sl = (sl,)
|
|
228
217
|
[outsl.__setitem__(i, s) for i, s in zip(indices, sl)]
|
|
229
218
|
yield tuple(outsl), af
|
|
230
|
-
|
|
219
|
+
|
|
231
220
|
def sort(self):
|
|
232
221
|
ids = self._axes.argsort()
|
|
233
222
|
return self[[self._axes[i] for i in ids]]
|
|
234
|
-
|
|
223
|
+
|
|
235
224
|
def proj(self, axis=None):
|
|
236
225
|
if axis is None:
|
|
237
226
|
axis = complement_axes("yx", self._axes)
|
|
238
227
|
cols = [a for a in self.col_axes if a not in axis]
|
|
239
228
|
return self[cols]
|
|
240
|
-
|
|
229
|
+
|
|
241
230
|
def tp_no_verbose(func):
|
|
242
231
|
"""
|
|
243
232
|
Temporary suppress logging in trackpy.
|
|
244
|
-
"""
|
|
233
|
+
"""
|
|
245
234
|
@wraps(func)
|
|
246
235
|
def wrapper(self, *args, **kwargs):
|
|
247
236
|
tp.quiet(suppress=True)
|
|
@@ -277,19 +266,19 @@ class MarkerFrame(AxesFrame):
|
|
|
277
266
|
-------
|
|
278
267
|
TrackFrame
|
|
279
268
|
Result of particle tracking.
|
|
280
|
-
"""
|
|
281
|
-
|
|
269
|
+
"""
|
|
270
|
+
|
|
282
271
|
linked = tp.link(pd.DataFrame(self), search_range=search_range, t_column="t", memory=memory, **kwargs)
|
|
283
|
-
|
|
272
|
+
|
|
284
273
|
linked.rename(columns = {"particle":Const["ID_AXIS"]}, inplace=True)
|
|
285
274
|
linked = linked.reindex(columns=[a for a in Const["ID_AXIS"]+str(self.col_axes)])
|
|
286
|
-
|
|
275
|
+
|
|
287
276
|
track = TrackFrame(linked, columns="".join(linked.columns.tolist()))
|
|
288
277
|
track.set_scale(self)
|
|
289
278
|
if min_dwell > 0:
|
|
290
279
|
out = track.filter_stubs(min_dwell)
|
|
291
280
|
else:
|
|
292
|
-
out = track
|
|
281
|
+
out = track
|
|
293
282
|
out.index = np.arange(len(out))
|
|
294
283
|
return out
|
|
295
284
|
|
|
@@ -298,7 +287,7 @@ class TrackFrame(AxesFrame):
|
|
|
298
287
|
df = pd.DataFrame(self, copy=True, dtype=np.float32)
|
|
299
288
|
df.rename(columns = {"t":"frame", Const["ID_AXIS"]:"particle"}, inplace=True)
|
|
300
289
|
return df
|
|
301
|
-
|
|
290
|
+
|
|
302
291
|
@tp_no_verbose
|
|
303
292
|
def track_drift(self, smoothing=0):
|
|
304
293
|
df = self._renamed_df()
|
|
@@ -307,25 +296,25 @@ class TrackFrame(AxesFrame):
|
|
|
307
296
|
ori = pd.DataFrame({"y":[0.], "x":[0.]}, dtype=np.float32)
|
|
308
297
|
shift = pd.concat([ori, shift], axis=0)
|
|
309
298
|
return MarkerFrame(shift)
|
|
310
|
-
|
|
299
|
+
|
|
311
300
|
@tp_no_verbose
|
|
312
301
|
def msd(self, max_lagt:int=100, detail:bool=False):
|
|
313
302
|
df = self._renamed_df()
|
|
314
|
-
return tp.motion.msd(df, self.scale["x"], self.scale["t"],
|
|
303
|
+
return tp.motion.msd(df, self.scale["x"], self.scale["t"],
|
|
315
304
|
max_lagtime=max_lagt, detail=detail)
|
|
316
|
-
|
|
305
|
+
|
|
317
306
|
@tp_no_verbose
|
|
318
307
|
def imsd(self, max_lagt=100):
|
|
319
308
|
df = self._renamed_df()
|
|
320
|
-
return tp.motion.imsd(df, self.scale["x"], self.scale["t"],
|
|
309
|
+
return tp.motion.imsd(df, self.scale["x"], self.scale["t"],
|
|
321
310
|
max_lagtime=max_lagt)
|
|
322
|
-
|
|
311
|
+
|
|
323
312
|
@tp_no_verbose
|
|
324
313
|
def emsd(self, max_lagt=100, detail=False):
|
|
325
314
|
df = self._renamed_df()
|
|
326
|
-
return tp.motion.emsd(df, self.scale["x"], self.scale["t"],
|
|
315
|
+
return tp.motion.emsd(df, self.scale["x"], self.scale["t"],
|
|
327
316
|
max_lagtime=max_lagt, detail=detail)
|
|
328
|
-
|
|
317
|
+
|
|
329
318
|
@tp_no_verbose
|
|
330
319
|
def filter_stubs(self, min_dwell=3):
|
|
331
320
|
df = self._renamed_df()
|
|
@@ -334,8 +323,8 @@ class TrackFrame(AxesFrame):
|
|
|
334
323
|
df = df.astype({"t":np.uint16, Const["ID_AXIS"]:np.uint32})
|
|
335
324
|
out = TrackFrame(df, columns=self.col_axes)
|
|
336
325
|
out.set_scale(self)
|
|
337
|
-
return out
|
|
338
|
-
|
|
326
|
+
return out
|
|
327
|
+
|
|
339
328
|
def as_path(self):
|
|
340
329
|
df = self[[a for a in self._axes if a != "t"]]
|
|
341
330
|
return PathFrame(df, columns=df._axes)
|
|
@@ -346,4 +335,4 @@ class PathFrame(AxesFrame):
|
|
|
346
335
|
dims = [a for a in "zyx" if a in self._axes]
|
|
347
336
|
path_len = lambda df: np.sum(np.sqrt(sum(np.diff(df[a])**2 for a in dims)))
|
|
348
337
|
c_axes = complement_axes(dims, self._axes)
|
|
349
|
-
return self.groupby(list(c_axes)).apply(path_len)
|
|
338
|
+
return self.groupby(list(c_axes)).apply(path_len)
|
impy/lazy/core.py
CHANGED
impy/viewer/utils.py
CHANGED
|
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
from napari.layers import Shapes
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def iter_layer(viewer:
|
|
19
|
+
def iter_layer(viewer:napari.Viewer, layer_type: str):
|
|
20
20
|
"""
|
|
21
21
|
Iterate over layers and yield only certain type of layers.
|
|
22
22
|
|
|
@@ -29,31 +29,31 @@ def iter_layer(viewer:"napari.Viewer", layer_type: str):
|
|
|
29
29
|
-------
|
|
30
30
|
napari.layers
|
|
31
31
|
Layers specified by layer_type
|
|
32
|
-
"""
|
|
32
|
+
"""
|
|
33
33
|
from napari import layers
|
|
34
34
|
if isinstance(layer_type, str):
|
|
35
35
|
layer_type = [layer_type]
|
|
36
36
|
layer_type = tuple(getattr(layers, t) for t in layer_type)
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
for layer in viewer.layers:
|
|
39
39
|
if isinstance(layer, layer_type):
|
|
40
40
|
yield layer
|
|
41
41
|
|
|
42
|
-
def iter_selected_layer(viewer:
|
|
42
|
+
def iter_selected_layer(viewer: napari.Viewer, layer_type: str | list[str]):
|
|
43
43
|
"""Iterate over selected layers and yield only certain type of layers."""
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
from napari import layers
|
|
46
46
|
if isinstance(layer_type, str):
|
|
47
47
|
layer_type = [layer_type]
|
|
48
48
|
layer_type = tuple(getattr(layers, t) for t in layer_type)
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
for layer in viewer.layers.selection:
|
|
51
51
|
if isinstance(layer, layer_type):
|
|
52
52
|
yield layer
|
|
53
53
|
|
|
54
|
-
def front_image(viewer:
|
|
55
|
-
"""From list of image layers return the most front visible image."""
|
|
56
|
-
|
|
54
|
+
def front_image(viewer:napari.Viewer):
|
|
55
|
+
"""From list of image layers return the most front visible image."""
|
|
56
|
+
|
|
57
57
|
front = None
|
|
58
58
|
for img in iter_layer(viewer, "Image"):
|
|
59
59
|
if img.visible:
|
|
@@ -62,7 +62,7 @@ def front_image(viewer:"napari.Viewer"):
|
|
|
62
62
|
raise ValueError("There is no visible image layer.")
|
|
63
63
|
return front
|
|
64
64
|
|
|
65
|
-
def to_labels(layer:
|
|
65
|
+
def to_labels(layer: Shapes, labels_shape: tuple[int, ...], zoom_factor: float = 1.):
|
|
66
66
|
"""Convert a Shapes layer to labels, with given zoom factor."""
|
|
67
67
|
return layer._data_view.to_labels(
|
|
68
68
|
labels_shape=labels_shape, zoom_factor=zoom_factor
|
|
@@ -79,9 +79,9 @@ def make_world_scale(obj):
|
|
|
79
79
|
scale.append(1)
|
|
80
80
|
return scale
|
|
81
81
|
|
|
82
|
-
def viewer_imread(viewer:
|
|
82
|
+
def viewer_imread(viewer: napari.Viewer, path: str):
|
|
83
83
|
"""Read an image into the viewer."""
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
if "*" in path or os.path.getsize(path)/2**30 < Const["MAX_GB"]:
|
|
86
86
|
img = imread(path)
|
|
87
87
|
else:
|
|
@@ -89,9 +89,9 @@ def viewer_imread(viewer: "napari.Viewer", path: str):
|
|
|
89
89
|
layer = add_labeledarray(viewer, img)
|
|
90
90
|
return layer
|
|
91
91
|
|
|
92
|
-
def add_labeledarray(viewer:
|
|
92
|
+
def add_labeledarray(viewer: napari.Viewer, img: LabeledArray, **kwargs):
|
|
93
93
|
"""Add a LabeledArray to the viewer."""
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
if not img.axes.is_sorted() and img.ndim > 2:
|
|
96
96
|
msg = (
|
|
97
97
|
f"Input image has axes that are not correctly sorted: {img.axes}. "
|
|
@@ -99,15 +99,15 @@ def add_labeledarray(viewer: "napari.Viewer", img: LabeledArray, **kwargs):
|
|
|
99
99
|
)
|
|
100
100
|
warnings.warn(msg, UserWarning)
|
|
101
101
|
chn_ax = img.axisof("c") if "c" in img.axes else None
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
if isinstance(img, PhaseArray) and not "colormap" in kwargs.keys():
|
|
104
104
|
kwargs["colormap"] = "hsv"
|
|
105
105
|
kwargs["contrast_limits"] = img.border
|
|
106
106
|
elif img.dtype.kind == "c" and not "colormap" in kwargs.keys():
|
|
107
107
|
kwargs["colormap"] = "plasma"
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
scale = make_world_scale(img)
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
if "name" in kwargs:
|
|
112
112
|
name = kwargs.pop("name")
|
|
113
113
|
else:
|
|
@@ -116,20 +116,20 @@ def add_labeledarray(viewer: "napari.Viewer", img: LabeledArray, **kwargs):
|
|
|
116
116
|
name = [f"[C{i}]{name}" for i in range(img.shape.c)]
|
|
117
117
|
else:
|
|
118
118
|
name = [name]
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
if img.dtype.kind == "c":
|
|
121
121
|
input = ComplexArrayView(img)
|
|
122
122
|
else:
|
|
123
123
|
input = img
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
layer = viewer.add_image(
|
|
126
126
|
input,
|
|
127
127
|
channel_axis=chn_ax,
|
|
128
|
-
scale=scale,
|
|
128
|
+
scale=scale,
|
|
129
129
|
name=name if len(name) > 1 else name[0],
|
|
130
130
|
**kwargs
|
|
131
131
|
)
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
if viewer.scale_bar.unit:
|
|
134
134
|
if viewer.scale_bar.unit != img.scale_unit:
|
|
135
135
|
msg = (
|
|
@@ -139,7 +139,7 @@ def add_labeledarray(viewer: "napari.Viewer", img: LabeledArray, **kwargs):
|
|
|
139
139
|
warnings.warn(msg)
|
|
140
140
|
else:
|
|
141
141
|
viewer.scale_bar.unit = img.scale_unit
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
new_axes = [str(a) for a in img.axes if a != "c"]
|
|
144
144
|
# add axis labels to slide bars and image orientation.
|
|
145
145
|
if len(new_axes) >= len(viewer.dims.axis_labels):
|
|
@@ -147,10 +147,10 @@ def add_labeledarray(viewer: "napari.Viewer", img: LabeledArray, **kwargs):
|
|
|
147
147
|
return layer
|
|
148
148
|
|
|
149
149
|
def add_labels(
|
|
150
|
-
viewer:
|
|
150
|
+
viewer: napari.Viewer,
|
|
151
151
|
labels: Label,
|
|
152
152
|
opacity: float = 0.3,
|
|
153
|
-
name: str | list[str] | None = None,
|
|
153
|
+
name: str | list[str] | None = None,
|
|
154
154
|
**kwargs
|
|
155
155
|
):
|
|
156
156
|
scale = make_world_scale(labels)
|
|
@@ -159,7 +159,7 @@ def add_labels(
|
|
|
159
159
|
lbls = labels.split("c")
|
|
160
160
|
else:
|
|
161
161
|
lbls = [labels]
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
# prepare name list
|
|
164
164
|
if isinstance(name, list):
|
|
165
165
|
names = [f"[L]{n}" for n in name]
|
|
@@ -167,19 +167,19 @@ def add_labels(
|
|
|
167
167
|
names = [f"[L]{name}"] * len(lbls)
|
|
168
168
|
else:
|
|
169
169
|
names = [labels.name]
|
|
170
|
-
|
|
170
|
+
|
|
171
171
|
kw = dict(opacity=opacity, scale=scale)
|
|
172
172
|
kw.update(kwargs)
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
out_layers = []
|
|
175
175
|
for lbl, name in zip(lbls, names):
|
|
176
176
|
layer = viewer.add_labels(lbl.value, name=name, **kw)
|
|
177
177
|
out_layers.append(layer)
|
|
178
178
|
return out_layers
|
|
179
179
|
|
|
180
|
-
def add_dask(viewer:
|
|
180
|
+
def add_dask(viewer: napari.Viewer, img: LazyImgArray, **kwargs):
|
|
181
181
|
chn_ax = img.axisof("c") if "c" in img.axes else None
|
|
182
|
-
|
|
182
|
+
|
|
183
183
|
scale = make_world_scale(img)
|
|
184
184
|
name = img.name
|
|
185
185
|
|
|
@@ -188,7 +188,7 @@ def add_dask(viewer: "napari.Viewer", img: LazyImgArray, **kwargs):
|
|
|
188
188
|
else:
|
|
189
189
|
name = ["[Lazy]" + name]
|
|
190
190
|
|
|
191
|
-
layer = viewer.add_image(img, channel_axis=chn_ax, scale=scale,
|
|
191
|
+
layer = viewer.add_image(img, channel_axis=chn_ax, scale=scale,
|
|
192
192
|
name=name if len(name)>1 else name[0], **kwargs)
|
|
193
193
|
viewer.scale_bar.unit = img.scale_unit
|
|
194
194
|
new_axes = [str(a) for a in img.axes if a != "c"]
|
|
@@ -197,19 +197,19 @@ def add_dask(viewer: "napari.Viewer", img: LazyImgArray, **kwargs):
|
|
|
197
197
|
viewer.dims.axis_labels = new_axes
|
|
198
198
|
return layer
|
|
199
199
|
|
|
200
|
-
def add_points(viewer:
|
|
200
|
+
def add_points(viewer:napari.Viewer, points: AxesFrame, **kwargs):
|
|
201
201
|
from ..frame import MarkerFrame
|
|
202
202
|
if isinstance(points, MarkerFrame):
|
|
203
203
|
scale = make_world_scale(points)
|
|
204
204
|
points = points.get_coords()
|
|
205
205
|
else:
|
|
206
206
|
scale=None
|
|
207
|
-
|
|
207
|
+
|
|
208
208
|
if "c" in points._axes:
|
|
209
209
|
pnts = points.split("c")
|
|
210
210
|
else:
|
|
211
211
|
pnts = [points]
|
|
212
|
-
|
|
212
|
+
|
|
213
213
|
for each in pnts:
|
|
214
214
|
metadata = {"axes": str(each._axes), "scale": each.scale}
|
|
215
215
|
kw = dict(
|
|
@@ -219,30 +219,30 @@ def add_points(viewer:"napari.Viewer", points: AxesFrame, **kwargs):
|
|
|
219
219
|
)
|
|
220
220
|
kw.update(kwargs)
|
|
221
221
|
viewer.add_points(each.values, scale=scale, **kw)
|
|
222
|
-
|
|
222
|
+
|
|
223
223
|
return None
|
|
224
224
|
|
|
225
|
-
def add_tracks(viewer:
|
|
225
|
+
def add_tracks(viewer:napari.Viewer, track: TrackFrame, **kwargs):
|
|
226
226
|
if "c" in track._axes:
|
|
227
227
|
track_list = track.split("c")
|
|
228
228
|
else:
|
|
229
229
|
track_list = [track]
|
|
230
|
-
|
|
230
|
+
|
|
231
231
|
scale = make_world_scale(
|
|
232
232
|
track[[a for a in track._axes if a != Const["ID_AXIS"]]]
|
|
233
233
|
)
|
|
234
234
|
for tr in track_list:
|
|
235
235
|
metadata = {"axes": str(tr._axes), "scale": tr.scale}
|
|
236
236
|
viewer.add_tracks(tr, scale=scale, metadata=metadata, **kwargs)
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
return None
|
|
239
239
|
|
|
240
|
-
def add_paths(viewer:
|
|
240
|
+
def add_paths(viewer: napari.Viewer, paths: PathFrame, **kwargs):
|
|
241
241
|
if "c" in paths._axes:
|
|
242
242
|
path_list = paths.split("c")
|
|
243
243
|
else:
|
|
244
244
|
path_list = [paths]
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
scale = make_world_scale(
|
|
247
247
|
paths[[a for a in paths._axes if a != Const["ID_AXIS"]]]
|
|
248
248
|
)
|
|
@@ -253,19 +253,19 @@ def add_paths(viewer: "napari.Viewer", paths: PathFrame, **kwargs):
|
|
|
253
253
|
metadata = {"axes": str(path._axes), "scale": path.scale}
|
|
254
254
|
paths = [single_path.values for single_path in path.split(Const["ID_AXIS"])]
|
|
255
255
|
viewer.add_shapes(paths, scale=scale, metadata=metadata, **kw)
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
return None
|
|
258
258
|
|
|
259
|
-
def add_rois(viewer:
|
|
259
|
+
def add_rois(viewer: napari.Viewer, rois: Iterable[Roi], **kwargs):
|
|
260
260
|
from ..roi import LineRoi, PointRoi, PolygonRoi, PolyLineRoi, RectangleRoi
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
_map = {
|
|
263
263
|
LineRoi: "line",
|
|
264
264
|
PolygonRoi: "polygon",
|
|
265
265
|
PolyLineRoi: "path",
|
|
266
266
|
RectangleRoi: "rectangle",
|
|
267
267
|
}
|
|
268
|
-
|
|
268
|
+
|
|
269
269
|
shapes = []
|
|
270
270
|
shape_types = []
|
|
271
271
|
for roi in rois:
|
|
@@ -274,16 +274,16 @@ def add_rois(viewer: "napari.Viewer", rois: Iterable[Roi], **kwargs):
|
|
|
274
274
|
else:
|
|
275
275
|
shape_types.append(_map[type(roi)])
|
|
276
276
|
shapes.append(np.array(roi))
|
|
277
|
-
|
|
277
|
+
|
|
278
278
|
viewer.add_shapes(shapes, shape_type=shape_types, **kwargs)
|
|
279
|
-
|
|
279
|
+
|
|
280
280
|
return None
|
|
281
281
|
|
|
282
|
-
def get_viewer_scale(viewer:
|
|
282
|
+
def get_viewer_scale(viewer: napari.Viewer):
|
|
283
283
|
"""Get the scale of the viewer."""
|
|
284
284
|
return {a: r[2] for a, r in zip(viewer.dims.axis_labels, viewer.dims.range)}
|
|
285
285
|
|
|
286
|
-
def layer_to_impy_object(viewer:
|
|
286
|
+
def layer_to_impy_object(viewer: napari.Viewer, layer):
|
|
287
287
|
"""
|
|
288
288
|
Convert layer to real data.
|
|
289
289
|
|
|
@@ -295,7 +295,7 @@ def layer_to_impy_object(viewer: "napari.Viewer", layer):
|
|
|
295
295
|
Returns
|
|
296
296
|
-------
|
|
297
297
|
ImgArray, Label, MarkerFrame or TrackFrame, or Shape features.
|
|
298
|
-
"""
|
|
298
|
+
"""
|
|
299
299
|
data = layer.data
|
|
300
300
|
axes = "".join(viewer.dims.axis_labels)
|
|
301
301
|
scale = get_viewer_scale(viewer)
|
|
@@ -321,21 +321,21 @@ def layer_to_impy_object(viewer: "napari.Viewer", layer):
|
|
|
321
321
|
ndim = data.shape[1]
|
|
322
322
|
axes = axes[-ndim:]
|
|
323
323
|
df = MarkerFrame(data, columns=layer.metadata.get("axes", axes))
|
|
324
|
-
df.set_scale(layer.metadata.get("scale",
|
|
324
|
+
df.set_scale(layer.metadata.get("scale",
|
|
325
325
|
{k: v for k, v in scale.items() if k in axes}))
|
|
326
|
-
return df
|
|
326
|
+
return df
|
|
327
327
|
elif isinstance(layer, Tracks):
|
|
328
328
|
from ..frame import TrackFrame
|
|
329
329
|
ndim = data.shape[1]
|
|
330
330
|
axes = axes[-ndim:]
|
|
331
331
|
df = TrackFrame(data, columns=layer.metadata.get("axes", axes))
|
|
332
|
-
df.set_scale(layer.metadata.get("scale",
|
|
332
|
+
df.set_scale(layer.metadata.get("scale",
|
|
333
333
|
{k: v for k, v in scale.items() if k in axes}))
|
|
334
|
-
return df
|
|
334
|
+
return df
|
|
335
335
|
else:
|
|
336
336
|
raise NotImplementedError(type(layer))
|
|
337
337
|
|
|
338
|
-
def get_a_selected_layer(viewer:
|
|
338
|
+
def get_a_selected_layer(viewer:napari.Viewer):
|
|
339
339
|
selected = list(viewer.layers.selection)
|
|
340
340
|
if len(selected) == 0:
|
|
341
341
|
raise ValueError("No layer is selected.")
|
|
@@ -352,34 +352,34 @@ class ComplexArrayView:
|
|
|
352
352
|
if data.dtype.kind != "c":
|
|
353
353
|
raise TypeError("Input was not a complex array.")
|
|
354
354
|
self._data = data
|
|
355
|
-
|
|
355
|
+
|
|
356
356
|
def __array__(self, dtype=None, copy=False) -> np.ndarray:
|
|
357
357
|
return np.abs(self._data)
|
|
358
|
-
|
|
358
|
+
|
|
359
359
|
@property
|
|
360
360
|
def data_raw(self) -> _A:
|
|
361
361
|
"""Return the raw data."""
|
|
362
362
|
return self._data
|
|
363
|
-
|
|
363
|
+
|
|
364
364
|
@property
|
|
365
365
|
def shape(self) -> tuple:
|
|
366
366
|
"""Shape of array."""
|
|
367
367
|
return self._data.shape
|
|
368
|
-
|
|
368
|
+
|
|
369
369
|
@property
|
|
370
370
|
def ndim(self) -> int:
|
|
371
371
|
"""Number of dimensions of array."""
|
|
372
372
|
return self._data.ndim
|
|
373
|
-
|
|
373
|
+
|
|
374
374
|
@property
|
|
375
375
|
def dtype(self) -> np.dtype:
|
|
376
376
|
"""Data type of array."""
|
|
377
377
|
return self._data.dtype
|
|
378
|
-
|
|
378
|
+
|
|
379
379
|
@property
|
|
380
380
|
def nbytes(self) -> int:
|
|
381
381
|
"""Bytes of array."""
|
|
382
382
|
return self._data.nbytes
|
|
383
|
-
|
|
383
|
+
|
|
384
384
|
def __getitem__(self, key):
|
|
385
|
-
return self.__class__(self._data[key])
|
|
385
|
+
return self.__class__(self._data[key])
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
impy/__init__.py,sha256=
|
|
1
|
+
impy/__init__.py,sha256=aibzVT5sn4GqWH_rElWQlVWdtgap0hDKqlCnALbn1P8,1638
|
|
2
2
|
impy/__main__.py,sha256=BAQkQ4X8EFo42pbNx__EqpZ5KL4MTfTUWsVbJIQF0O0,4974
|
|
3
3
|
impy/_const.py,sha256=uNHxxY5ltZuOsJWpwlBWFmUM0QfMgIk5WODqlHuBomo,3700
|
|
4
4
|
impy/_types.py,sha256=gO4l0hx9qxe6eI0PyC4ukW3k4IYxCEZ9gT-rQ3jj3zU,808
|
|
5
5
|
impy/array_api.py,sha256=9suP_Wck9maSiEa5qK6aZrCfaky6xhCMfIRcc9WuIs8,5585
|
|
6
6
|
impy/binder.py,sha256=CTMb11g6uYDVVQV5Wtef865IO0G2V3vGXc8SiGYRD5k,9651
|
|
7
7
|
impy/collections.py,sha256=2e55bLjZN7W4LFUCkyxekcDfLwZodMaU4JG5NQ3RS54,10946
|
|
8
|
-
impy/core.py,sha256=
|
|
8
|
+
impy/core.py,sha256=ntvPvL48PvX_tlxb7_KXMF8HGV8q-7Hh_wlIuMljxb4,26527
|
|
9
9
|
impy/correlation.py,sha256=Yw1T_0eL9FmsMcnCysc49oRJQMn8ho5z9bAzNg5i59Y,28232
|
|
10
10
|
impy/random.py,sha256=MQl0ViN6A7xDtM8BS4gbv1atgPKsrmp0TXzV1OtsDlU,7004
|
|
11
11
|
impy/roi.py,sha256=p9ttjBl5SGHHXj0xg5UjPlg_V9cY3MnNZxFfYIjTYsg,14164
|
|
@@ -13,12 +13,12 @@ impy/arrays/__init__.py,sha256=IHpTBIJysomS64rOZsv960YBmM1vc4M-asTSs1OJBWg,454
|
|
|
13
13
|
impy/arrays/_imshow.py,sha256=6mJ_PDqmE4UZO9e9SUgyY_YrzQdR2QKlTG7KF_aC_tI,6949
|
|
14
14
|
impy/arrays/axesmixin.py,sha256=NwiPldNbD3rYpvuydviJMEoH88-joHdfQuuXLE6Rs7c,10454
|
|
15
15
|
impy/arrays/big.py,sha256=tHNijyPgyIfTltLP3hQwZdHOpSX3IwG5DHPamajZ8Kg,2745
|
|
16
|
-
impy/arrays/imgarray.py,sha256=
|
|
16
|
+
impy/arrays/imgarray.py,sha256=qAZ_ZtK4rFisXta1W5jrF7b71ivoLLT6NbzY-MIHVWA,161761
|
|
17
17
|
impy/arrays/label.py,sha256=l0SZXcZxU8qwUgj0QZPZ32XsNaoBtenlrn6hNR03SPI,6406
|
|
18
|
-
impy/arrays/labeledarray.py,sha256=
|
|
19
|
-
impy/arrays/lazy.py,sha256=
|
|
18
|
+
impy/arrays/labeledarray.py,sha256=9fT0bVqyByYG1ifyQzzC1y8KdEUx_hrfNI7Vex_EAvs,59026
|
|
19
|
+
impy/arrays/lazy.py,sha256=lRRRN25WE9v2TwOl37Dny6OuyPv-be8dsBJ6vqHnkQY,60982
|
|
20
20
|
impy/arrays/phasearray.py,sha256=IojWaNs5sEujn6Lhgqe00H0xF-4CZEFWt5cVW6U_DWQ,13981
|
|
21
|
-
impy/arrays/specials.py,sha256=
|
|
21
|
+
impy/arrays/specials.py,sha256=M2EmpYNChc4FoAAZvkRq8OKq2zLAd6TWqKIF_lfpCqg,7666
|
|
22
22
|
impy/arrays/tiled.py,sha256=T44sS6v1Ovln1z1g61Eg8irgZR1Jmpb6BCY3nS6TmDE,9400
|
|
23
23
|
impy/arrays/_utils/__init__.py,sha256=M5HogfyUBvV8kp-X1ZthS8vDLUP7-O2f9Gvsc1ZXdT8,271
|
|
24
24
|
impy/arrays/_utils/_corr.py,sha256=ThGQV3KSv8ir8BTWDoV83ysalPB2p--LmSCv-J9qq2w,10047
|
|
@@ -42,7 +42,7 @@ impy/axes/_axes_tuple.py,sha256=hkgTr_n36gFcnnffmSp3z4oJ_52MxT1JnaszdJ3JnrY,1522
|
|
|
42
42
|
impy/axes/_axis.py,sha256=TlaF_Ya1DLcNwz8LFAL4xWC0Xt8HA0WR4ZUC3SYJPP0,7469
|
|
43
43
|
impy/axes/_slicer.py,sha256=Ts4m9V3PBlEb3xeHd6j1XdMEb1SwYGbBF5rnC9WWYZE,2657
|
|
44
44
|
impy/frame/__init__.py,sha256=Z4XfXzFSDq49tMrVoeYx1ThnHyw43iLVSVcte6b6-as,65
|
|
45
|
-
impy/frame/frames.py,sha256=
|
|
45
|
+
impy/frame/frames.py,sha256=RGFbRd5h7fSI-t1b2lt2GCF_Y9N8dkIFvkH6E63qFJ4,11720
|
|
46
46
|
impy/io/__init__.py,sha256=Xz7SeHkDDbLm3Z9gqav3iByLsmsBoLjol4nDtEq-WeY,315
|
|
47
47
|
impy/io/_czi.py,sha256=0FQsrzL9ygaB6IHITceAmLsOxkLFKwlQFKSLQCmJbyY,1667
|
|
48
48
|
impy/io/_mrc.py,sha256=i3_GHxBdM8f0NYnqU7Oklw6wM7boYcLzWwBTU7V3Y2U,3936
|
|
@@ -53,7 +53,7 @@ impy/io/_tiff.py,sha256=kfRB6H-fKBk-lrv_y6tY2fNbG_BEcPm2Ja41-0EtZ_8,6528
|
|
|
53
53
|
impy/io/_utils.py,sha256=WHAiuCC1_tdsZ07HLM8jKjptKnQGevG7eXdnuJd069o,3723
|
|
54
54
|
impy/io/_zarr.py,sha256=Nfr5VJ3DzKN5d7nYoq_ZG9AG2GIDWHYJ33LpG9SwGcs,1336
|
|
55
55
|
impy/lazy/__init__.py,sha256=hRjpE2zCy5qDAr_27imwRM9J0C7q-a_b5wfC3ux8ZLE,59
|
|
56
|
-
impy/lazy/core.py,sha256=
|
|
56
|
+
impy/lazy/core.py,sha256=LQMHl8cKBiGc972PFRP3jJungv8MtBn6B24bI4aFQWs,9670
|
|
57
57
|
impy/lazy/random.py,sha256=2rwHRsHPOvi8tI9kTtGuZ5SzN0MA7yn-30bZSvHeLVc,7713
|
|
58
58
|
impy/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
impy/utils/axesop.py,sha256=c86XdNlUBFLrwHhAT2j0eELxopNe2QEVaNeOQhXr2do,3076
|
|
@@ -63,10 +63,10 @@ impy/utils/misc.py,sha256=zV_NeqEaiTW4Rki5fqWfspQjczRaoTJ5MxTOUx6qstY,622
|
|
|
63
63
|
impy/utils/slicer.py,sha256=otDrizWdzoUjFUMlsha0zNFSS4TkgAmLPOAotaTVaUA,4316
|
|
64
64
|
impy/utils/utilcls.py,sha256=3Td9G2ZkU4C0BiW2LH0sq7RBjdco_BtyxNr-s-seLhs,437
|
|
65
65
|
impy/viewer/__init__.py,sha256=MH-jhpFxP8JVJwUzbKMLRhhWSEYavVHuik9uOS3dDNU,292
|
|
66
|
-
impy/viewer/utils.py,sha256=
|
|
66
|
+
impy/viewer/utils.py,sha256=Giv1Q50gXDHQZoJyrGJEBUKCKfOQLkRB6fC5NE2rzg0,11971
|
|
67
67
|
impy/viewer/viewer.py,sha256=Sfq-obSLoHkBkIW0NDWCxEEaX7-YsC4ifAJ-nxpvJws,17632
|
|
68
|
-
impy_array-2.5.
|
|
69
|
-
impy_array-2.5.
|
|
70
|
-
impy_array-2.5.
|
|
71
|
-
impy_array-2.5.
|
|
72
|
-
impy_array-2.5.
|
|
68
|
+
impy_array-2.5.2.dist-info/METADATA,sha256=_HvcusR2hwLfWqpdpTaYv7x3Zhi73k5kDb6zaKECFeY,7567
|
|
69
|
+
impy_array-2.5.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
70
|
+
impy_array-2.5.2.dist-info/entry_points.txt,sha256=reyrgy4odXvi1CcPOIIyRYBmsNGG2tO7ZkFOdG5CBkU,44
|
|
71
|
+
impy_array-2.5.2.dist-info/licenses/LICENSE,sha256=rpxKafH9r42sxLLYYB5VbZBHOdtYeLuYJjVU1LBwrxk,1546
|
|
72
|
+
impy_array-2.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|