dclab 0.62.11__cp313-cp313-win_amd64.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.

Files changed (137) hide show
  1. dclab/__init__.py +23 -0
  2. dclab/_version.py +16 -0
  3. dclab/cached.py +97 -0
  4. dclab/cli/__init__.py +10 -0
  5. dclab/cli/common.py +237 -0
  6. dclab/cli/task_compress.py +126 -0
  7. dclab/cli/task_condense.py +223 -0
  8. dclab/cli/task_join.py +229 -0
  9. dclab/cli/task_repack.py +98 -0
  10. dclab/cli/task_split.py +154 -0
  11. dclab/cli/task_tdms2rtdc.py +186 -0
  12. dclab/cli/task_verify_dataset.py +75 -0
  13. dclab/definitions/__init__.py +79 -0
  14. dclab/definitions/feat_const.py +202 -0
  15. dclab/definitions/feat_logic.py +183 -0
  16. dclab/definitions/meta_const.py +252 -0
  17. dclab/definitions/meta_logic.py +111 -0
  18. dclab/definitions/meta_parse.py +94 -0
  19. dclab/downsampling.cp313-win_amd64.pyd +0 -0
  20. dclab/downsampling.pyx +230 -0
  21. dclab/external/__init__.py +4 -0
  22. dclab/external/packaging/LICENSE +3 -0
  23. dclab/external/packaging/LICENSE.APACHE +177 -0
  24. dclab/external/packaging/LICENSE.BSD +23 -0
  25. dclab/external/packaging/__init__.py +6 -0
  26. dclab/external/packaging/_structures.py +61 -0
  27. dclab/external/packaging/version.py +505 -0
  28. dclab/external/skimage/LICENSE +28 -0
  29. dclab/external/skimage/__init__.py +2 -0
  30. dclab/external/skimage/_find_contours.py +216 -0
  31. dclab/external/skimage/_find_contours_cy.cp313-win_amd64.pyd +0 -0
  32. dclab/external/skimage/_find_contours_cy.pyx +188 -0
  33. dclab/external/skimage/_pnpoly.cp313-win_amd64.pyd +0 -0
  34. dclab/external/skimage/_pnpoly.pyx +99 -0
  35. dclab/external/skimage/_shared/__init__.py +1 -0
  36. dclab/external/skimage/_shared/geometry.cp313-win_amd64.pyd +0 -0
  37. dclab/external/skimage/_shared/geometry.pxd +6 -0
  38. dclab/external/skimage/_shared/geometry.pyx +55 -0
  39. dclab/external/skimage/measure.py +7 -0
  40. dclab/external/skimage/pnpoly.py +53 -0
  41. dclab/external/statsmodels/LICENSE +35 -0
  42. dclab/external/statsmodels/__init__.py +6 -0
  43. dclab/external/statsmodels/nonparametric/__init__.py +1 -0
  44. dclab/external/statsmodels/nonparametric/_kernel_base.py +203 -0
  45. dclab/external/statsmodels/nonparametric/kernel_density.py +165 -0
  46. dclab/external/statsmodels/nonparametric/kernels.py +36 -0
  47. dclab/features/__init__.py +9 -0
  48. dclab/features/bright.py +81 -0
  49. dclab/features/bright_bc.py +93 -0
  50. dclab/features/bright_perc.py +63 -0
  51. dclab/features/contour.py +161 -0
  52. dclab/features/emodulus/__init__.py +339 -0
  53. dclab/features/emodulus/load.py +252 -0
  54. dclab/features/emodulus/lut_HE-2D-FEM-22.txt +16432 -0
  55. dclab/features/emodulus/lut_HE-3D-FEM-22.txt +1276 -0
  56. dclab/features/emodulus/lut_LE-2D-FEM-19.txt +13082 -0
  57. dclab/features/emodulus/pxcorr.py +135 -0
  58. dclab/features/emodulus/scale_linear.py +247 -0
  59. dclab/features/emodulus/viscosity.py +256 -0
  60. dclab/features/fl_crosstalk.py +95 -0
  61. dclab/features/inert_ratio.py +377 -0
  62. dclab/features/volume.py +242 -0
  63. dclab/http_utils.py +322 -0
  64. dclab/isoelastics/__init__.py +468 -0
  65. dclab/isoelastics/iso_HE-2D-FEM-22-area_um-deform.txt +2440 -0
  66. dclab/isoelastics/iso_HE-2D-FEM-22-volume-deform.txt +2635 -0
  67. dclab/isoelastics/iso_HE-3D-FEM-22-area_um-deform.txt +1930 -0
  68. dclab/isoelastics/iso_HE-3D-FEM-22-volume-deform.txt +2221 -0
  69. dclab/isoelastics/iso_LE-2D-FEM-19-area_um-deform.txt +2151 -0
  70. dclab/isoelastics/iso_LE-2D-FEM-19-volume-deform.txt +2250 -0
  71. dclab/isoelastics/iso_LE-2D-ana-18-area_um-deform.txt +1266 -0
  72. dclab/kde_contours.py +222 -0
  73. dclab/kde_methods.py +303 -0
  74. dclab/lme4/__init__.py +5 -0
  75. dclab/lme4/lme4_template.R +94 -0
  76. dclab/lme4/rsetup.py +204 -0
  77. dclab/lme4/wrapr.py +386 -0
  78. dclab/polygon_filter.py +398 -0
  79. dclab/rtdc_dataset/__init__.py +15 -0
  80. dclab/rtdc_dataset/check.py +902 -0
  81. dclab/rtdc_dataset/config.py +533 -0
  82. dclab/rtdc_dataset/copier.py +353 -0
  83. dclab/rtdc_dataset/core.py +1001 -0
  84. dclab/rtdc_dataset/export.py +737 -0
  85. dclab/rtdc_dataset/feat_anc_core/__init__.py +24 -0
  86. dclab/rtdc_dataset/feat_anc_core/af_basic.py +75 -0
  87. dclab/rtdc_dataset/feat_anc_core/af_emodulus.py +160 -0
  88. dclab/rtdc_dataset/feat_anc_core/af_fl_max_ctc.py +133 -0
  89. dclab/rtdc_dataset/feat_anc_core/af_image_contour.py +113 -0
  90. dclab/rtdc_dataset/feat_anc_core/af_ml_class.py +102 -0
  91. dclab/rtdc_dataset/feat_anc_core/ancillary_feature.py +320 -0
  92. dclab/rtdc_dataset/feat_anc_ml/__init__.py +32 -0
  93. dclab/rtdc_dataset/feat_anc_plugin/__init__.py +3 -0
  94. dclab/rtdc_dataset/feat_anc_plugin/plugin_feature.py +329 -0
  95. dclab/rtdc_dataset/feat_basin.py +550 -0
  96. dclab/rtdc_dataset/feat_temp.py +102 -0
  97. dclab/rtdc_dataset/filter.py +263 -0
  98. dclab/rtdc_dataset/fmt_dcor/__init__.py +7 -0
  99. dclab/rtdc_dataset/fmt_dcor/access_token.py +52 -0
  100. dclab/rtdc_dataset/fmt_dcor/api.py +111 -0
  101. dclab/rtdc_dataset/fmt_dcor/base.py +200 -0
  102. dclab/rtdc_dataset/fmt_dcor/basin.py +73 -0
  103. dclab/rtdc_dataset/fmt_dcor/logs.py +26 -0
  104. dclab/rtdc_dataset/fmt_dcor/tables.py +42 -0
  105. dclab/rtdc_dataset/fmt_dict.py +103 -0
  106. dclab/rtdc_dataset/fmt_hdf5/__init__.py +6 -0
  107. dclab/rtdc_dataset/fmt_hdf5/base.py +192 -0
  108. dclab/rtdc_dataset/fmt_hdf5/basin.py +30 -0
  109. dclab/rtdc_dataset/fmt_hdf5/events.py +257 -0
  110. dclab/rtdc_dataset/fmt_hdf5/feat_defect.py +164 -0
  111. dclab/rtdc_dataset/fmt_hdf5/logs.py +33 -0
  112. dclab/rtdc_dataset/fmt_hdf5/tables.py +30 -0
  113. dclab/rtdc_dataset/fmt_hierarchy/__init__.py +11 -0
  114. dclab/rtdc_dataset/fmt_hierarchy/base.py +278 -0
  115. dclab/rtdc_dataset/fmt_hierarchy/events.py +146 -0
  116. dclab/rtdc_dataset/fmt_hierarchy/hfilter.py +140 -0
  117. dclab/rtdc_dataset/fmt_hierarchy/mapper.py +134 -0
  118. dclab/rtdc_dataset/fmt_http.py +102 -0
  119. dclab/rtdc_dataset/fmt_s3.py +320 -0
  120. dclab/rtdc_dataset/fmt_tdms/__init__.py +476 -0
  121. dclab/rtdc_dataset/fmt_tdms/event_contour.py +264 -0
  122. dclab/rtdc_dataset/fmt_tdms/event_image.py +220 -0
  123. dclab/rtdc_dataset/fmt_tdms/event_mask.py +62 -0
  124. dclab/rtdc_dataset/fmt_tdms/event_trace.py +146 -0
  125. dclab/rtdc_dataset/fmt_tdms/exc.py +37 -0
  126. dclab/rtdc_dataset/fmt_tdms/naming.py +151 -0
  127. dclab/rtdc_dataset/load.py +72 -0
  128. dclab/rtdc_dataset/writer.py +985 -0
  129. dclab/statistics.py +203 -0
  130. dclab/util.py +156 -0
  131. dclab/warn.py +15 -0
  132. dclab-0.62.11.dist-info/LICENSE +343 -0
  133. dclab-0.62.11.dist-info/METADATA +146 -0
  134. dclab-0.62.11.dist-info/RECORD +137 -0
  135. dclab-0.62.11.dist-info/WHEEL +5 -0
  136. dclab-0.62.11.dist-info/entry_points.txt +8 -0
  137. dclab-0.62.11.dist-info/top_level.txt +1 -0
