dclab 0.63.1__cp39-cp39-musllinux_1_2_x86_64.whl → 0.64.0__cp39-cp39-musllinux_1_2_x86_64.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.
Potentially problematic release.
This version of dclab might be problematic. Click here for more details.
- dclab/_version.py +2 -2
- dclab/downsampling.cpython-39-x86_64-linux-gnu.so +0 -0
- dclab/external/skimage/_find_contours_cy.cpython-39-x86_64-linux-gnu.so +0 -0
- dclab/external/skimage/_pnpoly.cpython-39-x86_64-linux-gnu.so +0 -0
- dclab/external/skimage/_shared/geometry.cpython-39-x86_64-linux-gnu.so +0 -0
- dclab/http_utils.py +1 -1
- dclab/kde/base.py +143 -5
- dclab/kde/methods.py +10 -0
- dclab/rtdc_dataset/core.py +13 -4
- dclab/rtdc_dataset/export.py +8 -3
- dclab/rtdc_dataset/feat_basin.py +138 -3
- dclab/rtdc_dataset/fmt_dcor/api.py +70 -8
- dclab/rtdc_dataset/fmt_dcor/base.py +103 -4
- dclab/rtdc_dataset/fmt_dcor/logs.py +1 -1
- dclab/rtdc_dataset/fmt_dcor/tables.py +1 -1
- dclab/rtdc_dataset/writer.py +12 -4
- {dclab-0.63.1.dist-info → dclab-0.64.0.dist-info}/METADATA +2 -2
- {dclab-0.63.1.dist-info → dclab-0.64.0.dist-info}/RECORD +22 -22
- {dclab-0.63.1.dist-info → dclab-0.64.0.dist-info}/WHEEL +1 -1
- {dclab-0.63.1.dist-info → dclab-0.64.0.dist-info}/entry_points.txt +0 -0
- {dclab-0.63.1.dist-info → dclab-0.64.0.dist-info}/licenses/LICENSE +0 -0
- {dclab-0.63.1.dist-info → dclab-0.64.0.dist-info}/top_level.txt +0 -0
dclab/_version.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
dclab/http_utils.py
CHANGED
dclab/kde/base.py
CHANGED
|
@@ -2,7 +2,12 @@ import warnings
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
|
-
from .methods import
|
|
5
|
+
from .methods import bin_width_doane_div5, get_bad_vals, methods
|
|
6
|
+
from .contours import find_contours_level, get_quantile_levels
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContourSpacingTooLarge(UserWarning):
|
|
10
|
+
pass
|
|
6
11
|
|
|
7
12
|
|
|
8
13
|
class KernelDensityEstimator:
|
|
@@ -107,6 +112,139 @@ class KernelDensityEstimator:
|
|
|
107
112
|
yscale: str
|
|
108
113
|
See `xscale`.
|
|
109
114
|
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
X, Y, Z : coordinates
|
|
118
|
+
The kernel density Z evaluated on a rectangular grid (X,Y).
|
|
119
|
+
"""
|
|
120
|
+
warnings.warn("`get_contour` is deprecated; please use "
|
|
121
|
+
"`get_raster` instead", DeprecationWarning)
|
|
122
|
+
return self.get_raster(
|
|
123
|
+
xax=xax, yax=yax, xacc=xacc, yacc=yacc,
|
|
124
|
+
kde_type=kde_type, kde_kwargs=kde_kwargs,
|
|
125
|
+
xscale=xscale, yscale=yscale
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def get_contour_lines(self, quantiles=None, xax="area_um", yax="deform",
|
|
129
|
+
xacc=None, yacc=None, kde_type="histogram",
|
|
130
|
+
kde_kwargs=None, xscale="linear", yscale="linear",
|
|
131
|
+
ret_levels=False):
|
|
132
|
+
"""Compute contour lines for a given kernel kensity estimate.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
quantiles: list or array of floats
|
|
137
|
+
KDE Quantiles for which contour levels are computed. The
|
|
138
|
+
values must be between 0 and 1. If set to None, use
|
|
139
|
+
[0.5, 0.95] as default.
|
|
140
|
+
xax: str
|
|
141
|
+
Identifier for X axis (e.g. "area_um", "aspect", "deform")
|
|
142
|
+
yax: str
|
|
143
|
+
Identifier for Y axis
|
|
144
|
+
xacc: float
|
|
145
|
+
Contour accuracy in x direction
|
|
146
|
+
if set to None, will use :func:`bin_width_doane_div5`
|
|
147
|
+
yacc: float
|
|
148
|
+
Contour accuracy in y direction
|
|
149
|
+
if set to None, will use :func:`bin_width_doane_div5`
|
|
150
|
+
kde_type: str
|
|
151
|
+
The KDE method to use
|
|
152
|
+
kde_kwargs: dict
|
|
153
|
+
Additional keyword arguments to the KDE method
|
|
154
|
+
xscale: str
|
|
155
|
+
If set to "log", take the logarithm of the x-values before
|
|
156
|
+
computing the KDE. This is useful when data are
|
|
157
|
+
displayed on a log-scale. Defaults to "linear".
|
|
158
|
+
yscale: str
|
|
159
|
+
See `xscale`
|
|
160
|
+
ret_levels: bool
|
|
161
|
+
If set to True, return the levels of the contours
|
|
162
|
+
(default: False)
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
contour_lines: list of lists (of lists)
|
|
167
|
+
For every number in `quantiles`, this list contains a list of
|
|
168
|
+
corresponding contour lines. Each contour line is a 2D
|
|
169
|
+
array of shape (N, 2), where N is the number of points in the
|
|
170
|
+
contour line.
|
|
171
|
+
levels: list of floats
|
|
172
|
+
The density levels corresponding to each number in `quantiles`.
|
|
173
|
+
Only returned if `ret_levels` is set to True.
|
|
174
|
+
"""
|
|
175
|
+
if not quantiles:
|
|
176
|
+
quantiles = [0.5, 0.95]
|
|
177
|
+
try:
|
|
178
|
+
x, y, density = self.get_raster(
|
|
179
|
+
xax=xax,
|
|
180
|
+
yax=yax,
|
|
181
|
+
xacc=xacc,
|
|
182
|
+
yacc=yacc,
|
|
183
|
+
xscale=xscale,
|
|
184
|
+
yscale=yscale,
|
|
185
|
+
kde_type=kde_type,
|
|
186
|
+
kde_kwargs=kde_kwargs,
|
|
187
|
+
)
|
|
188
|
+
except ValueError:
|
|
189
|
+
# most-likely there is nothing to compute a contour for
|
|
190
|
+
return []
|
|
191
|
+
if density.shape[0] < 3 or density.shape[1] < 3:
|
|
192
|
+
warnings.warn("Contour not possible; spacing may be too large!",
|
|
193
|
+
ContourSpacingTooLarge)
|
|
194
|
+
return []
|
|
195
|
+
levels = get_quantile_levels(
|
|
196
|
+
density=density,
|
|
197
|
+
x=x,
|
|
198
|
+
y=y,
|
|
199
|
+
xp=self.rtdc_ds[xax][self.rtdc_ds.filter.all],
|
|
200
|
+
yp=self.rtdc_ds[yax][self.rtdc_ds.filter.all],
|
|
201
|
+
q=np.array(quantiles),
|
|
202
|
+
normalize=False)
|
|
203
|
+
contours = []
|
|
204
|
+
# Normalize levels to [0, 1]
|
|
205
|
+
nlevels = np.array(levels) / density.max()
|
|
206
|
+
for nlev in nlevels:
|
|
207
|
+
# make sure that the contour levels are not at the boundaries
|
|
208
|
+
if not (np.allclose(nlev, 0, atol=1e-12, rtol=0)
|
|
209
|
+
or np.allclose(nlev, 1, atol=1e-12, rtol=0)):
|
|
210
|
+
cc = find_contours_level(
|
|
211
|
+
density, x=x, y=y, level=nlev)
|
|
212
|
+
contours.append(cc)
|
|
213
|
+
else:
|
|
214
|
+
contours.append([])
|
|
215
|
+
if ret_levels:
|
|
216
|
+
return contours, levels
|
|
217
|
+
else:
|
|
218
|
+
return contours
|
|
219
|
+
|
|
220
|
+
def get_raster(self, xax="area_um", yax="deform", xacc=None, yacc=None,
|
|
221
|
+
kde_type="histogram", kde_kwargs=None, xscale="linear",
|
|
222
|
+
yscale="linear"):
|
|
223
|
+
"""Evaluate the kernel density estimate on a grid
|
|
224
|
+
|
|
225
|
+
Parameters
|
|
226
|
+
----------
|
|
227
|
+
xax: str
|
|
228
|
+
Identifier for X axis (e.g. "area_um", "aspect", "deform")
|
|
229
|
+
yax: str
|
|
230
|
+
Identifier for Y axis
|
|
231
|
+
xacc: float
|
|
232
|
+
Contour accuracy in x direction
|
|
233
|
+
if set to None, will use :func:`bin_width_doane_div5`
|
|
234
|
+
yacc: float
|
|
235
|
+
Contour accuracy in y direction
|
|
236
|
+
if set to None, will use :func:`bin_width_doane_div5`
|
|
237
|
+
kde_type: str
|
|
238
|
+
The KDE method to use
|
|
239
|
+
kde_kwargs: dict
|
|
240
|
+
Additional keyword arguments to the KDE method
|
|
241
|
+
xscale: str
|
|
242
|
+
If set to "log", take the logarithm of the x-values before
|
|
243
|
+
computing the KDE. This is useful when data are
|
|
244
|
+
displayed on a log-scale. Defaults to "linear".
|
|
245
|
+
yscale: str
|
|
246
|
+
See `xscale`.
|
|
247
|
+
|
|
110
248
|
Returns
|
|
111
249
|
-------
|
|
112
250
|
X, Y, Z : coordinates
|
|
@@ -128,21 +266,21 @@ class KernelDensityEstimator:
|
|
|
128
266
|
a=x,
|
|
129
267
|
feat=xax,
|
|
130
268
|
scale=xscale,
|
|
131
|
-
method=
|
|
269
|
+
method=bin_width_doane_div5,
|
|
132
270
|
ret_scaled=True)
|
|
133
271
|
|
|
134
272
|
yacc_sc, ys = self.get_spacing(
|
|
135
273
|
a=y,
|
|
136
274
|
feat=yax,
|
|
137
275
|
scale=yscale,
|
|
138
|
-
method=
|
|
276
|
+
method=bin_width_doane_div5,
|
|
139
277
|
ret_scaled=True)
|
|
140
278
|
|
|
141
279
|
if xacc is None or xacc == 0:
|
|
142
|
-
xacc = xacc_sc
|
|
280
|
+
xacc = xacc_sc
|
|
143
281
|
|
|
144
282
|
if yacc is None or yacc == 0:
|
|
145
|
-
yacc = yacc_sc
|
|
283
|
+
yacc = yacc_sc
|
|
146
284
|
|
|
147
285
|
# Ignore infs and nans
|
|
148
286
|
bad = get_bad_vals(xs, ys)
|
dclab/kde/methods.py
CHANGED
|
@@ -56,6 +56,16 @@ def bin_width_doane(a):
|
|
|
56
56
|
return acc
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
def bin_width_doane_div5(a):
|
|
60
|
+
"""Compute contour spacing based on Doane's formula divided by five
|
|
61
|
+
|
|
62
|
+
See Also
|
|
63
|
+
--------
|
|
64
|
+
bin_width_doane: method used to compute the bin width
|
|
65
|
+
"""
|
|
66
|
+
return bin_width_doane(a) / 5
|
|
67
|
+
|
|
68
|
+
|
|
59
69
|
def bin_width_percentile(a):
|
|
60
70
|
"""Compute contour spacing based on data percentiles
|
|
61
71
|
|
dclab/rtdc_dataset/core.py
CHANGED
|
@@ -635,7 +635,7 @@ class RTDCBase(abc.ABC):
|
|
|
635
635
|
The kernel density Z evaluated on a rectangular grid (X,Y).
|
|
636
636
|
"""
|
|
637
637
|
kde_instance = KernelDensityEstimator(rtdc_ds=self)
|
|
638
|
-
xmesh, ymesh, density = kde_instance.
|
|
638
|
+
xmesh, ymesh, density = kde_instance.get_raster(
|
|
639
639
|
xax=xax, yax=yax, xacc=xacc, yacc=yacc, kde_type=kde_type,
|
|
640
640
|
kde_kwargs=kde_kwargs, xscale=xscale, yscale=yscale
|
|
641
641
|
)
|
|
@@ -746,6 +746,8 @@ class RTDCBase(abc.ABC):
|
|
|
746
746
|
"ignored_basins": bd_keys,
|
|
747
747
|
# basin key
|
|
748
748
|
"key": bdict["key"],
|
|
749
|
+
# whether the basin is perishable or not
|
|
750
|
+
"perishable": bdict.get("perishable", False),
|
|
749
751
|
}
|
|
750
752
|
|
|
751
753
|
# Check whether this basin is supported and exists
|
|
@@ -783,12 +785,19 @@ class RTDCBase(abc.ABC):
|
|
|
783
785
|
b_cls = bc[bdict["format"]]
|
|
784
786
|
# Try absolute path
|
|
785
787
|
bna = b_cls(pp, **kwargs)
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
788
|
+
|
|
789
|
+
try:
|
|
790
|
+
absolute_exists = bna.verify_basin()
|
|
791
|
+
except BaseException:
|
|
792
|
+
pass
|
|
793
|
+
else:
|
|
794
|
+
if absolute_exists:
|
|
795
|
+
basins.append(bna)
|
|
796
|
+
break
|
|
789
797
|
# Try relative path
|
|
790
798
|
this_path = pathlib.Path(self.path)
|
|
791
799
|
if this_path.exists():
|
|
800
|
+
|
|
792
801
|
# Insert relative path
|
|
793
802
|
bnr = b_cls(this_path.parent / pp, **kwargs)
|
|
794
803
|
if bnr.verify_basin():
|
dclab/rtdc_dataset/export.py
CHANGED
|
@@ -268,8 +268,8 @@ class Export(object):
|
|
|
268
268
|
compression_kwargs: dict
|
|
269
269
|
Dictionary with the keys "compression" and "compression_opts"
|
|
270
270
|
which are passed to :func:`h5py.H5File.create_dataset`. The
|
|
271
|
-
default is Zstandard compression with the
|
|
272
|
-
level `hdf5plugin.Zstd(clevel=
|
|
271
|
+
default is Zstandard compression with the compression
|
|
272
|
+
level 5 `hdf5plugin.Zstd(clevel=5)`.
|
|
273
273
|
compression: str or None
|
|
274
274
|
Compression method used for data storage;
|
|
275
275
|
one of [None, "lzf", "gzip", "szip"].
|
|
@@ -300,7 +300,7 @@ class Export(object):
|
|
|
300
300
|
# be backwards-compatible
|
|
301
301
|
compression_kwargs = {"compression": compression}
|
|
302
302
|
if compression_kwargs is None:
|
|
303
|
-
compression_kwargs = hdf5plugin.Zstd(clevel=
|
|
303
|
+
compression_kwargs = hdf5plugin.Zstd(clevel=5)
|
|
304
304
|
path = pathlib.Path(path)
|
|
305
305
|
# Make sure that path ends with .rtdc
|
|
306
306
|
if path.suffix not in [".rtdc", ".rtdc~"]:
|
|
@@ -505,6 +505,11 @@ class Export(object):
|
|
|
505
505
|
# defined in. Since we are exporting, it does not
|
|
506
506
|
# make sense to store these basins in the output file.
|
|
507
507
|
continue
|
|
508
|
+
elif bn_dict.get("perishable"):
|
|
509
|
+
# Perishable basins require secret keys or complicated
|
|
510
|
+
# logic to execute in order to refresh them. We do not
|
|
511
|
+
# store them in the output file.
|
|
512
|
+
continue
|
|
508
513
|
basinmap_orig = bn_dict.get("basin_map")
|
|
509
514
|
if not filtered:
|
|
510
515
|
# filtering disabled: just copy basins
|
dclab/rtdc_dataset/feat_basin.py
CHANGED
|
@@ -6,9 +6,10 @@ which, when opened in dclab, can access features stored in the input file
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import abc
|
|
9
|
+
import logging
|
|
9
10
|
import numbers
|
|
10
11
|
import threading
|
|
11
|
-
from typing import Dict, List, Literal
|
|
12
|
+
from typing import Callable, Dict, List, Literal, Union
|
|
12
13
|
import uuid
|
|
13
14
|
import warnings
|
|
14
15
|
import weakref
|
|
@@ -18,6 +19,9 @@ import numpy as np
|
|
|
18
19
|
from ..util import copy_if_needed
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
21
25
|
class BasinFeatureMissingWarning(UserWarning):
|
|
22
26
|
"""Used when a badin feature is defined but not stored"""
|
|
23
27
|
|
|
@@ -26,6 +30,10 @@ class CyclicBasinDependencyFoundWarning(UserWarning):
|
|
|
26
30
|
"""Used when a basin is defined in one of its sub-basins"""
|
|
27
31
|
|
|
28
32
|
|
|
33
|
+
class IgnoringPerishableBasinTTL(UserWarning):
|
|
34
|
+
"""Used when refreshing a basin does not support TTL"""
|
|
35
|
+
|
|
36
|
+
|
|
29
37
|
class BasinmapFeatureMissingError(KeyError):
|
|
30
38
|
"""Used when one of the `basinmap` features is not defined"""
|
|
31
39
|
pass
|
|
@@ -47,6 +55,114 @@ class BasinAvailabilityChecker(threading.Thread):
|
|
|
47
55
|
self.basin.is_available()
|
|
48
56
|
|
|
49
57
|
|
|
58
|
+
class PerishableRecord:
|
|
59
|
+
"""A class containing information about perishable basins
|
|
60
|
+
|
|
61
|
+
Perishable basins are basins than may discontinue to work after
|
|
62
|
+
e.g. a specific amount of time (e.g. presigned S3 URLs). With the
|
|
63
|
+
`PerishableRecord`, these basins may be "refreshed" (made
|
|
64
|
+
available again).
|
|
65
|
+
"""
|
|
66
|
+
def __init__(self,
|
|
67
|
+
basin,
|
|
68
|
+
expiration_func: Callable = None,
|
|
69
|
+
expiration_kwargs: Dict = None,
|
|
70
|
+
refresh_func: Callable = None,
|
|
71
|
+
refresh_kwargs: Dict = None,
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
basin: Basin
|
|
77
|
+
Instance of the perishable basin
|
|
78
|
+
expiration_func: callable
|
|
79
|
+
A function that determines whether the basin has perished.
|
|
80
|
+
It must accept `basin` as the first argument. Calling this
|
|
81
|
+
function should be fast, as it is called every time a feature
|
|
82
|
+
is accessed.
|
|
83
|
+
Note that if you are implementing this in the time domain, then
|
|
84
|
+
you should use `time.time()` (TSE), because you need an absolute
|
|
85
|
+
time measure. `time.monotonic()` for instance does not count up
|
|
86
|
+
when the system goes to sleep. However, keep in mind that if
|
|
87
|
+
a remote machine dictates the expiration time, then that
|
|
88
|
+
remote machine should also transmit the creation time (in case
|
|
89
|
+
there are time offsets).
|
|
90
|
+
expiration_kwargs: dict
|
|
91
|
+
Additional kwargs for `expiration_func`.
|
|
92
|
+
refresh_func: callable
|
|
93
|
+
The function used to refresh the `basin`. It must accept
|
|
94
|
+
`basin` as the first argument.
|
|
95
|
+
refresh_kwargs: dict
|
|
96
|
+
Additional kwargs for `refresh_func`
|
|
97
|
+
"""
|
|
98
|
+
if not isinstance(basin, weakref.ProxyType):
|
|
99
|
+
basin = weakref.proxy(basin)
|
|
100
|
+
self.basin = basin
|
|
101
|
+
self.expiration_func = expiration_func
|
|
102
|
+
self.expiration_kwargs = expiration_kwargs or {}
|
|
103
|
+
self.refresh_func = refresh_func
|
|
104
|
+
self.refresh_kwargs = refresh_kwargs or {}
|
|
105
|
+
|
|
106
|
+
def __repr__(self):
|
|
107
|
+
state = "perished" if self.perished() else "valid"
|
|
108
|
+
return f"<PerishableRecord ({state}) at {hex(id(self))}>"
|
|
109
|
+
|
|
110
|
+
def perished(self) -> Union[bool, None]:
|
|
111
|
+
"""Determine whether the basin has perished
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
state: bool or None
|
|
116
|
+
True means the basin has perished, False means the basin
|
|
117
|
+
has not perished, and `None` means we don't know
|
|
118
|
+
"""
|
|
119
|
+
if self.expiration_func is None:
|
|
120
|
+
return None
|
|
121
|
+
else:
|
|
122
|
+
return self.expiration_func(self.basin, **self.expiration_kwargs)
|
|
123
|
+
|
|
124
|
+
def refresh(self, extend_by: float = None) -> None:
|
|
125
|
+
"""Extend the lifetime of the associated perishable basin
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
extend_by: float
|
|
130
|
+
Custom argument for extending the life of the basin.
|
|
131
|
+
Normally, this would be a lifetime.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
basin: dict | None
|
|
136
|
+
Dictionary for instantiating a new basin
|
|
137
|
+
"""
|
|
138
|
+
if self.refresh_func is None:
|
|
139
|
+
# The basin is a perishable basin, but we have no way of
|
|
140
|
+
# refreshing it.
|
|
141
|
+
logger.error(f"Cannot refresh basin '{self.basin}'")
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
if extend_by and "extend_by" not in self.refresh_kwargs:
|
|
145
|
+
warnings.warn(
|
|
146
|
+
"Parameter 'extend_by' ignored, because the basin "
|
|
147
|
+
"source does not support it",
|
|
148
|
+
IgnoringPerishableBasinTTL)
|
|
149
|
+
extend_by = None
|
|
150
|
+
|
|
151
|
+
rkw = {}
|
|
152
|
+
rkw.update(self.refresh_kwargs)
|
|
153
|
+
|
|
154
|
+
if extend_by is not None:
|
|
155
|
+
rkw["extend_by"] = extend_by
|
|
156
|
+
|
|
157
|
+
self.refresh_func(self.basin, **rkw)
|
|
158
|
+
logger.info(f"Refreshed basin '{self.basin}'")
|
|
159
|
+
|
|
160
|
+
# If everything went well, reset the current dataset of the basin
|
|
161
|
+
if self.basin._ds is not None:
|
|
162
|
+
self.basin._ds.close()
|
|
163
|
+
self.basin._ds = None
|
|
164
|
+
|
|
165
|
+
|
|
50
166
|
class Basin(abc.ABC):
|
|
51
167
|
"""A basin represents data from an external source
|
|
52
168
|
|
|
@@ -76,6 +192,7 @@ class Basin(abc.ABC):
|
|
|
76
192
|
mapping_referrer: Dict = None,
|
|
77
193
|
ignored_basins: List[str] = None,
|
|
78
194
|
key: str = None,
|
|
195
|
+
perishable=False,
|
|
79
196
|
**kwargs):
|
|
80
197
|
"""
|
|
81
198
|
|
|
@@ -115,6 +232,10 @@ class Basin(abc.ABC):
|
|
|
115
232
|
Unique key to identify this basin; normally computed from
|
|
116
233
|
a JSON dump of the basin definition. A random string is used
|
|
117
234
|
if None is specified.
|
|
235
|
+
perishable: bool or PerishableRecord
|
|
236
|
+
If this is not False, then it must be a :class:`.PerishableRecord`
|
|
237
|
+
that holds the information about the expiration time, and that
|
|
238
|
+
comes with a method `refresh` to extend the lifetime of the basin.
|
|
118
239
|
kwargs:
|
|
119
240
|
Additional keyword arguments passed to the `load_dataset`
|
|
120
241
|
method of the `Basin` subclass.
|
|
@@ -130,7 +251,12 @@ class Basin(abc.ABC):
|
|
|
130
251
|
self.name = name
|
|
131
252
|
#: lengthy description of the basin
|
|
132
253
|
self.description = description
|
|
133
|
-
#
|
|
254
|
+
# perishable record
|
|
255
|
+
if isinstance(perishable, bool) and perishable:
|
|
256
|
+
# Create an empty perishable record
|
|
257
|
+
perishable = PerishableRecord(self)
|
|
258
|
+
self.perishable = perishable
|
|
259
|
+
# define key of the basin
|
|
134
260
|
self.key = key or str(uuid.uuid4())
|
|
135
261
|
# features this basin provides
|
|
136
262
|
self._features = features
|
|
@@ -164,10 +290,14 @@ class Basin(abc.ABC):
|
|
|
164
290
|
self._av_check.start()
|
|
165
291
|
|
|
166
292
|
def __repr__(self):
|
|
293
|
+
try:
|
|
294
|
+
feature_info = len(self.features)
|
|
295
|
+
except BaseException:
|
|
296
|
+
feature_info = "unknown"
|
|
167
297
|
options = [
|
|
168
298
|
self.name,
|
|
169
299
|
f"mapped {self.mapping}" if self.mapping != "same" else "",
|
|
170
|
-
f"
|
|
300
|
+
f"{feature_info} features",
|
|
171
301
|
f"location {self.location}",
|
|
172
302
|
]
|
|
173
303
|
opt_str = ", ".join([o for o in options if o])
|
|
@@ -220,6 +350,10 @@ class Basin(abc.ABC):
|
|
|
220
350
|
@property
|
|
221
351
|
def ds(self):
|
|
222
352
|
"""The :class:`.RTDCBase` instance represented by the basin"""
|
|
353
|
+
if self.perishable and self.perishable.perished():
|
|
354
|
+
# We have perished. Ask the PerishableRecord to refresh this
|
|
355
|
+
# basin so we can access it again.
|
|
356
|
+
self.perishable.refresh()
|
|
223
357
|
if self._ds is None:
|
|
224
358
|
if not self.is_available():
|
|
225
359
|
raise BasinNotAvailableError(f"Basin {self} is not available!")
|
|
@@ -265,6 +399,7 @@ class Basin(abc.ABC):
|
|
|
265
399
|
"basin_descr": self.description,
|
|
266
400
|
"basin_feats": self.features,
|
|
267
401
|
"basin_map": self.basinmap,
|
|
402
|
+
"perishable": bool(self.perishable),
|
|
268
403
|
}
|
|
269
404
|
|
|
270
405
|
def close(self):
|
|
@@ -11,8 +11,10 @@ class DCORAccessError(BaseException):
|
|
|
11
11
|
|
|
12
12
|
class APIHandler:
|
|
13
13
|
"""Handles the DCOR api with caching for simple queries"""
|
|
14
|
-
#:
|
|
15
|
-
|
|
14
|
+
#: These are cached to minimize network usage
|
|
15
|
+
#: Note that we are not caching basins, since they may contain
|
|
16
|
+
#: expiring URLs.
|
|
17
|
+
cache_queries = ["metadata", "size", "feature_list", "valid"]
|
|
16
18
|
#: DCOR API Keys/Tokens in the current session
|
|
17
19
|
api_keys = []
|
|
18
20
|
|
|
@@ -52,8 +54,36 @@ class APIHandler:
|
|
|
52
54
|
if api_key.strip() and api_key not in APIHandler.api_keys:
|
|
53
55
|
APIHandler.api_keys.append(api_key)
|
|
54
56
|
|
|
55
|
-
def _get(self,
|
|
56
|
-
|
|
57
|
+
def _get(self,
|
|
58
|
+
query: str,
|
|
59
|
+
feat: str = None,
|
|
60
|
+
trace: str = None,
|
|
61
|
+
event: str = None,
|
|
62
|
+
api_key: str = "",
|
|
63
|
+
timeout: float = None,
|
|
64
|
+
retries: int = 5):
|
|
65
|
+
"""Fetch information via the DCOR API
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
query: str
|
|
70
|
+
API route
|
|
71
|
+
feat: str
|
|
72
|
+
DEPRECATED (use basins instead), adds f"&feature={feat}" to query
|
|
73
|
+
trace: str
|
|
74
|
+
DEPRECATED (use basins instead), adds f"&trace={trace}" to query
|
|
75
|
+
event: str
|
|
76
|
+
DEPRECATED (use basins instead), adds f"&event={event}" to query
|
|
77
|
+
api_key: str
|
|
78
|
+
DCOR API token to use
|
|
79
|
+
timeout: float
|
|
80
|
+
Request timeout
|
|
81
|
+
retries: int
|
|
82
|
+
Number of retries to fetch the request. For every retry, the
|
|
83
|
+
timeout is increased by two seconds.
|
|
84
|
+
"""
|
|
85
|
+
if timeout is None:
|
|
86
|
+
timeout = 1
|
|
57
87
|
# "version=2" introduced in dclab 0.54.3
|
|
58
88
|
# (supported since ckanext.dc_serve 0.13.2)
|
|
59
89
|
qstr = f"&version={self.dcserv_api_version}&query={query}"
|
|
@@ -65,13 +95,13 @@ class APIHandler:
|
|
|
65
95
|
qstr += f"&event={event}"
|
|
66
96
|
apicall = self.url + qstr
|
|
67
97
|
fail_reasons = []
|
|
68
|
-
for
|
|
98
|
+
for ii in range(retries):
|
|
69
99
|
try:
|
|
70
100
|
# try-except both requests and json conversion
|
|
71
101
|
req = self.session.get(apicall,
|
|
72
102
|
headers={"Authorization": api_key},
|
|
73
103
|
verify=self.verify,
|
|
74
|
-
timeout=
|
|
104
|
+
timeout=timeout + ii * 2,
|
|
75
105
|
)
|
|
76
106
|
jreq = req.json()
|
|
77
107
|
except requests.urllib3.exceptions.ConnectionError: # requests
|
|
@@ -92,13 +122,45 @@ class APIHandler:
|
|
|
92
122
|
f"Messages: {fail_reasons}")
|
|
93
123
|
return jreq
|
|
94
124
|
|
|
95
|
-
def get(self,
|
|
125
|
+
def get(self,
|
|
126
|
+
query: str,
|
|
127
|
+
feat: str = None,
|
|
128
|
+
trace: str = None,
|
|
129
|
+
event: str = None,
|
|
130
|
+
timeout: float = None,
|
|
131
|
+
retries: int = 5,
|
|
132
|
+
):
|
|
133
|
+
"""Fetch information from DCOR
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
query: str
|
|
138
|
+
API route
|
|
139
|
+
feat: str
|
|
140
|
+
DEPRECATED (use basins instead), adds f"&feature={feat}" to query
|
|
141
|
+
trace: str
|
|
142
|
+
DEPRECATED (use basins instead), adds f"&trace={trace}" to query
|
|
143
|
+
event: str
|
|
144
|
+
DEPRECATED (use basins instead), adds f"&event={event}" to query
|
|
145
|
+
timeout: float
|
|
146
|
+
Request timeout
|
|
147
|
+
retries: int
|
|
148
|
+
Number of retries to fetch the request. For every retry, the
|
|
149
|
+
timeout is increased by two seconds.
|
|
150
|
+
"""
|
|
96
151
|
if query in APIHandler.cache_queries and query in self._cache:
|
|
97
152
|
result = self._cache[query]
|
|
98
153
|
else:
|
|
99
154
|
req = {"error": {"message": "No access to API (api key?)"}}
|
|
100
155
|
for api_key in [self.api_key] + APIHandler.api_keys:
|
|
101
|
-
req = self._get(query,
|
|
156
|
+
req = self._get(query=query,
|
|
157
|
+
feat=feat,
|
|
158
|
+
trace=trace,
|
|
159
|
+
event=event,
|
|
160
|
+
api_key=api_key,
|
|
161
|
+
timeout=timeout,
|
|
162
|
+
retries=retries,
|
|
163
|
+
)
|
|
102
164
|
if req["success"]:
|
|
103
165
|
self.api_key = api_key # remember working key
|
|
104
166
|
break
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
"""DCOR client interface"""
|
|
2
|
+
import logging
|
|
2
3
|
import pathlib
|
|
3
4
|
import re
|
|
5
|
+
import time
|
|
4
6
|
|
|
5
7
|
from ...util import hashobj
|
|
6
8
|
|
|
7
9
|
from ..config import Configuration
|
|
8
10
|
from ..core import RTDCBase
|
|
11
|
+
from ..feat_basin import PerishableRecord
|
|
9
12
|
|
|
10
13
|
from . import api
|
|
11
14
|
from .logs import DCORLogs
|
|
12
15
|
from .tables import DCORTables
|
|
13
16
|
|
|
14
17
|
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
15
21
|
#: Append directories here where dclab should look for certificate bundles
|
|
16
22
|
#: for a specific host. The directory should contain files named after the
|
|
17
23
|
#: hostname, e.g. "dcor.mpl.mpg.de.cert".
|
|
@@ -73,6 +79,8 @@ class RTDC_DCOR(RTDCBase):
|
|
|
73
79
|
super(RTDC_DCOR, self).__init__(*args, **kwargs)
|
|
74
80
|
|
|
75
81
|
self._hash = None
|
|
82
|
+
self._cache_basin_dict = None
|
|
83
|
+
self.cache_basin_dict_time = 600
|
|
76
84
|
self.path = RTDC_DCOR.get_full_url(url, use_ssl, host)
|
|
77
85
|
|
|
78
86
|
if cert_path is None:
|
|
@@ -161,15 +169,106 @@ class RTDC_DCOR(RTDCBase):
|
|
|
161
169
|
new_url = f"{scheme}://{netloc}/{api_path}"
|
|
162
170
|
return new_url
|
|
163
171
|
|
|
164
|
-
def
|
|
165
|
-
"""
|
|
172
|
+
def _basin_refresh(self, basin):
|
|
173
|
+
"""Refresh the specified basin"""
|
|
174
|
+
# Retrieve the basin dictionary from DCOR
|
|
175
|
+
basin_dicts = self.basins_get_dicts()
|
|
176
|
+
for bn_dict in basin_dicts:
|
|
177
|
+
if bn_dict.get("name") == basin.name:
|
|
178
|
+
break
|
|
179
|
+
else:
|
|
180
|
+
raise ValueError(f"Basin '{basin.name}' not found in {self}")
|
|
181
|
+
|
|
182
|
+
tre = bn_dict["time_request"]
|
|
183
|
+
ttl = bn_dict["time_expiration"]
|
|
184
|
+
# remember time relative to time.time, subtract 30s to be on safe side
|
|
185
|
+
tex = bn_dict["time_local_request"] + (ttl - tre) - 30
|
|
186
|
+
|
|
187
|
+
if isinstance(basin.perishable, bool):
|
|
188
|
+
logger.debug("Initializing basin perishable %s", basin.name)
|
|
189
|
+
# create a perishable record
|
|
190
|
+
basin.perishable = PerishableRecord(
|
|
191
|
+
basin=basin,
|
|
192
|
+
expiration_func=self._basin_expiration,
|
|
193
|
+
expiration_kwargs={"time_local_expiration": tex},
|
|
194
|
+
refresh_func=self._basin_refresh,
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
logger.debug("Refreshing basin perishable %s", basin.name)
|
|
198
|
+
# only update (this also works with weakref.ProxyType)
|
|
199
|
+
basin.perishable.expiration_kwargs = {"time_local_expiration": tex}
|
|
200
|
+
|
|
201
|
+
if len(bn_dict["urls"]) > 1:
|
|
202
|
+
logger.warning(f"Basin {basin.name} has multiple URLs. I am not "
|
|
203
|
+
f"checking their availability: {bn_dict}")
|
|
204
|
+
basin.location = bn_dict["urls"][0]
|
|
205
|
+
|
|
206
|
+
def _basin_expiration(self, basin, time_local_expiration):
|
|
207
|
+
"""Check whether the basin has perished"""
|
|
208
|
+
return time_local_expiration < time.time()
|
|
209
|
+
|
|
210
|
+
def _basins_get_dicts(self):
|
|
166
211
|
try:
|
|
167
|
-
|
|
212
|
+
basin_dicts = self.api.get(query="basins")
|
|
213
|
+
# Fill in missing timing information
|
|
214
|
+
for bn_dict in basin_dicts:
|
|
215
|
+
if (bn_dict.get("format") == "http"
|
|
216
|
+
and "perishable" not in bn_dict):
|
|
217
|
+
# We are communicating with an older version of
|
|
218
|
+
# ckanext-dc_serve. Take a look at the URL and check
|
|
219
|
+
# whether we have a perishable (~1 hour) URL or whether
|
|
220
|
+
# this is a public resource.
|
|
221
|
+
expires_regexp = re.compile(".*expires=([0-9]*)$")
|
|
222
|
+
for url in bn_dict.get("urls", []):
|
|
223
|
+
if match := expires_regexp.match(url.lower()):
|
|
224
|
+
logger.debug("Detected perishable basin: %s",
|
|
225
|
+
bn_dict["name"])
|
|
226
|
+
bn_dict["perishable"] = True
|
|
227
|
+
bn_dict["time_request"] = time.time()
|
|
228
|
+
bn_dict["time_expiration"] = int(match.group(1))
|
|
229
|
+
# add part of the resource ID to the name
|
|
230
|
+
infourl = url.split(bn_dict["name"], 1)[-1]
|
|
231
|
+
infourl = infourl.replace("/", "")
|
|
232
|
+
bn_dict["name"] += f"-{infourl[:5]}"
|
|
233
|
+
break
|
|
234
|
+
else:
|
|
235
|
+
bn_dict["perishable"] = False
|
|
236
|
+
# If we have a perishable basin, add the local request time
|
|
237
|
+
if bn_dict.get("perishable"):
|
|
238
|
+
bn_dict["time_local_request"] = time.time()
|
|
168
239
|
except api.DCORAccessError:
|
|
169
240
|
# TODO: Do not catch this exception when all DCOR instances
|
|
170
241
|
# implement the 'basins' query.
|
|
171
242
|
# This means that the server does not implement the 'basins' query.
|
|
172
|
-
|
|
243
|
+
basin_dicts = []
|
|
244
|
+
return basin_dicts
|
|
245
|
+
|
|
246
|
+
def basins_get_dicts(self):
|
|
247
|
+
"""Return list of dicts for all basins defined on DCOR
|
|
248
|
+
|
|
249
|
+
The return value of this method is cached for 10 minutes
|
|
250
|
+
(cache time defined in the `cache_basin_dict_time` [s] property).
|
|
251
|
+
"""
|
|
252
|
+
if (self._cache_basin_dict is None
|
|
253
|
+
or time.time() > (self._cache_basin_dict[1]
|
|
254
|
+
+ self.cache_basin_dict_time)):
|
|
255
|
+
self._cache_basin_dict = (self._basins_get_dicts(), time.time())
|
|
256
|
+
return self._cache_basin_dict[0]
|
|
257
|
+
|
|
258
|
+
def basins_retrieve(self):
|
|
259
|
+
"""Same as superclass, but add perishable information"""
|
|
260
|
+
basin_dicts = self.basins_get_dicts()
|
|
261
|
+
basins = super(RTDC_DCOR, self).basins_retrieve()
|
|
262
|
+
for bn in basins:
|
|
263
|
+
for bn_dict in basin_dicts:
|
|
264
|
+
if bn.name == bn_dict.get("name"):
|
|
265
|
+
# Determine whether we have to set a perishable record.
|
|
266
|
+
if bn_dict.get("perishable"):
|
|
267
|
+
# required for `_basin_refresh` to create a record
|
|
268
|
+
bn.perishable = True
|
|
269
|
+
# create the actual record
|
|
270
|
+
self._basin_refresh(bn)
|
|
271
|
+
break
|
|
173
272
|
return basins
|
|
174
273
|
|
|
175
274
|
|
dclab/rtdc_dataset/writer.py
CHANGED
|
@@ -66,8 +66,8 @@ class RTDCWriter:
|
|
|
66
66
|
compression_kwargs: dict-like
|
|
67
67
|
Dictionary with the keys "compression" and "compression_opts"
|
|
68
68
|
which are passed to :func:`h5py.H5File.create_dataset`. The
|
|
69
|
-
default is Zstandard compression with the
|
|
70
|
-
level `hdf5plugin.Zstd(clevel=
|
|
69
|
+
default is Zstandard compression with the compression
|
|
70
|
+
level 5 `hdf5plugin.Zstd(clevel=5)`. To disable compression, use
|
|
71
71
|
`{"compression": None}`.
|
|
72
72
|
compression: str or None
|
|
73
73
|
Compression method used for data storage;
|
|
@@ -88,7 +88,7 @@ class RTDCWriter:
|
|
|
88
88
|
# be backwards-compatible
|
|
89
89
|
compression_kwargs = {"compression": compression}
|
|
90
90
|
if compression_kwargs is None:
|
|
91
|
-
compression_kwargs = hdf5plugin.Zstd(clevel=
|
|
91
|
+
compression_kwargs = hdf5plugin.Zstd(clevel=5)
|
|
92
92
|
|
|
93
93
|
self.mode = mode
|
|
94
94
|
self.compression_kwargs = compression_kwargs
|
|
@@ -209,6 +209,7 @@ class RTDCWriter:
|
|
|
209
209
|
basin_map: np.ndarray | Tuple[str, np.ndarray] = None,
|
|
210
210
|
internal_data: Dict | h5py.Group = None,
|
|
211
211
|
verify: bool = True,
|
|
212
|
+
perishable: bool = False,
|
|
212
213
|
):
|
|
213
214
|
"""Write basin information
|
|
214
215
|
|
|
@@ -249,9 +250,13 @@ class RTDCWriter:
|
|
|
249
250
|
This must be specified when storing internal basins, and it
|
|
250
251
|
must not be specified for any other basin type.
|
|
251
252
|
verify: bool
|
|
252
|
-
|
|
253
|
+
Whether to verify the basin before storing it; You might have
|
|
253
254
|
set this to False if you would like to write a basin that is
|
|
254
255
|
e.g. temporarily not available
|
|
256
|
+
perishable: bool
|
|
257
|
+
Whether the basin is perishable. If this is True, then a
|
|
258
|
+
warning will be issued, because perishable basins may not be
|
|
259
|
+
accessed (e.g. time-based URL for private S3 data).
|
|
255
260
|
|
|
256
261
|
Returns
|
|
257
262
|
-------
|
|
@@ -261,6 +266,8 @@ class RTDCWriter:
|
|
|
261
266
|
|
|
262
267
|
.. versionadded:: 0.58.0
|
|
263
268
|
"""
|
|
269
|
+
if perishable:
|
|
270
|
+
warnings.warn(f"Storing perishable basin {basin_name}")
|
|
264
271
|
if basin_type == "internal":
|
|
265
272
|
if internal_data is None:
|
|
266
273
|
raise ValueError(
|
|
@@ -381,6 +388,7 @@ class RTDCWriter:
|
|
|
381
388
|
"type": basin_type,
|
|
382
389
|
"features": None if basin_feats is None else sorted(basin_feats),
|
|
383
390
|
"mapping": basin_map_name,
|
|
391
|
+
"perishable": perishable,
|
|
384
392
|
}
|
|
385
393
|
if basin_type == "file":
|
|
386
394
|
flocs = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dclab
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.64.0
|
|
4
4
|
Summary: Library for real-time deformability cytometry (RT-DC)
|
|
5
5
|
Author: Benedikt Hartmann, Eoghan O'Connell, Maik Herbig, Maximilian Schlögel, Nadia Sbaa, Paul Müller, Philipp Rosendahl, Raghava Alajangi
|
|
6
6
|
Maintainer-email: Paul Müller <dev@craban.de>
|
|
@@ -14,7 +14,7 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
16
16
|
Classifier: Intended Audience :: Science/Research
|
|
17
|
-
Requires-Python: <4,>=3.
|
|
17
|
+
Requires-Python: <4,>=3.9
|
|
18
18
|
Description-Content-Type: text/x-rst
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: h5py<4,>=3.0.0
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
dclab/__init__.py,sha256=wyJWhElQRPcq09vUqUnuquTU_KHgHxv6wQxuxQ988Iw,1583
|
|
2
|
-
dclab/_version.py,sha256=
|
|
2
|
+
dclab/_version.py,sha256=zVb-mNfv7Q80VP6gLIonMXNXR1BAme5zhf4Ww25kC90,513
|
|
3
3
|
dclab/cached.py,sha256=eWTYBiI-HQM7JuPH-oxa5LLnhAX32GpRwlYg2kQ3sTA,2917
|
|
4
|
-
dclab/downsampling.cpython-39-x86_64-linux-gnu.so,sha256=
|
|
4
|
+
dclab/downsampling.cpython-39-x86_64-linux-gnu.so,sha256=a8dZlnaETZhboAi2V_jmqv8jTjtPaJMSXfi1XLiRPYI,1480784
|
|
5
5
|
dclab/downsampling.pyx,sha256=OK7zbgGLl5gVyoU8ZBHo9EWwb8C9ChavmLNEvQvC9T0,7258
|
|
6
|
-
dclab/http_utils.py,sha256=
|
|
6
|
+
dclab/http_utils.py,sha256=XHicbHQts5LY3zSNmYqNgAZpKTktotEiwQgJ8d2sBlk,10912
|
|
7
7
|
dclab/kde_contours.py,sha256=UlU64lrzMQUZH11oZndW7xf7NFCzwP3FcVujwuqXDCI,278
|
|
8
8
|
dclab/kde_methods.py,sha256=f0-zDN7ETintvGB3gSzxwgBb53YtT9jZtzI70EAX50g,365
|
|
9
9
|
dclab/polygon_filter.py,sha256=qexmo-rXe06CUPZhN6EMJy4y4B5gXZeqejdvIB2arOE,13480
|
|
@@ -35,14 +35,14 @@ dclab/external/packaging/version.py,sha256=9MLL6_EYHvGA1yCGndwL5ZmmDA_wqQsW15GyK
|
|
|
35
35
|
dclab/external/skimage/LICENSE,sha256=ivsSBvn3c0R9mOctWRRdza7C7wdZSRYgCVxlVqUdlB8,1452
|
|
36
36
|
dclab/external/skimage/__init__.py,sha256=-B2QUKHAFzQuBWuuKvPDC5JIl0Zb-x3OGmbwPaE9VwQ,72
|
|
37
37
|
dclab/external/skimage/_find_contours.py,sha256=16v5eeTZBmevG8SSuXtJ6yUpVPhwfSmtc8pDD0nuuOU,9340
|
|
38
|
-
dclab/external/skimage/_find_contours_cy.cpython-39-x86_64-linux-gnu.so,sha256=
|
|
38
|
+
dclab/external/skimage/_find_contours_cy.cpython-39-x86_64-linux-gnu.so,sha256=B2frqGkOmlrASITtPC3yHMGiOfQ3Q4ddrVmbgrYoZis,1090792
|
|
39
39
|
dclab/external/skimage/_find_contours_cy.pyx,sha256=pZJOBhMHzYEMkcz4WQVyjn7jDNrdjCfet47FU1hRAxk,7161
|
|
40
|
-
dclab/external/skimage/_pnpoly.cpython-39-x86_64-linux-gnu.so,sha256=
|
|
40
|
+
dclab/external/skimage/_pnpoly.cpython-39-x86_64-linux-gnu.so,sha256=QJg9uS9gap-2wiTrSnZCOstM9ukYfhCVysdEJ3doOgw,1191776
|
|
41
41
|
dclab/external/skimage/_pnpoly.pyx,sha256=Qdn6xPazDschBqbr46DzB75MB2MnqvdnoTSBMK7kUGE,2504
|
|
42
42
|
dclab/external/skimage/measure.py,sha256=y1idCqD9TUxp3-QnOiWR_d674OKaeqBJ4MN2-gVP6ro,247
|
|
43
43
|
dclab/external/skimage/pnpoly.py,sha256=r8hFNiTz5XlUoNZjosqA0iyv1FPn0l7ewbplgFgkdaw,1347
|
|
44
44
|
dclab/external/skimage/_shared/__init__.py,sha256=2sHZwTtJSlMTa3Q2YSvQW7jrPLMUSqDJQa-ROe5zfcw,37
|
|
45
|
-
dclab/external/skimage/_shared/geometry.cpython-39-x86_64-linux-gnu.so,sha256=
|
|
45
|
+
dclab/external/skimage/_shared/geometry.cpython-39-x86_64-linux-gnu.so,sha256=8BUxEv5oF5nWa8uxzvSZDBLWz_uXpIp3vrHGXXeLmbk,64944
|
|
46
46
|
dclab/external/skimage/_shared/geometry.pxd,sha256=kRsu9ifv_rL3kbRIgSLf86p0hn2oTMp6s013lZ9bBZM,346
|
|
47
47
|
dclab/external/skimage/_shared/geometry.pyx,sha256=miCHUh6mBDbRRIoaF_0xAER1MRzsCAzFdlYQZhV7RmE,1667
|
|
48
48
|
dclab/external/statsmodels/LICENSE,sha256=JCyTeA3bPAyFsOpDoSVZjoui7Lu1XTrcAuf0eClKvV0,1637
|
|
@@ -76,9 +76,9 @@ dclab/isoelastics/iso_LE-2D-FEM-19-area_um-deform.txt,sha256=lcTjUUnIwj_bVBrG2T2
|
|
|
76
76
|
dclab/isoelastics/iso_LE-2D-FEM-19-volume-deform.txt,sha256=vTcazOlOXo3BQ0NQtGB_IdHKA0neOLXZ_d3JuMU--RE,83358
|
|
77
77
|
dclab/isoelastics/iso_LE-2D-ana-18-area_um-deform.txt,sha256=KD2RkhCfkrna20pLJ3UzNZZapMkhQydMYz0iKdMtRRE,46805
|
|
78
78
|
dclab/kde/__init__.py,sha256=_WSLPMfxE2su6tmO5mJxUE_9ON16-pqQUQCUlzRtyKI,55
|
|
79
|
-
dclab/kde/base.py,sha256=
|
|
79
|
+
dclab/kde/base.py,sha256=KuV_9_AJ4Sn14C4WAH4eF63URAVYCnaFOcLgsVCaAjo,12961
|
|
80
80
|
dclab/kde/contours.py,sha256=WoRqBj_xK-23FZjtaYly7E2Q8sGZ16q2ILq-DmrlmC8,6742
|
|
81
|
-
dclab/kde/methods.py,sha256=
|
|
81
|
+
dclab/kde/methods.py,sha256=8g4lYUKYqt2pdA9efHVRBDCUUzmePmWPp6rljtJ0XD8,9438
|
|
82
82
|
dclab/lme4/__init__.py,sha256=5WPFMTK-Yia3NJuwZEEBQ3fCyW3DiFgpZFrAwU33TV4,272
|
|
83
83
|
dclab/lme4/lme4_template.R,sha256=CEXQIquvYCla9dCvRYgiBemI6fiVgAKnJTetJA2LAtk,2570
|
|
84
84
|
dclab/lme4/rsetup.py,sha256=kH9VFtcK83ZaF9jvh1n5kcmGmPLLsmCPia_ElEHBLes,5890
|
|
@@ -87,9 +87,9 @@ dclab/rtdc_dataset/__init__.py,sha256=MUHSGVQJ4Zc0IyU2lf01dpDWyOyNveHip-UjSkmPNv
|
|
|
87
87
|
dclab/rtdc_dataset/check.py,sha256=lJNaz4QTe2WNlxik6zSohRHTiAYuP_bKOzSDjPGTUS0,35006
|
|
88
88
|
dclab/rtdc_dataset/config.py,sha256=MvBteFya3R6Ch3U6UgTakCsJoBgVykTxS_Z25STWPHU,17432
|
|
89
89
|
dclab/rtdc_dataset/copier.py,sha256=-2ISiOs4ytxN_ttXQGhaepuD2Ppy80G9UlDSZVyEoOU,14175
|
|
90
|
-
dclab/rtdc_dataset/core.py,sha256=
|
|
91
|
-
dclab/rtdc_dataset/export.py,sha256=
|
|
92
|
-
dclab/rtdc_dataset/feat_basin.py,sha256=
|
|
90
|
+
dclab/rtdc_dataset/core.py,sha256=p1Wy9Dq1Ny4i-cfvgPfCZov_lQAhGz0--x59j-g4mTs,34753
|
|
91
|
+
dclab/rtdc_dataset/export.py,sha256=Ukmdz-Mm9iei6vhfp1lh7oNQiAbXvA2o3tRx1XlBWCM,33416
|
|
92
|
+
dclab/rtdc_dataset/feat_basin.py,sha256=i1J6iKQQEJXdi3u-TB9y_OdxbkFPBK6_G2jeaGcBsLY,26172
|
|
93
93
|
dclab/rtdc_dataset/feat_temp.py,sha256=XbDIS1iUUkRH0Zp9uVlwvK_untJ7hkOnKshK1Drsnt8,3694
|
|
94
94
|
dclab/rtdc_dataset/filter.py,sha256=AFPUBzOIi3pqXgUdMQ5CIi9ZeGOKC71rfSZKLMLgtog,10023
|
|
95
95
|
dclab/rtdc_dataset/fmt_dict.py,sha256=gumVQOiVVDFUKow_483PY7cxInqo-NiBBnBhIU8s4lg,3009
|
|
@@ -97,7 +97,7 @@ dclab/rtdc_dataset/fmt_http.py,sha256=vXVxRLXZp2_V1v3xk4lu4VUHYXfNHJdsRkVt3trC1R
|
|
|
97
97
|
dclab/rtdc_dataset/fmt_s3.py,sha256=bU3V_WGyqJhxPCH80X_nlNqq-jXcgoZKv_aUBIqwaL8,11877
|
|
98
98
|
dclab/rtdc_dataset/load.py,sha256=5_xGw2P8Mjs0gW-vGr2Kn28j6Qv3BvvMvguMibC_mM4,2761
|
|
99
99
|
dclab/rtdc_dataset/meta_table.py,sha256=ucqBNrgI6rDAuQFuMRckY8lp1LpnYAoRgEsLObWTJCE,648
|
|
100
|
-
dclab/rtdc_dataset/writer.py,sha256=
|
|
100
|
+
dclab/rtdc_dataset/writer.py,sha256=BqP4QSzHxCSxp9z7_cJF2v04taO3ZXE3Wg6zJY6fMao,41819
|
|
101
101
|
dclab/rtdc_dataset/feat_anc_core/__init__.py,sha256=hEWMqg2rmbxW86Fe-dkTD4b0Zmp-dJe6gPsMjspPGXA,464
|
|
102
102
|
dclab/rtdc_dataset/feat_anc_core/af_basic.py,sha256=15UW0wp1XG0o9QHxcVmn48dPZUdRgGezaC7ZidS6EhA,2193
|
|
103
103
|
dclab/rtdc_dataset/feat_anc_core/af_emodulus.py,sha256=Pl1kJSqAx15xBeipbw7fv8QbsvMjzY6gd1MC7Atm5kc,6670
|
|
@@ -110,11 +110,11 @@ dclab/rtdc_dataset/feat_anc_plugin/__init__.py,sha256=Em8nKxzex6M46Q86pRoSdrzb02
|
|
|
110
110
|
dclab/rtdc_dataset/feat_anc_plugin/plugin_feature.py,sha256=ED7vAtHgMXoanbeoUdklDAocj0Pq_cpckmCJ-YWqwr8,12381
|
|
111
111
|
dclab/rtdc_dataset/fmt_dcor/__init__.py,sha256=WjO1uM_Vlof15Y7HkhkV5Xv75q9TDIdOBIuS_I38qps,210
|
|
112
112
|
dclab/rtdc_dataset/fmt_dcor/access_token.py,sha256=jotLQay138RUlv8wbdF2ishRnyE9N0KwGGBlbCL0wRI,2028
|
|
113
|
-
dclab/rtdc_dataset/fmt_dcor/api.py,sha256=
|
|
114
|
-
dclab/rtdc_dataset/fmt_dcor/base.py,sha256=
|
|
113
|
+
dclab/rtdc_dataset/fmt_dcor/api.py,sha256=IhmNpEdVSGHdJUepCkmuyTVOp3fNn1WASPVohAzwhu8,6274
|
|
114
|
+
dclab/rtdc_dataset/fmt_dcor/base.py,sha256=cFiZcWG43jOGTY3oNl-E_vdzbm5QZU1CEB7ucrLZP_U,11167
|
|
115
115
|
dclab/rtdc_dataset/fmt_dcor/basin.py,sha256=tQZ4GumqURjS3eppRrSyUq1zBPD0y_8rwznMRDXiDUs,2526
|
|
116
|
-
dclab/rtdc_dataset/fmt_dcor/logs.py,sha256=
|
|
117
|
-
dclab/rtdc_dataset/fmt_dcor/tables.py,sha256=
|
|
116
|
+
dclab/rtdc_dataset/fmt_dcor/logs.py,sha256=FHaDGjh4wMd18S2FFr6IVdd23l21S6s3fwZnFbPG83E,594
|
|
117
|
+
dclab/rtdc_dataset/fmt_dcor/tables.py,sha256=a4gMIjH0TgFdz36l_F-xriHTT4LMI64ur-atHyvAp80,1694
|
|
118
118
|
dclab/rtdc_dataset/fmt_hdf5/__init__.py,sha256=yWLYK-Fq0EYnp2eYfl1Ze02RBMOWg-iALJWs4dFSxxY,270
|
|
119
119
|
dclab/rtdc_dataset/fmt_hdf5/base.py,sha256=_PgmDq2K7RGCuhV9J4YZwg9noW1hi2w14ZP8ooRR8Lw,6391
|
|
120
120
|
dclab/rtdc_dataset/fmt_hdf5/basin.py,sha256=mJZR92Qoa71EwDVDYAP9KtOcjvRyjtA2wO1DkCBfBQc,792
|
|
@@ -134,9 +134,9 @@ dclab/rtdc_dataset/fmt_tdms/event_mask.py,sha256=eZiDHAGG3MCVckEMHsV-YBbL-pETVLo
|
|
|
134
134
|
dclab/rtdc_dataset/fmt_tdms/event_trace.py,sha256=Vkym0QKSw2mq1XZl5n8wDkgHXmaZwQGiMAV5AuRSJkE,5215
|
|
135
135
|
dclab/rtdc_dataset/fmt_tdms/exc.py,sha256=WzrMqnyrzp8gsT8Pf7JKqGGv43ewx7d_qgtirURppRI,813
|
|
136
136
|
dclab/rtdc_dataset/fmt_tdms/naming.py,sha256=biI9l1EO6BuSYgwZG0deacj4i1fMHQcW78AKXEcm5Wc,5373
|
|
137
|
-
dclab-0.
|
|
138
|
-
dclab-0.
|
|
139
|
-
dclab-0.
|
|
140
|
-
dclab-0.
|
|
141
|
-
dclab-0.
|
|
142
|
-
dclab-0.
|
|
137
|
+
dclab-0.64.0.dist-info/METADATA,sha256=zfrjZaLGPiE_ZPYkVtoUGvGI-CPkjgY-eiKJshd-3bo,4755
|
|
138
|
+
dclab-0.64.0.dist-info/WHEEL,sha256=RCs-IytiafpWtat_ywWwz8oKW5vOEqKNayxVvj2QscE,110
|
|
139
|
+
dclab-0.64.0.dist-info/entry_points.txt,sha256=eOpjgznu-eW-9utUpLU-77O5098YyUEgGF3ksGMdtec,273
|
|
140
|
+
dclab-0.64.0.dist-info/top_level.txt,sha256=irvwZMgs1edY1Zj60ZFk7Almb9Zhk4k6E6aC4YPFnnM,6
|
|
141
|
+
dclab-0.64.0.dist-info/RECORD,,
|
|
142
|
+
dclab-0.64.0.dist-info/licenses/LICENSE,sha256=gLDaVZWRrlnLdyfOrR0qfWjLbOVcjvoJ-kCLUK0fyXA,15360
|
|
File without changes
|
|
File without changes
|
|
File without changes
|