dclab 0.67.0__cp314-cp314-macosx_10_13_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/__init__.py +41 -0
- dclab/_version.py +34 -0
- dclab/cached.py +97 -0
- dclab/cli/__init__.py +10 -0
- dclab/cli/common.py +237 -0
- dclab/cli/task_compress.py +126 -0
- dclab/cli/task_condense.py +223 -0
- dclab/cli/task_join.py +229 -0
- dclab/cli/task_repack.py +98 -0
- dclab/cli/task_split.py +154 -0
- dclab/cli/task_tdms2rtdc.py +186 -0
- dclab/cli/task_verify_dataset.py +75 -0
- dclab/definitions/__init__.py +79 -0
- dclab/definitions/feat_const.py +202 -0
- dclab/definitions/feat_logic.py +182 -0
- dclab/definitions/meta_const.py +252 -0
- dclab/definitions/meta_logic.py +111 -0
- dclab/definitions/meta_parse.py +94 -0
- dclab/downsampling.cpython-314-darwin.so +0 -0
- dclab/downsampling.pyx +230 -0
- dclab/external/__init__.py +4 -0
- dclab/external/packaging/LICENSE +3 -0
- dclab/external/packaging/LICENSE.APACHE +177 -0
- dclab/external/packaging/LICENSE.BSD +23 -0
- dclab/external/packaging/__init__.py +6 -0
- dclab/external/packaging/_structures.py +61 -0
- dclab/external/packaging/version.py +505 -0
- dclab/external/skimage/LICENSE +28 -0
- dclab/external/skimage/__init__.py +2 -0
- dclab/external/skimage/_find_contours.py +216 -0
- dclab/external/skimage/_find_contours_cy.cpython-314-darwin.so +0 -0
- dclab/external/skimage/_find_contours_cy.pyx +188 -0
- dclab/external/skimage/_pnpoly.cpython-314-darwin.so +0 -0
- dclab/external/skimage/_pnpoly.pyx +99 -0
- dclab/external/skimage/_shared/__init__.py +1 -0
- dclab/external/skimage/_shared/geometry.cpython-314-darwin.so +0 -0
- dclab/external/skimage/_shared/geometry.pxd +6 -0
- dclab/external/skimage/_shared/geometry.pyx +55 -0
- dclab/external/skimage/measure.py +7 -0
- dclab/external/skimage/pnpoly.py +53 -0
- dclab/external/statsmodels/LICENSE +35 -0
- dclab/external/statsmodels/__init__.py +6 -0
- dclab/external/statsmodels/nonparametric/__init__.py +1 -0
- dclab/external/statsmodels/nonparametric/_kernel_base.py +203 -0
- dclab/external/statsmodels/nonparametric/kernel_density.py +165 -0
- dclab/external/statsmodels/nonparametric/kernels.py +36 -0
- dclab/features/__init__.py +9 -0
- dclab/features/bright.py +81 -0
- dclab/features/bright_bc.py +93 -0
- dclab/features/bright_perc.py +63 -0
- dclab/features/contour.py +161 -0
- dclab/features/emodulus/__init__.py +339 -0
- dclab/features/emodulus/load.py +252 -0
- dclab/features/emodulus/lut_HE-2D-FEM-22.txt +16432 -0
- dclab/features/emodulus/lut_HE-3D-FEM-22.txt +1276 -0
- dclab/features/emodulus/lut_LE-2D-FEM-19.txt +13082 -0
- dclab/features/emodulus/pxcorr.py +135 -0
- dclab/features/emodulus/scale_linear.py +247 -0
- dclab/features/emodulus/viscosity.py +260 -0
- dclab/features/fl_crosstalk.py +95 -0
- dclab/features/inert_ratio.py +377 -0
- dclab/features/volume.py +242 -0
- dclab/http_utils.py +322 -0
- dclab/isoelastics/__init__.py +468 -0
- dclab/isoelastics/iso_HE-2D-FEM-22-area_um-deform.txt +2440 -0
- dclab/isoelastics/iso_HE-2D-FEM-22-volume-deform.txt +2635 -0
- dclab/isoelastics/iso_HE-3D-FEM-22-area_um-deform.txt +1930 -0
- dclab/isoelastics/iso_HE-3D-FEM-22-volume-deform.txt +2221 -0
- dclab/isoelastics/iso_LE-2D-FEM-19-area_um-deform.txt +2151 -0
- dclab/isoelastics/iso_LE-2D-FEM-19-volume-deform.txt +2250 -0
- dclab/isoelastics/iso_LE-2D-ana-18-area_um-deform.txt +1266 -0
- dclab/kde/__init__.py +1 -0
- dclab/kde/base.py +459 -0
- dclab/kde/contours.py +222 -0
- dclab/kde/methods.py +313 -0
- dclab/kde_contours.py +10 -0
- dclab/kde_methods.py +11 -0
- dclab/lme4/__init__.py +5 -0
- dclab/lme4/lme4_template.R +94 -0
- dclab/lme4/rsetup.py +204 -0
- dclab/lme4/wrapr.py +386 -0
- dclab/polygon_filter.py +398 -0
- dclab/rtdc_dataset/__init__.py +15 -0
- dclab/rtdc_dataset/check.py +902 -0
- dclab/rtdc_dataset/config.py +533 -0
- dclab/rtdc_dataset/copier.py +353 -0
- dclab/rtdc_dataset/core.py +896 -0
- dclab/rtdc_dataset/export.py +867 -0
- dclab/rtdc_dataset/feat_anc_core/__init__.py +24 -0
- dclab/rtdc_dataset/feat_anc_core/af_basic.py +75 -0
- dclab/rtdc_dataset/feat_anc_core/af_emodulus.py +160 -0
- dclab/rtdc_dataset/feat_anc_core/af_fl_max_ctc.py +133 -0
- dclab/rtdc_dataset/feat_anc_core/af_image_contour.py +113 -0
- dclab/rtdc_dataset/feat_anc_core/af_ml_class.py +102 -0
- dclab/rtdc_dataset/feat_anc_core/ancillary_feature.py +320 -0
- dclab/rtdc_dataset/feat_anc_ml/__init__.py +32 -0
- dclab/rtdc_dataset/feat_anc_plugin/__init__.py +3 -0
- dclab/rtdc_dataset/feat_anc_plugin/plugin_feature.py +329 -0
- dclab/rtdc_dataset/feat_basin.py +762 -0
- dclab/rtdc_dataset/feat_temp.py +102 -0
- dclab/rtdc_dataset/filter.py +263 -0
- dclab/rtdc_dataset/fmt_dcor/__init__.py +7 -0
- dclab/rtdc_dataset/fmt_dcor/access_token.py +52 -0
- dclab/rtdc_dataset/fmt_dcor/api.py +173 -0
- dclab/rtdc_dataset/fmt_dcor/base.py +299 -0
- dclab/rtdc_dataset/fmt_dcor/basin.py +73 -0
- dclab/rtdc_dataset/fmt_dcor/logs.py +26 -0
- dclab/rtdc_dataset/fmt_dcor/tables.py +66 -0
- dclab/rtdc_dataset/fmt_dict.py +103 -0
- dclab/rtdc_dataset/fmt_hdf5/__init__.py +6 -0
- dclab/rtdc_dataset/fmt_hdf5/base.py +192 -0
- dclab/rtdc_dataset/fmt_hdf5/basin.py +30 -0
- dclab/rtdc_dataset/fmt_hdf5/events.py +276 -0
- dclab/rtdc_dataset/fmt_hdf5/feat_defect.py +164 -0
- dclab/rtdc_dataset/fmt_hdf5/logs.py +33 -0
- dclab/rtdc_dataset/fmt_hdf5/tables.py +60 -0
- dclab/rtdc_dataset/fmt_hierarchy/__init__.py +11 -0
- dclab/rtdc_dataset/fmt_hierarchy/base.py +278 -0
- dclab/rtdc_dataset/fmt_hierarchy/events.py +146 -0
- dclab/rtdc_dataset/fmt_hierarchy/hfilter.py +140 -0
- dclab/rtdc_dataset/fmt_hierarchy/mapper.py +134 -0
- dclab/rtdc_dataset/fmt_http.py +102 -0
- dclab/rtdc_dataset/fmt_s3.py +354 -0
- dclab/rtdc_dataset/fmt_tdms/__init__.py +476 -0
- dclab/rtdc_dataset/fmt_tdms/event_contour.py +264 -0
- dclab/rtdc_dataset/fmt_tdms/event_image.py +220 -0
- dclab/rtdc_dataset/fmt_tdms/event_mask.py +62 -0
- dclab/rtdc_dataset/fmt_tdms/event_trace.py +146 -0
- dclab/rtdc_dataset/fmt_tdms/exc.py +37 -0
- dclab/rtdc_dataset/fmt_tdms/naming.py +151 -0
- dclab/rtdc_dataset/load.py +77 -0
- dclab/rtdc_dataset/meta_table.py +25 -0
- dclab/rtdc_dataset/writer.py +1019 -0
- dclab/statistics.py +226 -0
- dclab/util.py +176 -0
- dclab/warn.py +15 -0
- dclab-0.67.0.dist-info/METADATA +153 -0
- dclab-0.67.0.dist-info/RECORD +142 -0
- dclab-0.67.0.dist-info/WHEEL +6 -0
- dclab-0.67.0.dist-info/entry_points.txt +8 -0
- dclab-0.67.0.dist-info/licenses/LICENSE +283 -0
- dclab-0.67.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from .ancillary_feature import AncillaryFeature # noqa: F401
|
|
2
|
+
from . import af_basic
|
|
3
|
+
from . import af_emodulus
|
|
4
|
+
from . import af_fl_max_ctc
|
|
5
|
+
from . import af_image_contour
|
|
6
|
+
from . import af_ml_class
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#: features whose computation is fast
|
|
10
|
+
FEATURES_RAPID = [
|
|
11
|
+
"area_ratio",
|
|
12
|
+
"area_um",
|
|
13
|
+
"aspect",
|
|
14
|
+
"deform",
|
|
15
|
+
"index",
|
|
16
|
+
"time",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
af_basic.register()
|
|
21
|
+
af_emodulus.register()
|
|
22
|
+
af_fl_max_ctc.register()
|
|
23
|
+
af_image_contour.register()
|
|
24
|
+
af_ml_class.register()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from .ancillary_feature import AncillaryFeature
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def compute_area_ratio(mm):
|
|
7
|
+
valid = mm["area_msd"] != 0
|
|
8
|
+
out = np.nan * np.ones(len(mm), dtype=float)
|
|
9
|
+
return np.divide(mm["area_cvx"], mm["area_msd"], where=valid, out=out)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def compute_area_um(mm):
|
|
13
|
+
pxs = mm.config["imaging"]["pixel size"]
|
|
14
|
+
return mm["area_cvx"] * pxs**2
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def compute_aspect(mm):
|
|
18
|
+
"""Compute the aspect ratio of the bounding box
|
|
19
|
+
|
|
20
|
+
Notes
|
|
21
|
+
-----
|
|
22
|
+
If the cell is elongated along the channel, i.e.
|
|
23
|
+
`size_x` is larger than `size_y`, then the aspect
|
|
24
|
+
ratio is larger than 1.
|
|
25
|
+
"""
|
|
26
|
+
out = np.nan * np.ones(len(mm), dtype=float)
|
|
27
|
+
valid = mm["size_y"] != 0
|
|
28
|
+
# parallel to flow, perpendicular to flow
|
|
29
|
+
return np.divide(mm["size_x"], mm["size_y"], where=valid, out=out)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def compute_deform(mm):
|
|
33
|
+
return 1 - mm["circ"]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def compute_index(mm):
|
|
37
|
+
return np.arange(1, len(mm)+1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def compute_time(mm):
|
|
41
|
+
fr = mm.config["imaging"]["frame rate"]
|
|
42
|
+
# Since version 0.47.8, we don't "normalize" the time anymore
|
|
43
|
+
# with the information from mm["frame"][0]. This is important
|
|
44
|
+
# for cases where it is important to know the time elapsed before
|
|
45
|
+
# the first event was recorded (issue #207).
|
|
46
|
+
return np.array(mm["frame"], dtype=float) / fr
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
AncillaryFeature(feature_name="time",
|
|
50
|
+
method=compute_time,
|
|
51
|
+
req_config=[["imaging", ["frame rate"]]],
|
|
52
|
+
req_features=["frame"])
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
AncillaryFeature(feature_name="index",
|
|
56
|
+
method=compute_index)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def register():
|
|
60
|
+
AncillaryFeature(feature_name="area_ratio",
|
|
61
|
+
method=compute_area_ratio,
|
|
62
|
+
req_features=["area_cvx", "area_msd"])
|
|
63
|
+
|
|
64
|
+
AncillaryFeature(feature_name="area_um",
|
|
65
|
+
method=compute_area_um,
|
|
66
|
+
req_config=[["imaging", ["pixel size"]]],
|
|
67
|
+
req_features=["area_cvx"])
|
|
68
|
+
|
|
69
|
+
AncillaryFeature(feature_name="aspect",
|
|
70
|
+
method=compute_aspect,
|
|
71
|
+
req_features=["size_x", "size_y"])
|
|
72
|
+
|
|
73
|
+
AncillaryFeature(feature_name="deform",
|
|
74
|
+
method=compute_deform,
|
|
75
|
+
req_features=["circ"])
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
from ... import features
|
|
4
|
+
|
|
5
|
+
from .ancillary_feature import AncillaryFeature
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute_emodulus(mm):
|
|
9
|
+
"""Wrapper function for computing the Young's modulus
|
|
10
|
+
|
|
11
|
+
Please take a look at the docs :ref:`sec_emodulus_usage`
|
|
12
|
+
for more details on the three cases A, B, and C.
|
|
13
|
+
There are also some sanity checks taking place here.
|
|
14
|
+
"""
|
|
15
|
+
calccfg = mm.config["calculation"]
|
|
16
|
+
|
|
17
|
+
medium = calccfg.get("emodulus medium", "other").lower()
|
|
18
|
+
temperature = calccfg.get("emodulus temperature", None)
|
|
19
|
+
viscosity = calccfg.get("emodulus viscosity", None)
|
|
20
|
+
|
|
21
|
+
if viscosity is not None and medium == "other":
|
|
22
|
+
# sanity checks
|
|
23
|
+
if temperature is not None:
|
|
24
|
+
warnings.warn("The 'emodulus temperature' configuration key is "
|
|
25
|
+
"ignored if the 'emodulus viscosity' key is set!")
|
|
26
|
+
# Case B from the docs
|
|
27
|
+
return compute_emodulus_visc_only(mm)
|
|
28
|
+
else:
|
|
29
|
+
# sanity checks
|
|
30
|
+
if not isinstance(medium, str):
|
|
31
|
+
raise ValueError(
|
|
32
|
+
f"'emodulus medium' must be a string, got '{medium}'!")
|
|
33
|
+
if medium not in features.emodulus.viscosity.KNOWN_MEDIA:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"Only the following media are supported: "
|
|
36
|
+
f"{features.emodulus.viscosity.KNOWN_MEDIA}, got '{medium}'!")
|
|
37
|
+
if viscosity is not None:
|
|
38
|
+
raise ValueError("You must not set the 'emodulus viscosity' "
|
|
39
|
+
"configuration keyword for known media!")
|
|
40
|
+
# warnings
|
|
41
|
+
if "emodulus viscosity model" not in calccfg:
|
|
42
|
+
warnings.warn("Please specify the 'emodulus viscosity model' "
|
|
43
|
+
"key in the 'calculation' config segion, falling "
|
|
44
|
+
"back to 'herold-2017'!",
|
|
45
|
+
DeprecationWarning)
|
|
46
|
+
# actual function calls
|
|
47
|
+
if temperature is not None:
|
|
48
|
+
# case C from the docs
|
|
49
|
+
temperature = mm.config["calculation"]["emodulus temperature"]
|
|
50
|
+
return compute_emodulus_known_media(mm, temperature=temperature)
|
|
51
|
+
elif "temp" in mm:
|
|
52
|
+
# case A from the docs
|
|
53
|
+
return compute_emodulus_known_media(mm, temperature=mm["temp"])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def compute_emodulus_known_media(mm, temperature):
|
|
57
|
+
"""Only use known media and one temperature for all"""
|
|
58
|
+
calccfg = mm.config["calculation"]
|
|
59
|
+
# compute elastic modulus
|
|
60
|
+
emod = features.emodulus.get_emodulus(
|
|
61
|
+
area_um=mm["area_um"],
|
|
62
|
+
deform=mm["deform"],
|
|
63
|
+
medium=calccfg["emodulus medium"],
|
|
64
|
+
channel_width=mm.config["setup"]["channel width"],
|
|
65
|
+
flow_rate=mm.config["setup"]["flow rate"],
|
|
66
|
+
px_um=mm.config["imaging"]["pixel size"],
|
|
67
|
+
temperature=temperature,
|
|
68
|
+
lut_data=calccfg["emodulus lut"],
|
|
69
|
+
visc_model=calccfg.get("emodulus viscosity model", "herold-2017"),
|
|
70
|
+
)
|
|
71
|
+
return emod
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def compute_emodulus_visc_only(mm):
|
|
75
|
+
"""The user entered the viscosity directly"""
|
|
76
|
+
calccfg = mm.config["calculation"]
|
|
77
|
+
# compute elastic modulus
|
|
78
|
+
emod = features.emodulus.get_emodulus(
|
|
79
|
+
area_um=mm["area_um"],
|
|
80
|
+
deform=mm["deform"],
|
|
81
|
+
medium=calccfg["emodulus viscosity"],
|
|
82
|
+
channel_width=mm.config["setup"]["channel width"],
|
|
83
|
+
flow_rate=mm.config["setup"]["flow rate"],
|
|
84
|
+
px_um=mm.config["imaging"]["pixel size"],
|
|
85
|
+
temperature=None,
|
|
86
|
+
visc_model=None,
|
|
87
|
+
lut_data=calccfg["emodulus lut"],
|
|
88
|
+
)
|
|
89
|
+
return emod
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def is_channel(mm):
|
|
93
|
+
"""Check whether the measurement was performed in the channel
|
|
94
|
+
|
|
95
|
+
If the chip region is not set, then it is assumed to be a
|
|
96
|
+
channel measurement (for backwards compatibility and user-
|
|
97
|
+
friendliness).
|
|
98
|
+
"""
|
|
99
|
+
if "setup" in mm.config and "chip region" in mm.config["setup"]:
|
|
100
|
+
region = mm.config["setup"]["chip region"]
|
|
101
|
+
if region == "channel":
|
|
102
|
+
# measured in the channel
|
|
103
|
+
return True
|
|
104
|
+
else:
|
|
105
|
+
# measured in the reservoir
|
|
106
|
+
return False
|
|
107
|
+
else:
|
|
108
|
+
# This might be a testing dictionary or someone who is
|
|
109
|
+
# playing around with data. Avoid disappointments here.
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def register():
|
|
114
|
+
# Please note that registering these things is a delicate business,
|
|
115
|
+
# because the priority has to be chosen carefully.
|
|
116
|
+
# Note that here we have not included the "emodulus viscosity model"
|
|
117
|
+
# configuration keyword. This is checked in the `compute_emodulus`
|
|
118
|
+
# method above and a deprecation warning is issued, so old code
|
|
119
|
+
# does not break immediately.
|
|
120
|
+
for pr, vm in [(1, ["emodulus viscosity model"]),
|
|
121
|
+
(0, []) # this is deprecated and should be removed!
|
|
122
|
+
]:
|
|
123
|
+
AncillaryFeature(feature_name="emodulus",
|
|
124
|
+
method=compute_emodulus,
|
|
125
|
+
data="case C",
|
|
126
|
+
req_features=["area_um", "deform"],
|
|
127
|
+
req_config=[["calculation", vm + [
|
|
128
|
+
"emodulus lut",
|
|
129
|
+
"emodulus medium",
|
|
130
|
+
"emodulus temperature"]],
|
|
131
|
+
["imaging", ["pixel size"]],
|
|
132
|
+
["setup", ["flow rate", "channel width"]]
|
|
133
|
+
],
|
|
134
|
+
req_func=is_channel,
|
|
135
|
+
priority=4 + pr)
|
|
136
|
+
AncillaryFeature(feature_name="emodulus",
|
|
137
|
+
data="case A",
|
|
138
|
+
method=compute_emodulus,
|
|
139
|
+
req_features=["area_um", "deform", "temp"],
|
|
140
|
+
req_config=[["calculation", vm + [
|
|
141
|
+
"emodulus lut",
|
|
142
|
+
"emodulus medium"]],
|
|
143
|
+
["imaging", ["pixel size"]],
|
|
144
|
+
["setup", ["flow rate", "channel width"]]
|
|
145
|
+
],
|
|
146
|
+
req_func=is_channel,
|
|
147
|
+
priority=0 + pr)
|
|
148
|
+
|
|
149
|
+
AncillaryFeature(feature_name="emodulus",
|
|
150
|
+
data="case B",
|
|
151
|
+
method=compute_emodulus,
|
|
152
|
+
req_features=["area_um", "deform"],
|
|
153
|
+
req_config=[["calculation", vm + [
|
|
154
|
+
"emodulus lut",
|
|
155
|
+
"emodulus viscosity"]],
|
|
156
|
+
["imaging", ["pixel size"]],
|
|
157
|
+
["setup", ["flow rate", "channel width"]]
|
|
158
|
+
],
|
|
159
|
+
req_func=is_channel,
|
|
160
|
+
priority=2)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from ... import features
|
|
4
|
+
from .ancillary_feature import AncillaryFeature
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MissingCrosstalkMatrixElementsError(BaseException):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def compute_ctc(mm, fl_channel):
|
|
12
|
+
if "fl1_max" in mm:
|
|
13
|
+
fl1 = mm["fl1_max"]
|
|
14
|
+
else:
|
|
15
|
+
fl1 = 0
|
|
16
|
+
|
|
17
|
+
if "fl2_max" in mm:
|
|
18
|
+
fl2 = mm["fl2_max"]
|
|
19
|
+
else:
|
|
20
|
+
fl2 = 0
|
|
21
|
+
|
|
22
|
+
if "fl3_max" in mm:
|
|
23
|
+
fl3 = mm["fl3_max"]
|
|
24
|
+
else:
|
|
25
|
+
fl3 = 0
|
|
26
|
+
|
|
27
|
+
ctdict = {}
|
|
28
|
+
|
|
29
|
+
for i in [1, 2, 3]:
|
|
30
|
+
for j in [1, 2, 3]:
|
|
31
|
+
if i == j:
|
|
32
|
+
continue
|
|
33
|
+
key = "crosstalk fl{}{}".format(i, j)
|
|
34
|
+
par = "ct{}{}".format(i, j)
|
|
35
|
+
if key in mm.config["calculation"]:
|
|
36
|
+
ctdict[par] = mm.config["calculation"][key]
|
|
37
|
+
|
|
38
|
+
if ("fl1_max" in mm and
|
|
39
|
+
"fl2_max" in mm and
|
|
40
|
+
"fl3_max" in mm and
|
|
41
|
+
("ct12" not in ctdict or
|
|
42
|
+
"ct13" not in ctdict or
|
|
43
|
+
"ct21" not in ctdict or
|
|
44
|
+
"ct23" not in ctdict or
|
|
45
|
+
"ct31" not in ctdict or
|
|
46
|
+
"ct32" not in ctdict)):
|
|
47
|
+
msg = "{}, has fl1_max, fl2_max, and fl3_max,".format(mm) \
|
|
48
|
+
+ " but not all crosstalk matrix elements are" \
|
|
49
|
+
+ " defined in the 'calculation' configuration section."
|
|
50
|
+
raise MissingCrosstalkMatrixElementsError(msg)
|
|
51
|
+
|
|
52
|
+
return features.fl_crosstalk.correct_crosstalk(
|
|
53
|
+
fl1=fl1,
|
|
54
|
+
fl2=fl2,
|
|
55
|
+
fl3=fl3,
|
|
56
|
+
fl_channel=fl_channel,
|
|
57
|
+
**ctdict)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def compute_ctc1(mm):
|
|
61
|
+
return compute_ctc(mm, fl_channel=1)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def compute_ctc2(mm):
|
|
65
|
+
return compute_ctc(mm, fl_channel=2)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def compute_ctc3(mm):
|
|
69
|
+
return compute_ctc(mm, fl_channel=3)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_method(fl_channel):
|
|
73
|
+
if fl_channel == 1:
|
|
74
|
+
return compute_ctc1
|
|
75
|
+
elif fl_channel == 2:
|
|
76
|
+
return compute_ctc2
|
|
77
|
+
elif fl_channel == 3:
|
|
78
|
+
return compute_ctc3
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def register():
|
|
82
|
+
opts_all = (["fl1_max",
|
|
83
|
+
"fl2_max",
|
|
84
|
+
"fl3_max"],
|
|
85
|
+
["crosstalk fl21",
|
|
86
|
+
"crosstalk fl31",
|
|
87
|
+
"crosstalk fl12",
|
|
88
|
+
"crosstalk fl32",
|
|
89
|
+
"crosstalk fl13",
|
|
90
|
+
"crosstalk fl23"])
|
|
91
|
+
|
|
92
|
+
opts_12 = (["fl1_max",
|
|
93
|
+
"fl2_max"],
|
|
94
|
+
["crosstalk fl21",
|
|
95
|
+
"crosstalk fl12"])
|
|
96
|
+
|
|
97
|
+
opts_13 = (["fl1_max",
|
|
98
|
+
"fl3_max"],
|
|
99
|
+
["crosstalk fl31",
|
|
100
|
+
"crosstalk fl13"])
|
|
101
|
+
|
|
102
|
+
opts_23 = (["fl2_max",
|
|
103
|
+
"fl3_max"],
|
|
104
|
+
["crosstalk fl32",
|
|
105
|
+
"crosstalk fl23"])
|
|
106
|
+
|
|
107
|
+
for flch in [1, 2, 3]:
|
|
108
|
+
AncillaryFeature(feature_name="fl{}_max_ctc".format(flch),
|
|
109
|
+
method=get_method(flch),
|
|
110
|
+
req_features=opts_all[0],
|
|
111
|
+
req_config=[["calculation", opts_all[1]]],
|
|
112
|
+
priority=1)
|
|
113
|
+
|
|
114
|
+
for flch in [1, 2]:
|
|
115
|
+
AncillaryFeature(feature_name="fl{}_max_ctc".format(flch),
|
|
116
|
+
method=get_method(flch),
|
|
117
|
+
req_features=opts_12[0],
|
|
118
|
+
req_config=[["calculation", opts_12[1]]],
|
|
119
|
+
priority=0)
|
|
120
|
+
|
|
121
|
+
for flch in [1, 3]:
|
|
122
|
+
AncillaryFeature(feature_name="fl{}_max_ctc".format(flch),
|
|
123
|
+
method=get_method(flch),
|
|
124
|
+
req_features=opts_13[0],
|
|
125
|
+
req_config=[["calculation", opts_13[1]]],
|
|
126
|
+
priority=0)
|
|
127
|
+
|
|
128
|
+
for flch in [2, 3]:
|
|
129
|
+
AncillaryFeature(feature_name="fl{}_max_ctc".format(flch),
|
|
130
|
+
method=get_method(flch),
|
|
131
|
+
req_features=opts_23[0],
|
|
132
|
+
req_config=[["calculation", opts_23[1]]],
|
|
133
|
+
priority=0)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from ... import features
|
|
2
|
+
from .ancillary_feature import AncillaryFeature
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def compute_contour(mm):
|
|
6
|
+
cont = features.contour.get_contour_lazily(mask=mm["mask"])
|
|
7
|
+
return cont
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def compute_bright(mm):
|
|
11
|
+
bavg, bsd = features.bright.get_bright(
|
|
12
|
+
mask=mm["mask"],
|
|
13
|
+
image=mm["image"],
|
|
14
|
+
ret_data="avg,sd",
|
|
15
|
+
)
|
|
16
|
+
return {"bright_avg": bavg, "bright_sd": bsd}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def compute_bright_bc(mm):
|
|
20
|
+
bavg, bsd = features.bright_bc.get_bright_bc(
|
|
21
|
+
mask=mm["mask"],
|
|
22
|
+
image=mm["image"],
|
|
23
|
+
image_bg=mm["image_bg"],
|
|
24
|
+
bg_off=mm["bg_off"] if "bg_off" in mm else None,
|
|
25
|
+
ret_data="avg,sd",
|
|
26
|
+
)
|
|
27
|
+
return {"bright_bc_avg": bavg, "bright_bc_sd": bsd}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def compute_bright_perc(mm):
|
|
31
|
+
p10, p90 = features.bright_perc.get_bright_perc(
|
|
32
|
+
mask=mm["mask"],
|
|
33
|
+
image=mm["image"],
|
|
34
|
+
image_bg=mm["image_bg"],
|
|
35
|
+
bg_off=mm["bg_off"] if "bg_off" in mm else None,
|
|
36
|
+
)
|
|
37
|
+
return {"bright_perc_10": p10, "bright_perc_90": p90}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def compute_inert_ratio_cvx(mm):
|
|
41
|
+
return features.inert_ratio.get_inert_ratio_cvx(cont=mm["contour"])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def compute_inert_ratio_prnc(mm):
|
|
45
|
+
return features.inert_ratio.get_inert_ratio_prnc(cont=mm["contour"])
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def compute_inert_ratio_raw(mm):
|
|
49
|
+
return features.inert_ratio.get_inert_ratio_raw(cont=mm["contour"])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def compute_tilt(mm):
|
|
53
|
+
return features.inert_ratio.get_tilt(cont=mm["contour"])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def compute_volume(mm):
|
|
57
|
+
vol = features.volume.get_volume(
|
|
58
|
+
cont=mm["contour"],
|
|
59
|
+
pos_x=mm["pos_x"],
|
|
60
|
+
pos_y=mm["pos_y"],
|
|
61
|
+
pix=mm.config["imaging"]["pixel size"])
|
|
62
|
+
return vol
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def register():
|
|
66
|
+
AncillaryFeature(feature_name="contour",
|
|
67
|
+
method=compute_contour,
|
|
68
|
+
req_features=["mask"])
|
|
69
|
+
|
|
70
|
+
AncillaryFeature(feature_name="bright_avg",
|
|
71
|
+
method=compute_bright,
|
|
72
|
+
req_features=["image", "mask"])
|
|
73
|
+
|
|
74
|
+
AncillaryFeature(feature_name="bright_sd",
|
|
75
|
+
method=compute_bright,
|
|
76
|
+
req_features=["image", "mask"])
|
|
77
|
+
|
|
78
|
+
AncillaryFeature(feature_name="bright_bc_avg",
|
|
79
|
+
method=compute_bright_bc,
|
|
80
|
+
req_features=["image", "image_bg", "mask"])
|
|
81
|
+
|
|
82
|
+
AncillaryFeature(feature_name="bright_bc_sd",
|
|
83
|
+
method=compute_bright_bc,
|
|
84
|
+
req_features=["image", "image_bg", "mask"])
|
|
85
|
+
|
|
86
|
+
AncillaryFeature(feature_name="bright_perc_10",
|
|
87
|
+
method=compute_bright_perc,
|
|
88
|
+
req_features=["image", "image_bg", "mask"])
|
|
89
|
+
|
|
90
|
+
AncillaryFeature(feature_name="bright_perc_90",
|
|
91
|
+
method=compute_bright_perc,
|
|
92
|
+
req_features=["image", "image_bg", "mask"])
|
|
93
|
+
|
|
94
|
+
AncillaryFeature(feature_name="inert_ratio_cvx",
|
|
95
|
+
method=compute_inert_ratio_cvx,
|
|
96
|
+
req_features=["contour"])
|
|
97
|
+
|
|
98
|
+
AncillaryFeature(feature_name="inert_ratio_prnc",
|
|
99
|
+
method=compute_inert_ratio_prnc,
|
|
100
|
+
req_features=["contour"])
|
|
101
|
+
|
|
102
|
+
AncillaryFeature(feature_name="inert_ratio_raw",
|
|
103
|
+
method=compute_inert_ratio_raw,
|
|
104
|
+
req_features=["contour"])
|
|
105
|
+
|
|
106
|
+
AncillaryFeature(feature_name="tilt",
|
|
107
|
+
method=compute_tilt,
|
|
108
|
+
req_features=["contour"])
|
|
109
|
+
|
|
110
|
+
AncillaryFeature(feature_name="volume",
|
|
111
|
+
method=compute_volume,
|
|
112
|
+
req_features=["contour", "pos_x", "pos_y"],
|
|
113
|
+
req_config=[["imaging", ["pixel size"]]])
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
from .ancillary_feature import AncillaryFeature
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_ml_score_names(mm):
|
|
7
|
+
"""Return a list of all ml_score_??? features"""
|
|
8
|
+
feats = []
|
|
9
|
+
# We cannot loop over mm.features because of infinite recursions
|
|
10
|
+
for ft in mm._feature_candidates:
|
|
11
|
+
if ft.startswith("ml_score_") and ft in mm:
|
|
12
|
+
feats.append(ft)
|
|
13
|
+
return sorted(feats)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def compute_ml_class(mm, sanity_checks=True):
|
|
17
|
+
"""Compute the most-probable class membership for all events
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
mm: .RTDCBase
|
|
22
|
+
instance with the `ml_score_???` features
|
|
23
|
+
sanity_checks: bool
|
|
24
|
+
set to `False` to not perform sanity checks (checks whether
|
|
25
|
+
the scores are between 0 and 1)
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
ml_class: 1D ndarray
|
|
30
|
+
The most-probable class for each event in `mm`. If no class
|
|
31
|
+
can be attributed to an event (because the scores are all
|
|
32
|
+
`np.nan` or `0` for that event), the class `-1` is used.
|
|
33
|
+
|
|
34
|
+
Notes
|
|
35
|
+
-----
|
|
36
|
+
I initially thought about also checking whether each feature
|
|
37
|
+
sums to one, but discarded the idea. Let's assume that a classifier
|
|
38
|
+
does an awful classification and classifies all events in
|
|
39
|
+
the same way. If the dataset is cropped at some point (e.g.
|
|
40
|
+
debris or other events), then this bad classifier has an
|
|
41
|
+
increased probability compared to another classifier which is
|
|
42
|
+
perfect at picking out one population. The ml_score values
|
|
43
|
+
should be just in the range of [0, 1]. This also simplifies
|
|
44
|
+
export to hdf5 and the work with hierarchy children.
|
|
45
|
+
"""
|
|
46
|
+
feats = get_ml_score_names(mm)
|
|
47
|
+
|
|
48
|
+
# the score matrix
|
|
49
|
+
score_matrix = np.zeros((len(mm), len(feats)), dtype=float)
|
|
50
|
+
|
|
51
|
+
for ii, ft in enumerate(feats):
|
|
52
|
+
if sanity_checks:
|
|
53
|
+
if np.nanmax(mm[ft]) > 1:
|
|
54
|
+
raise ValueError("Feature '{}' has values > 1!".format(ft))
|
|
55
|
+
elif np.nanmin(mm[ft]) < 0:
|
|
56
|
+
raise ValueError("Feature '{}' has values < 0!".format(ft))
|
|
57
|
+
score_matrix[:, ii] = mm[ft]
|
|
58
|
+
|
|
59
|
+
# Now compute the maximum for each event. The initial idea was to just
|
|
60
|
+
# use `ml_class = np.nanargmax(score_matrix, axis=1)`. However, here we
|
|
61
|
+
# run into these problems:
|
|
62
|
+
# 1. This does not handle All-NaN slices, e.g. all features are `np.nan`
|
|
63
|
+
# for an event.
|
|
64
|
+
# 2. This does not properly handle manually-rated, zero-valued features,
|
|
65
|
+
# e.g. in a situation where we have two features, one with `np.nan`
|
|
66
|
+
# and one with `0`, we cannot assign the event to either of the two
|
|
67
|
+
# classes.
|
|
68
|
+
# 3. There is no "unclassified" class (this also becomes apparent in
|
|
69
|
+
# point 2). We will set all events that cannot be attributed to a
|
|
70
|
+
# class to `-1` in `ml_class`.
|
|
71
|
+
|
|
72
|
+
# Define unusable entries:
|
|
73
|
+
unusable = np.logical_or(np.isnan(score_matrix), (score_matrix == 0))
|
|
74
|
+
where_idx_nan = np.sum(~unusable, axis=1) == 0
|
|
75
|
+
score_matrix[where_idx_nan, :] = -1
|
|
76
|
+
ml_class = np.nanargmax(score_matrix, axis=1)
|
|
77
|
+
ml_class[where_idx_nan] = -1
|
|
78
|
+
return ml_class
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def has_ml_scores(mm):
|
|
82
|
+
"""Check whether the dataset has ml_scores defined"""
|
|
83
|
+
# Return the sorted score names plus Ancillary feature hashes.
|
|
84
|
+
# This will be used to determine the hash of the ml_class feature,
|
|
85
|
+
# which is important in case the user replaces an ML feature
|
|
86
|
+
# with a new one.
|
|
87
|
+
features = get_ml_score_names(mm)
|
|
88
|
+
idlist = []
|
|
89
|
+
for feat in features:
|
|
90
|
+
# We also hash any other AncillaryFeature that might implement
|
|
91
|
+
# this ML score. But this use case is basically non-existent and
|
|
92
|
+
# the performance impact is probably negligible.
|
|
93
|
+
candidates = AncillaryFeature.get_instances(feat)
|
|
94
|
+
idlist.append((feat, [c.hash(mm) for c in candidates]))
|
|
95
|
+
return idlist
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def register():
|
|
99
|
+
AncillaryFeature(feature_name="ml_class",
|
|
100
|
+
method=compute_ml_class,
|
|
101
|
+
req_func=has_ml_scores,
|
|
102
|
+
)
|