@@ -0,0 +1,202 @@
1
+ #: List of scalar (one scalar value per event) features. This
2
+ #: list does not include the `ml_score_???` features. If you
3
+ #: need find out whether a feature name is valid, please use
4
+ #: :func:`is_valid_feature`.
5
+ FEATURES_SCALAR = [
6
+ ["area_cvx", "Convex area [px]"],
7
+ # area_msd is the contour moment M00
8
+ ["area_msd", "Measured area [px]"],
9
+ ["area_ratio", "Porosity (convex to measured area ratio)"],
10
+ # area_um is computed from the convex contour
11
+ ["area_um", "Area [µm²]"],
12
+ ["area_um_raw", "Area [µm²] of raw contour"],
13
+ ["aspect", "Aspect ratio of bounding box"],
14
+ # The background brightness of the frame (not of the mask)
15
+ ["bg_med", "Median frame background brightness [a.u.]"],
16
+ # Background image offset which should be added to "image_bg" before
17
+ # performing background correction. This is used in cases where the
18
+ # background stored in "image_bg" is not accurate enough, e.g.
19
+ # because the image_bg is a median image for multiple events and
20
+ # the imaging system exhibits flickering.
21
+ ["bg_off", "Background offset [a.u.]"],
22
+ # Brightness values are computed only for pixels inside the mask
23
+ ["bright_avg", "Brightness average [a.u.]"],
24
+ ["bright_sd", "Brightness SD [a.u.]"],
25
+ ["bright_bc_avg", "Brightness average (bgc) [a.u.]"],
26
+ ["bright_bc_sd", "Brightness SD (bgc) [a.u.]"],
27
+ ["bright_perc_10", "10th Percentile of brightness (bgc)"],
28
+ ["bright_perc_90", "90th Percentile of brightness (bgc)"],
29
+ ["circ", "Circularity"],
30
+ # deform is computed from the convex contour
31
+ ["deform", "Deformation"],
32
+ ["deform_raw", "Deformation of raw contour"],
33
+ ["eccentr_prnc", "Eccentricity of raw contour"],
34
+ ["emodulus", "Young's modulus [kPa]"],
35
+ # fl*_area, fl*_pos, and fl*_width values correspond to the
36
+ # object for which the contour was found. For high concentrations,
37
+ # these values could be error-prone due to the assignment from
38
+ # false objects.
39
+ ["fl1_area", "FL-1 area of peak [a.u.]"],
40
+ # fl1_dist is set to zero if there is only one peak
41
+ ["fl1_dist", "FL-1 distance between two first peaks [µs]"],
42
+ ["fl1_max", "FL-1 maximum [a.u.]"],
43
+ ["fl1_max_ctc", "FL-1 maximum, crosstalk-corrected [a.u.]"],
44
+ ["fl1_npeaks", "FL-1 number of peaks"],
45
+ ["fl1_pos", "FL-1 position of peak [µs]"],
46
+ ["fl1_width", "FL-1 width [µs]"],
47
+ ["fl2_area", "FL-2 area of peak [a.u.]"],
48
+ ["fl2_dist", "FL-2 distance between two first peaks [µs]"],
49
+ ["fl2_max", "FL-2 maximum [a.u.]"],
50
+ ["fl2_max_ctc", "FL-2 maximum, crosstalk-corrected [a.u.]"],
51
+ ["fl2_npeaks", "FL-2 number of peaks"],
52
+ ["fl2_pos", "FL-2 position of peak [µs]"],
53
+ ["fl2_width", "FL-2 width [µs]"],
54
+ ["fl3_area", "FL-3 area of peak [a.u.]"],
55
+ ["fl3_dist", "FL-3 distance between two first peaks [µs]"],
56
+ ["fl3_max", "FL-3 maximum [a.u.]"],
57
+ ["fl3_max_ctc", "FL-3 maximum, crosstalk-corrected [a.u.]"],
58
+ ["fl3_npeaks", "FL-3 number of peaks"],
59
+ ["fl3_pos", "FL-3 position of peak [µs]"],
60
+ ["fl3_width", "FL-3 width [µs]"],
61
+ # Sum of the flow rates for sample and sheath flow
62
+ ["flow_rate", "Flow rate [µLs⁻¹]"],
63
+ ["frame", "Video frame number"],
64
+ ["g_force", "Gravitational force in multiples of g"],
65
+ # index starts with 1
66
+ ["index", "Index (Dataset)"],
67
+ # index_online enumerates the events found by Shape-In and may have
68
+ # missing values in case of a writer-overrun with recovery (#71)
69
+ ["index_online", "Index (Online)"],
70
+ # The inertia ratios of the event contours are defined by the
71
+ # central second order moments of area (sqrt(m20/m02).
72
+ ["inert_ratio_cvx", "Inertia ratio of convex contour"],
73
+ ["inert_ratio_prnc", "Principal inertia ratio of raw contour"],
74
+ ["inert_ratio_raw", "Inertia ratio of raw contour"],
75
+ # This is an ancillary integer feature for visualizing the class
76
+ # membership of individual events based on the `ml_score_???`
77
+ # features.
78
+ ["ml_class", "Most probable ML class"],
79
+ ["nevents", "Number of events in the same image"],
80
+ ["pc1", "Principal component 1"],
81
+ ["pc2", "Principal component 2"],
82
+ # Convexity is defined by the ratio of convex contour length
83
+ # versus raw contour length. We use inverse convexity as it is
84
+ # more convenient to work with numbers >1.
85
+ ["per_ratio", "Inverse Convexity (raw to convex perimeter ratio)"],
86
+ ["per_um_raw", "Perimeter [µm] of raw contour"],
87
+ # pos_x and pos_y are computed from the contour moments
88
+ # "m10"/"m00" and "m01"/"m00" of the convex hull of "contour"
89
+ ["pos_x", "Position along channel axis [µm]"],
90
+ ["pos_y", "Position lateral in channel [µm]"],
91
+ # Sum of the pressures applied to sample and sheath flow
92
+ ["pressure", "Pressure [mPa]"],
93
+ # QPI features computed from holographic data
94
+ ["qpi_dm_avg", "Dry mass (average) [pg]"],
95
+ ["qpi_dm_sd", "Dry mass (SD) [pg]"],
96
+ ["qpi_pha_int", "Integrated phase [rad]"],
97
+ ["qpi_ri_avg", "Refractive index (average)"],
98
+ ["qpi_ri_sd", "Refractive index (SD)"],
99
+ # QPI features from refocused events
100
+ ["qpi_focus", "Computed focus distance [µm]"],
101
+ # Size features
102
+ ["size_x", "Bounding box size x [µm]"],
103
+ ["size_y", "Bounding box size y [µm]"],
104
+ # Ratio between two halves of a mask
105
+ ["sym_x", "Symmetry ratio left-right"],
106
+ ["sym_y", "Symmetry ratio top-bottom"],
107
+ ["temp", "Chip temperature [°C]"],
108
+ ["temp_amb", "Ambient temperature [°C]"],
109
+ # Haralick texture features can be computed using the mahotas package
110
+ # from the background-corrected and masked image
111
+ ["tex_asm_avg", "Texture angular second moment (avg)"], # H1
112
+ ["tex_asm_ptp", "Texture angular second moment (ptp)"], # H1
113
+ ["tex_con_avg", "Texture contrast (avg)"], # H2
114
+ ["tex_con_ptp", "Texture contrast (ptp)"], # H2
115
+ ["tex_cor_avg", "Texture correlation (avg)"], # H3
116
+ ["tex_cor_ptp", "Texture correlation (ptp)"], # H3
117
+ ["tex_den_avg", "Texture difference entropy (avg)"], # 11
118
+ ["tex_den_ptp", "Texture difference entropy (ptp)"], # 11
119
+ ["tex_ent_avg", "Texture entropy (avg)"], # H9
120
+ ["tex_ent_ptp", "Texture entropy (ptp)"], # H9
121
+ ["tex_f12_avg", "Texture First measure of correlation (avg)"], # 12
122
+ ["tex_f12_ptp", "Texture First measure of correlation (ptp)"], # 12
123
+ ["tex_f13_avg", "Texture Second measure of correlation (avg)"], # 13
124
+ ["tex_f13_ptp", "Texture Second measure of correlation (ptp)"], # 13
125
+ ["tex_idm_avg", "Texture inverse difference moment (avg)"], # H5
126
+ ["tex_idm_ptp", "Texture inverse difference moment (ptp)"], # H5
127
+ ["tex_sen_avg", "Texture sum entropy (avg)"], # H8
128
+ ["tex_sen_ptp", "Texture sum entropy (ptp)"], # H8
129
+ ["tex_sva_avg", "Texture sum variance (avg)"], # H7
130
+ ["tex_sva_ptp", "Texture sum variance (ptp)"], # H7
131
+ ["tex_var_avg", "Texture variance (avg)"], # H4
132
+ ["tex_var_ptp", "Texture variance (ptp)"], # H4
133
+ ["tilt", "Absolute tilt of raw contour"],
134
+ ["time", "Time [s]"],
135
+ # Volume is computed from the raw contour (i.e. with exclusions).
136
+ # Fun fact: If we had decided to compute it from the convex contour,
137
+ # then we would have close to none pixelation effects ¯\_(ツ)_/¯.
138
+ ["volume", "Volume [µm³]"],
139
+ ]
140
+
141
+ #: User-defined features: They are not reserved for anything specific
142
+ #: and can be used by the user for e.g. prototyping.
143
+ for _i in range(10):
144
+ FEATURES_SCALAR.append([f"userdef{_i}", f"User-defined {_i}"])
145
+
146
+ #: Basin mapping features: These are used for datasets that are derived from a
147
+ #: subset of events of another dataset. For instance, if a dataset consists
148
+ #: of every second event from another dataset, the feature `basinmap1` would
149
+ #: consist of the integer array `[1, 3, 5, 7, ...]` (indexing starts at zero).
150
+ #: The `basinmap1` feature must then be referenced in the corresponding basin
151
+ #: definition. These features should not be presented explicitly to the
152
+ #: normal user (e.g. in Shape-Out) to avoid ambiguities, and they should
153
+ #: always be exported alongside basins that refer to them.
154
+ for _j in range(10):
155
+ FEATURES_SCALAR.append([f"basinmap{_j}", f"Basin mapping {_j}"])
156
+
157
+ #: list of non-scalar features
158
+ FEATURES_NON_SCALAR = [
159
+ # This is a (M, 2)-shaped array with integer contour coordinates
160
+ ["contour", "Event contour"],
161
+ ["image", "Gray scale event image"],
162
+ ["image_bg", "Gray scale event background image"],
163
+ # This is the contour with holes filled
164
+ ["mask", "Binary mask labeling the event in the image"],
165
+ # See FLUOR_TRACES for valid keys
166
+ ["trace", "Dictionary of fluorescence traces"],
167
+ # QPI experimental holographic data
168
+ ["qpi_oah", "Off-axis hologram"],
169
+ # QPI holographic background data (experimental or computed)
170
+ ["qpi_oah_bg", "Off-axis hologram background"],
171
+ # QPI features computed from holographic data
172
+ ["qpi_pha", "Hologram phase image [rad]"],
173
+ ["qpi_amp", "Hologram amplitude image"],
174
+ ]
175
+
176
+ #: List of fluorescence traces
177
+ FLUOR_TRACES = [
178
+ "fl1_median",
179
+ "fl1_raw",
180
+ "fl2_median",
181
+ "fl2_raw",
182
+ "fl3_median",
183
+ "fl3_raw",
184
+ ]
185
+
186
+
187
+ # FEATURE convenience lists and dicts
188
+
189
+ #: list of feature names
190
+ feature_names = [_cc[0] for _cc in FEATURES_SCALAR + FEATURES_NON_SCALAR]
191
+
192
+ #: list of feature labels (same order as :const:`feature_names`
193
+ feature_labels = [_cc[1] for _cc in FEATURES_SCALAR + FEATURES_NON_SCALAR]
194
+
195
+ #: dict for converting feature names to labels
196
+ feature_name2label = {}
197
+
198
+ for _cc in FEATURES_SCALAR + FEATURES_NON_SCALAR:
199
+ feature_name2label[_cc[0]] = _cc[1]
200
+
201
+ #: list of scalar feature names
202
+ scalar_feature_names = [_cc[0] for _cc in FEATURES_SCALAR]
@@ -0,0 +1,183 @@
1
+ from . import feat_const
2
+
3
+
4
+ def check_feature_shape(name, data):
5
+ """Check if (non)-scalar feature matches with its data's dimensionality
6
+
7
+ Parameters
8
+ ----------
9
+ name: str
10
+ name of the feature
11
+ data: array-like
12
+ data whose dimensionality will be checked
13
+
14
+ Raises
15
+ ------
16
+ ValueError
17
+ If the data's shape does not match its scalar description
18
+ """
19
+ if len(data.shape) == 1 and not scalar_feature_exists(name):
20
+ raise ValueError(f"Feature '{name}' is not a scalar feature, but "
21
+ "a 1D array was given for `data`!")
22
+ elif len(data.shape) != 1 and scalar_feature_exists(name):
23
+ raise ValueError(f"Feature '{name}' is a scalar feature, but the "
24
+ "`data` array is not 1D!")
25
+
26
+
27
+ def feature_exists(name, scalar_only=False):
28
+ """Return True if `name` is a valid feature name
29
+
30
+ This function not only checks whether `name` is in
31
+ :const:`feature_names`, but also validates against
32
+ the machine learning scores `ml_score_???` (where
33
+ `?` can be a digit or a lower-case letter in the
34
+ English alphabet).
35
+
36
+ Parameters
37
+ ----------
38
+ name: str
39
+ name of a feature
40
+ scalar_only : bool
41
+ Specify whether the check should only search in scalar features
42
+
43
+ Returns
44
+ -------
45
+ valid: bool
46
+ True if name is a valid feature, False otherwise.
47
+
48
+ See Also
49
+ --------
50
+ scalar_feature_exists: Wraps `feature_exists` with `scalar_only=True`
51
+ """
52
+ valid = False
53
+ if name in feat_const.scalar_feature_names:
54
+ # scalar feature
55
+ valid = True
56
+ elif not scalar_only and name in feat_const.feature_names:
57
+ # non-scalar feature
58
+ valid = True
59
+ else:
60
+ # check whether we have an `ml_score_???` feature
61
+ valid_chars = "0123456789abcdefghijklmnopqrstuvwxyz"
62
+ if (name.startswith("ml_score_")
63
+ and len(name) == len("ml_score_???")
64
+ and name[-3] in valid_chars
65
+ and name[-2] in valid_chars
66
+ and name[-1] in valid_chars):
67
+ valid = True
68
+ return valid
69
+
70
+
71
+ def feature_register(name, label=None, is_scalar=True):
72
+ """Register a new feature for usage in dclab
73
+
74
+ Used by temporary features and plugin features to add new feature
75
+ names and labels to `dclab.definitions`.
76
+
77
+ Parameters
78
+ ----------
79
+ name: str
80
+ name of a feature
81
+ label: str, optional
82
+ feature label corresponding to the feature name. If set to None, then
83
+ a label is constructed for the feature name.
84
+ is_scalar: bool
85
+ Specify whether the feature of an event is a scalar (True)
86
+ or not (False)
87
+
88
+ Raises
89
+ ------
90
+ ValueError
91
+ If the feature already exists.
92
+ """
93
+ allowed_chars = "abcdefghijklmnopqrstuvwxyz_1234567890"
94
+ feat = "".join([f for f in name if f in allowed_chars])
95
+ if feat != name:
96
+ raise ValueError("`feature` must only contain lower-case characters, "
97
+ f"digits, and underscores; got '{name}'!")
98
+ if label is None:
99
+ label = f"User-defined feature {name}"
100
+ if feature_exists(name):
101
+ raise ValueError(f"Feature '{name}' already exists!")
102
+
103
+ # Populate the new feature in all dictionaries and lists
104
+ # (we don't need global here)
105
+ feat_const.feature_names.append(name)
106
+ feat_const.feature_labels.append(label)
107
+ feat_const.feature_name2label[name] = label
108
+ if is_scalar:
109
+ feat_const.scalar_feature_names.append(name)
110
+
111
+
112
+ def feature_deregister(name):
113
+ """Unregister a feature from dclab
114
+
115
+ Used by temporary features and plugin features to
116
+ remove the feature names and labels from `dclab.definitions`.
117
+
118
+ Parameters
119
+ ----------
120
+ name: str
121
+ name of a feature
122
+
123
+ Warnings
124
+ --------
125
+ This function should only be used internally, i.e., You should not use
126
+ this function. This function can break things.
127
+ """
128
+ label = get_feature_label(name)
129
+ feat_const.feature_names.remove(name)
130
+ feat_const.feature_labels.remove(label)
131
+ feat_const.feature_name2label.pop(name)
132
+ if name in feat_const.scalar_feature_names:
133
+ feat_const.scalar_feature_names.remove(name)
134
+
135
+
136
+ def get_feature_label(name, rtdc_ds=None, with_unit=True):
137
+ """Return the label corresponding to a feature name
138
+
139
+ This function not only checks :const:`feature_name2label`,
140
+ but also supports registered `ml_score_???` features.
141
+
142
+ Parameters
143
+ ----------
144
+ name: str
145
+ name of a feature
146
+ with_unit: bool
147
+ set to False to remove units in square brackets
148
+
149
+ Returns
150
+ -------
151
+ label: str
152
+ feature label corresponding to the feature name
153
+
154
+ Notes
155
+ -----
156
+ TODO: extract feature label from ancillary information when an rtdc_ds is
157
+ given.
158
+ """
159
+ # TODO: Is there another way of avoiding this circular import?
160
+ from ..rtdc_dataset.feat_anc_core.ancillary_feature import AncillaryFeature
161
+ assert feature_exists(name)
162
+ if name in feat_const.feature_name2label:
163
+ label = feat_const.feature_name2label[name]
164
+ else:
165
+ # First check whether an ancillary feature with that
166
+ # name exists.
167
+ for af in AncillaryFeature.features:
168
+ if af.feature_name == name:
169
+ labelid = af.data.outputs.index(name)
170
+ label = af.data.output_labels[labelid]
171
+ break
172
+ else:
173
+ # If that did not work, use a generic name.
174
+ label = "ML score {}".format(name[-3:].upper())
175
+ if not with_unit:
176
+ if label.endswith("]") and label.count("["):
177
+ label = label.rsplit("[", 1)[0].strip()
178
+ return label
179
+
180
+
181
+ def scalar_feature_exists(name):
182
+ """Convenience method wrapping `feature_exists(..., scalar_only=True)`"""
183
+ return feature_exists(name, scalar_only=True)
@@ -0,0 +1,252 @@
1
+ import copy
2
+
3
+ from .meta_parse import (
4
+ fbool, fint, fintlist, func_types, lcstr, f1dfloatduple, fboolorfloat
5
+ )
6
+
7
+ #: All configuration keywords editable by the user
8
+ CFG_ANALYSIS = {
9
+ # filtering parameters
10
+ "filtering": [
11
+ ["hierarchy parent", str, "Hierarchy parent of the dataset"],
12
+ ["remove invalid events", fbool, "Remove events with inf/nan values"],
13
+ ["enable filters", fbool, "Enable filtering"],
14
+ ["limit events", fint, "Upper limit for number of filtered events"],
15
+ ["polygon filters", fintlist, "Polygon filter indices"],
16
+ ],
17
+ # Addition user-defined data
18
+ "calculation": [
19
+ ["emodulus lut", str, "Look-up table identifier"],
20
+ ["emodulus medium", str, "Medium used (e.g. '0.49% MC-PBS')"],
21
+ ["emodulus temperature", float, "Chip temperature [°C]"],
22
+ ["emodulus viscosity", float, "Viscosity [Pa*s] if 'medium' unknown"],
23
+ ["emodulus viscosity model", str, "Viscosity model for known media"],
24
+ ["crosstalk fl21", float, "Fluorescence crosstalk, channel 2 to 1"],
25
+ ["crosstalk fl31", float, "Fluorescence crosstalk, channel 3 to 1"],
26
+ ["crosstalk fl12", float, "Fluorescence crosstalk, channel 1 to 2"],
27
+ ["crosstalk fl32", float, "Fluorescence crosstalk, channel 3 to 2"],
28
+ ["crosstalk fl13", float, "Fluorescence crosstalk, channel 1 to 3"],
29
+ ["crosstalk fl23", float, "Fluorescence crosstalk, channel 2 to 3"],
30
+ ]
31
+ }
32
+
33
+ #: All read-only configuration keywords for a measurement
34
+ CFG_METADATA = {
35
+ # All parameters related to the actual experiment
36
+ "experiment": [
37
+ ["date", str, "Date of measurement ('YYYY-MM-DD')"],
38
+ ["event count", fint, "Number of recorded events"],
39
+ ["run index", fint, "Index of measurement run"],
40
+ ["run identifier", str, "Unique measurement identifier"],
41
+ ["sample", str, "Measured sample or user-defined reference"],
42
+ ["time", str, "Start time of measurement ('HH:MM:SS[.S]')"],
43
+ ["timestamp", float, "Start of measurement in unix time [s]"],
44
+ ],
45
+ # All special keywords related to RT-FDC
46
+ # This section should not be present for regular RT-DC measurements.
47
+ "fluorescence": [
48
+ # The baseline offset was introduced in 0.33.0. It is added to
49
+ # the trace data to obtain the actual signal used for data
50
+ # processing (e.g. obtaining the fl1_max feature). This is more
51
+ # robust than adding the offset directly to the trace data, because
52
+ # of the possibility of integer overflows. Furthermore, DCKit can
53
+ # set this parameter without modifying the original trace data
54
+ # to correct/remove negative trace data
55
+ # (see https://github.com/DC-analysis/dclab/issues/101).
56
+ # Note that traces accessed from RTDCBase instances are never
57
+ # background-corrected!
58
+ ["baseline 1 offset", fint, "Baseline offset channel 1"],
59
+ ["baseline 2 offset", fint, "Baseline offset channel 2"],
60
+ ["baseline 3 offset", fint, "Baseline offset channel 3"],
61
+ ["bit depth", fint, "Trace bit depth"],
62
+ # If a fluorescence channel is used, a channel name *must* be
63
+ # present. If a channel is not used, the channel name *must not*
64
+ # be present. E.g. if only channels 1 and 2 are used, but there
65
+ # are three channels present, then `channel count` is two,
66
+ # `channels installed` is three, and `channel 3 name` is not set.
67
+ ["channel 1 name", str, "FL1 description"],
68
+ ["channel 2 name", str, "FL2 description"],
69
+ ["channel 3 name", str, "FL3 description"],
70
+ ["channel count", fint, "Number of active channels"],
71
+ ["channels installed", fint, "Number of available channels"],
72
+ # In contrast to `channel ? name`, the laser power *may*
73
+ # be present (but must be set to 0), if a laser line is not used.
74
+ ["laser 1 lambda", float, "Laser 1 wavelength [nm]"],
75
+ ["laser 1 power", float, "Laser 1 output power [%]"],
76
+ ["laser 2 lambda", float, "Laser 2 wavelength [nm]"],
77
+ ["laser 2 power", float, "Laser 2 output power [%]"],
78
+ ["laser 3 lambda", float, "Laser 3 wavelength [nm]"],
79
+ ["laser 3 power", float, "Laser 3 output power [%]"],
80
+ ["laser count", fint, "Number of active lasers"],
81
+ ["lasers installed", fint, "Number of available lasers"],
82
+ ["sample rate", fint, "Trace sample rate [Hz]"],
83
+ ["samples per event", fint, "Samples per event"],
84
+ ["signal max", float, "Upper voltage detection limit [V]"],
85
+ ["signal min", float, "Lower voltage detection limit [V]"],
86
+ ["trace median", fint, "Rolling median filter size for traces"],
87
+ ],
88
+ # All tdms-related parameters
89
+ "fmt_tdms": [
90
+ ["video frame offset", fint, "Missing events at beginning of video"],
91
+ ],
92
+ # All imaging-related keywords
93
+ "imaging": [
94
+ ["flash device", str, "Light source device type"], # e.g. green LED
95
+ ["flash duration", float, "Light source flash duration [µs]"],
96
+ ["frame rate", float, "Imaging frame rate [Hz]"],
97
+ ["pixel size", float, "Pixel size [µm]"],
98
+ ["roi position x", fint, "Image x coordinate on sensor [px]"],
99
+ ["roi position y", fint, "Image y coordinate on sensor [px]"],
100
+ ["roi size x", fint, "Image width [px]"],
101
+ ["roi size y", fint, "Image height [px]"],
102
+ ],
103
+ # All parameters for online contour extraction from the event images
104
+ "online_contour": [
105
+ # The option "bg empty" was introduced in dclab 0.34.0 and
106
+ # Shape-In 2.2.2.5.
107
+ # Shape-In writes to the "shapein-warning" log if there are
108
+ # frames with event images (non-empty frames) that had to be
109
+ # used for background correction.
110
+ ["bg empty", fbool, "Background correction from empty frames only"],
111
+ ["bin area min", fint, "Minium pixel area of binary image event"],
112
+ ["bin kernel", fint, "Disk size for binary closing of mask image"],
113
+ ["bin threshold", fint, "Threshold for mask from bg-corrected image"],
114
+ ["image blur", fint, "Odd sigma for Gaussian blur (21x21 kernel)"],
115
+ ["no absdiff", fbool, "Do not use OpenCV 'absdiff' for bg-correction"],
116
+ ],
117
+ # All online-filter-related keywords (box filters, soft limit, and
118
+ # polygons are handled in `meta_logic`).
119
+ # Note that "soft limit" means that the event is still included in
120
+ # the dataset, but is not counted for "target event count". On the
121
+ # other hand, "hard limit" means that only those events that are
122
+ # within that filter are written to the dataset.
123
+ "online_filter": [
124
+ # "target*" is only set if measurement is stopped automatically.
125
+ # "target*" is not necessarily reached (e.g. user aborted).
126
+ ["target duration", float, "Target measurement duration [min]"],
127
+ ["target event count", fint, "Target event count for online gating"],
128
+ ],
129
+ # Data processing pipeline
130
+ "pipeline": [
131
+ ["dcnum background", str, "Background ID"],
132
+ ["dcnum data", str, "Data ID"],
133
+ ["dcnum feature", str, "Feature extractor ID"],
134
+ ["dcnum gate", str, "Gating ID"],
135
+ ["dcnum generation", str, "Generation ID"],
136
+ # The hash is computed by joining the other pipeline identifiers with
137
+ # the "|" character in this order: generation, data, background,
138
+ # segmenter, feature, gate.
139
+ ["dcnum hash", str, "Hash"],
140
+ ["dcnum mapping", str, "Event mapping from original dataset"],
141
+ ["dcnum segmenter", str, "Segmenter ID"],
142
+ # The event yield the number of events the pipeline produced and
143
+ # helps identify files that were e.g. exported from original files.
144
+ ["dcnum yield", fint, "Event yield"],
145
+ ],
146
+ # All qpi-related keywords
147
+ "qpi": [
148
+ # experiment-related qpi metadata, see qpretrieve for details
149
+ ["wavelength", float, "Imaging wavelength [nm]"],
150
+ ["medium index", float, "Refractive index of medium"],
151
+ ["pixel size raw", float, "Hologram pixel size [µm]."],
152
+ # post-analysis-related qpi metadata
153
+ ["software version", str, "Software version(s)"],
154
+ # How background image was created 'experimental' or
155
+ # computation method e.g. 'sparsemed'
156
+ ["bg method", str, "Background computation method"],
157
+ # calculation of pha and amp from hologram
158
+ # FFT preprocessing
159
+ # padding: 0 means no padding
160
+ ["padding", fint, "Level of padding"],
161
+ ["subtract mean", fbool, "Subtract mean before processing"],
162
+ # pipeline_kws
163
+ ["filter name", str, "Fourier filter used"],
164
+ # qpretrieve defines the keyword argument `filter_size_interpretation`
165
+ # for determining the filter size in Fourier space. In DC, we
166
+ # need a well-defined value for the filter size. The most logical
167
+ # choice is to interpret the filter size as "frequency index", which
168
+ # is independent of the image shape and yields a good approximation
169
+ # of the actual resolution one can expect. The default value
170
+ # ("sideband distance") is a good choice for general QPI analysis,
171
+ # but there is no meaningful information one could extract from it
172
+ # by just looking at the number. Thus, the "filter size" that we
173
+ # see here corresponds to a filter size set in qpretrieve where
174
+ # `filter_size_interpretation="frequency index"`.
175
+ ["filter size", float, "Fourier filter size [1/pix]"],
176
+ ["scale to filter", fboolorfloat, "Scale QPI data to filter size"],
177
+ # x, y coordinates, don't set if you wish None to be the default
178
+ ["sideband freq", f1dfloatduple, "Sideband coordinates [1/pix]"],
179
+ ["invert phase", fbool, "Invert the phase data"],
180
+ # "pixel size proc" depends on `scale_to_filter`.
181
+ # If `scale_to_filter` is False, this is equal to "pixel size raw".
182
+ # If `scale_to_filter` is True or a float, this value will differ from
183
+ # "pixel size raw".
184
+ # RTDC "imaging:pixel size" equals "pixel size proc"
185
+ ["pixel size proc", float, "QPI pixel size [µm]."],
186
+ # postprocessing of phase and amplitude
187
+ ["amp fit offset", str, "Amplitude offset correction"],
188
+ ["amp fit profile", str, "Amplitude profile correction"],
189
+ ["pha fit offset", str, "Phase offset correction"],
190
+ ["pha fit profile", str, "Phase profile correction"],
191
+ # QPImage background correction mask information
192
+ ["amp border px", fint, "Width of border for amplitude [pix]"],
193
+ ["pha border px", fint, "Width of border for phase [pix]"],
194
+ # Forward compatible QPImage background correction for trivial
195
+ # masks e.g. "tblr". "tb" useful for RTDC channel.
196
+ ["amp border loc", str, "Border location specifier for amplitude"],
197
+ ["pha border loc", str, "Border location specifier for phase"],
198
+ # refocusing metadata
199
+ ["focus interval", f1dfloatduple, "Focus interval to search [µm]"],
200
+ ["focus metric", str, "Metric used to calculate focus"],
201
+ ["focus minimizer", str, "Minimizer used to calculate focus"],
202
+ ["focus kernel", str, "Propagation kernel"],
203
+ ["focus padding", fint, "Level of padding for refocus"],
204
+ ],
205
+ # All setup-related keywords, except imaging
206
+ "setup": [
207
+ ["channel width", float, "Width of microfluidic channel [µm]"],
208
+ ["chip identifier", lcstr, "Unique identifier of the chip used"],
209
+ ["chip region", lcstr, "Imaged chip region (channel or reservoir)"],
210
+ ["flow rate", float, "Flow rate in channel [µL/s]"],
211
+ ["flow rate sample", float, "Sample flow rate [µL/s]"],
212
+ ["flow rate sheath", float, "Sheath flow rate [µL/s]"],
213
+ ["identifier", str, "Unique setup identifier"],
214
+ # "medium" can have various values; it is used to calculate viscosity
215
+ ["medium", str, "Medium used"],
216
+ ["module composition", str, "Comma-separated list of modules used"],
217
+ ["software version", str, "Acquisition software with version"],
218
+ ["temperature", float, "Mean chip temperature [°C]"],
219
+ ],
220
+ }
221
+
222
+ # CFG convenience lists and dicts
223
+ _cfg = copy.deepcopy(CFG_METADATA)
224
+ _cfg.update(CFG_ANALYSIS)
225
+
226
+ #: dict with metadata description
227
+ config_descr = {}
228
+ for _key in _cfg:
229
+ config_descr[_key] = {}
230
+ for _subkey, __, _descr in _cfg[_key]:
231
+ config_descr[_key][_subkey] = _descr
232
+
233
+ #: dict of dicts containing functions to convert input data
234
+ config_funcs = {}
235
+ for _key in _cfg:
236
+ config_funcs[_key] = {}
237
+ for _subkey, _type, __ in _cfg[_key]:
238
+ config_funcs[_key][_subkey] = _type
239
+
240
+ #: dict with section as keys and config parameter names as values
241
+ config_keys = {}
242
+ for _key in _cfg:
243
+ config_keys[_key] = [it[0] for it in _cfg[_key]]
244
+
245
+ #: dict of dicts containing the type of section parameters
246
+ config_types = {}
247
+ for _key in _cfg:
248
+ config_types[_key] = {}
249
+ for _subkey, _type, __ in _cfg[_key]:
250
+ if _type in func_types:
251
+ _type = func_types[_type]
252
+ config_types[_key][_subkey] = _type