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,257 @@
1
+ """RT-DC hdf5 format"""
2
+ from __future__ import annotations
3
+
4
+ import warnings
5
+
6
+ import numbers
7
+ import numpy as np
8
+
9
+ from ... import definitions as dfn
10
+ from ...util import copy_if_needed
11
+
12
+ from . import feat_defect
13
+
14
+
15
+ class H5ContourEvent:
16
+ def __init__(self, h5group, length=None):
17
+ self._length = length
18
+ self.h5group = h5group
19
+ # for hashing in util.obj2bytes
20
+ self.identifier = (h5group.file.filename, h5group["0"].name)
21
+
22
+ def __getitem__(self, key):
23
+ if not isinstance(key, numbers.Integral):
24
+ # slicing!
25
+ indices = np.arange(len(self))[key]
26
+ output = []
27
+ # populate the output list
28
+ for evid in indices:
29
+ output.append(self.h5group[str(evid)][:])
30
+ return output
31
+ elif key < 0:
32
+ return self.__getitem__(key + len(self))
33
+ else:
34
+ return self.h5group[str(key)][:]
35
+
36
+ def __iter__(self):
37
+ for idx in range(len(self)):
38
+ yield self[idx]
39
+
40
+ def __len__(self):
41
+ if self._length is None:
42
+ # computing the length of an H5Group is slow
43
+ self._length = len(self.h5group)
44
+ return self._length
45
+
46
+ @property
47
+ def dtype(self):
48
+ return self.h5group["0"].dtype
49
+
50
+ @property
51
+ def shape(self):
52
+ return len(self), np.nan, 2
53
+
54
+
55
+ class H5Events:
56
+ def __init__(self, h5):
57
+ self.h5file = h5
58
+ # According to https://github.com/h5py/h5py/issues/1960, we always
59
+ # have to keep a reference to the HDF5 dataset, otherwise it will
60
+ # be garbage-collected immediately. In addition to caching the HDF5
61
+ # datasets, we cache the wrapping classes in the `self._cached_events`
62
+ # dictionary.
63
+ self._cached_events = {}
64
+ self._defective_features = {}
65
+ self._features_list = None
66
+
67
+ @property
68
+ def _features(self):
69
+ if self._features_list is None:
70
+ self._features_list = sorted(self.h5file["events"].keys())
71
+ # make sure that "trace" is not empty
72
+ if ("trace" in self._features
73
+ and len(self.h5file["events"]["trace"]) == 0):
74
+ self._features_list.remove("trace")
75
+ return self._features_list
76
+
77
+ def __contains__(self, key):
78
+ return key in self.keys()
79
+
80
+ def __getitem__(self, key):
81
+ if key not in self._cached_events:
82
+ # user-level checking is done in core.py
83
+ assert dfn.feature_exists(key), f"Feature '{key}' does not exist!"
84
+ data = self.h5file["events"][key]
85
+ if key == "contour":
86
+ length = self.h5file.attrs.get("experiment:event count")
87
+ fdata = H5ContourEvent(data, length=length)
88
+ elif key == "mask":
89
+ fdata = H5MaskEvent(data)
90
+ elif key == "trace":
91
+ fdata = H5TraceEvent(data)
92
+ elif data.ndim == 1:
93
+ fdata = H5ScalarEvent(data)
94
+ else:
95
+ # for features like "image", "image_bg" and other non-scalar
96
+ # ancillary features
97
+ fdata = data
98
+ self._cached_events[key] = fdata
99
+ return self._cached_events[key]
100
+
101
+ def __iter__(self):
102
+ # dict-like behavior
103
+ for key in self.keys():
104
+ yield key
105
+
106
+ def _is_defective_feature(self, feat):
107
+ """Whether the stored feature is defective"""
108
+ if feat not in self._defective_features:
109
+ defective = False
110
+ if (feat in feat_defect.DEFECTIVE_FEATURES
111
+ and feat in self._features):
112
+ # feature exists in the HDF5 file
113
+ # workaround machinery for sorting out defective features
114
+ defective = feat_defect.DEFECTIVE_FEATURES[feat](self.h5file)
115
+ self._defective_features[feat] = defective
116
+ return self._defective_features[feat]
117
+
118
+ def keys(self):
119
+ """Returns list of valid features
120
+
121
+ Checks for
122
+ - defective features: whether the data in the HDF5 file is invalid
123
+ - existing feature names: dynamic, depending on e.g. plugin features
124
+ """
125
+ features = []
126
+ for key in self._features:
127
+ # check for defective features
128
+ if dfn.feature_exists(key) and not self._is_defective_feature(key):
129
+ features.append(key)
130
+ return features
131
+
132
+
133
+ class H5MaskEvent:
134
+ """Cast uint8 masks to boolean"""
135
+
136
+ def __init__(self, h5dataset):
137
+ self.h5dataset = h5dataset
138
+ # identifier required because "mask" is used for computation
139
+ # of ancillary feature "contour".
140
+ self.identifier = (self.h5dataset.file.filename, self.h5dataset.name)
141
+ self.dtype = np.dtype(bool)
142
+
143
+ def __array__(self, dtype=np.bool_, copy=copy_if_needed, *args, **kwargs):
144
+ if dtype is not np.uint8:
145
+ warnings.warn("Please avoid calling the `__array__` method of the "
146
+ "`H5MaskEvent`. It may consume a lot of memory.",
147
+ UserWarning)
148
+ # One of the reasons why we implement __array__ is such that
149
+ # the data exporter knows this object is sliceable
150
+ # (see yield_filtered_array_stacks).
151
+ return self.h5dataset.__array__(dtype=dtype, *args, **kwargs)
152
+
153
+ def __getitem__(self, idx):
154
+ return np.asarray(self.h5dataset[idx], dtype=bool)
155
+
156
+ def __iter__(self):
157
+ for idx in range(len(self)):
158
+ yield self[idx]
159
+
160
+ def __len__(self):
161
+ return len(self.h5dataset)
162
+
163
+ @property
164
+ def attrs(self):
165
+ return self.h5dataset.attrs
166
+
167
+ @property
168
+ def shape(self):
169
+ return self.h5dataset.shape
170
+
171
+
172
+ class H5ScalarEvent(np.lib.mixins.NDArrayOperatorsMixin):
173
+ def __init__(self, h5ds):
174
+ """Lazy access to a scalar feature with cache"""
175
+ self.h5ds = h5ds
176
+ # for hashing in util.obj2bytes
177
+ self.identifier = (self.h5ds.file.filename, self.h5ds.name)
178
+ self._array = None
179
+ self.ndim = 1 # matplotlib might expect this from an array
180
+ # attrs
181
+ self._ufunc_attrs = dict(self.h5ds.attrs)
182
+
183
+ def __array__(self, dtype=None, copy=copy_if_needed, *args, **kwargs):
184
+ if self._array is None:
185
+ self._array = np.asarray(self.h5ds, *args, **kwargs)
186
+ return np.array(self._array, dtype=dtype, copy=copy)
187
+
188
+ def __getitem__(self, idx):
189
+ return self.__array__()[idx]
190
+
191
+ def __len__(self):
192
+ return len(self.h5ds)
193
+
194
+ def _fetch_ufunc_attr(self, uname, ufunc):
195
+ """A wrapper for calling functions on the scalar feature data
196
+
197
+ The ideas are:
198
+
199
+ 1. If there is a ufunc (max/mean/min) value stored in the dataset
200
+ attributes, then use this one.
201
+ 2. If the ufunc is computed, it is cached permanently in
202
+ self._ufunc_attrs
203
+ """
204
+ val = self._ufunc_attrs.get(uname, None)
205
+ if val is None:
206
+ val = ufunc(self.__array__())
207
+ self._ufunc_attrs[uname] = val
208
+ return val
209
+
210
+ def max(self, *args, **kwargs):
211
+ return self._fetch_ufunc_attr("max", np.nanmax)
212
+
213
+ def mean(self, *args, **kwargs):
214
+ return self._fetch_ufunc_attr("mean", np.nanmean)
215
+
216
+ def min(self, *args, **kwargs):
217
+ return self._fetch_ufunc_attr("min", np.nanmin)
218
+
219
+ @property
220
+ def dtype(self):
221
+ return self.h5ds.dtype
222
+
223
+ @property
224
+ def shape(self):
225
+ return self.h5ds.shape
226
+
227
+
228
+ class H5TraceEvent:
229
+ def __init__(self, h5group):
230
+ self.h5group = h5group
231
+ self._num_traces = None
232
+ self._shape = None
233
+
234
+ def __getitem__(self, idx):
235
+ return self.h5group[idx]
236
+
237
+ def __contains__(self, item):
238
+ return item in self.h5group
239
+
240
+ def __len__(self):
241
+ if self._num_traces is None:
242
+ self._num_traces = len(self.h5group)
243
+ return self._num_traces
244
+
245
+ def __iter__(self):
246
+ for key in sorted(self.h5group.keys()):
247
+ yield key
248
+
249
+ def keys(self):
250
+ return self.h5group.keys()
251
+
252
+ @property
253
+ def shape(self):
254
+ if self._shape is None:
255
+ atrace = list(self.h5group.keys())[0]
256
+ self._shape = tuple([len(self)] + list(self.h5group[atrace].shape))
257
+ return self._shape
@@ -0,0 +1,164 @@
1
+ """RT-DC hdf5 format"""
2
+ from __future__ import annotations
3
+
4
+ from ...external.packaging import parse as parse_version
5
+
6
+
7
+ def get_software_version_from_h5(h5):
8
+ software_version = h5.attrs.get("setup:software version", "")
9
+ if isinstance(software_version, bytes):
10
+ software_version = software_version.decode("utf-8")
11
+ return software_version
12
+
13
+
14
+ def is_defective_feature_aspect(h5):
15
+ """In Shape-In 2.0.6, there was a wrong variable cast"""
16
+ software_version = get_software_version_from_h5(h5)
17
+ return software_version in ["ShapeIn 2.0.6", "ShapeIn 2.0.7"]
18
+
19
+
20
+ def is_defective_feature_time(h5):
21
+ """Shape-In stores the "time" feature as a low-precision float32
22
+
23
+ This makes time resolution for large measurements useless,
24
+ because times are only resolved with four digits after the
25
+ decimal point. Here, we first check whether the "frame" feature
26
+ and the [imaging]:"frame rate" configuration are set. If so,
27
+ then we can compute "time" as an ancillary feature which will
28
+ be more accurate than its float32 version.
29
+ """
30
+ # This is a necessary requirement. If we cannot compute the
31
+ # ancillary feature, then we cannot ignore (even inaccurate) information.
32
+ has_ancil = "frame" in h5["events"] and h5.attrs.get("imaging:frame rate",
33
+ 0) != 0
34
+ if not has_ancil:
35
+ return False
36
+
37
+ # If we have a 32 bit dataset, then things are pretty clear.
38
+ is_32float = h5["events/time"].dtype.char[-1] == "f"
39
+ if is_32float:
40
+ return True
41
+
42
+ # Consider the software
43
+ software_version = get_software_version_from_h5(h5)
44
+
45
+ # Only Shape-In stores false data, so we can ignore other recording
46
+ # software.
47
+ is_shapein = software_version.count("ShapeIn")
48
+ if not is_shapein:
49
+ return False
50
+
51
+ # The tricky part: dclab might have analyzed the dataset recorded by
52
+ # Shape-In, e.g. in a compression step. Since dclab appends its version
53
+ # string to the software_version, we just have to parse that and make
54
+ # sure that it is above 0.47.6.
55
+ last_version = software_version.split("|")[-1].strip()
56
+ if last_version.startswith("dclab"):
57
+ dclab_version = last_version.split()[1]
58
+ if parse_version(dclab_version) < parse_version("0.47.6"):
59
+ # written with an older version of dclab
60
+ return True
61
+
62
+ # We covered all cases:
63
+ # - ancillary information are available
64
+ # - it's not a float32 dataset
65
+ # - we excluded all non-Shape-In recording software
66
+ # - it was not written with an older version of dclab
67
+ return False
68
+
69
+
70
+ def is_defective_feature_volume(h5):
71
+ """dclab computed volume wrong up until version 0.36.1"""
72
+ # first check if the scripted fix was applied
73
+ if "dclab_issue_141" in list(h5.get("logs", {}).keys()):
74
+ return False
75
+ # if that does not apply, check the software version
76
+ software_version = get_software_version_from_h5(h5)
77
+ if software_version:
78
+ last_version = software_version.split("|")[-1].strip()
79
+ if last_version.startswith("dclab"):
80
+ dclab_version = last_version.split()[1]
81
+ if parse_version(dclab_version) < parse_version("0.37.0"):
82
+ return True
83
+ return False
84
+
85
+
86
+ def is_defective_feature_inert_ratio(h5):
87
+ """For long channels, there was an integer overflow until 0.48.1
88
+
89
+ The problem here is that not only the channel length, but also
90
+ the length of the contour play a role. All point coordinates of
91
+ the contour are summed up and multiplied with one another which
92
+ leads to integer overflows when computing mu20.
93
+
94
+ Thus, this test is only a best guess, but still quite fast.
95
+
96
+ See also https://github.com/DC-analysis/dclab/issues/212
97
+ """
98
+ # determine whether the image width is larger than 500px
99
+ # If this file was written with dclab, then we always have the ROI size,
100
+ # so we don't have to check the actual image.
101
+ width_large = h5.attrs.get("imaging:roi size x", 0) > 500
102
+
103
+ if width_large:
104
+ # determine whether the software version was outdated
105
+ software_version = get_software_version_from_h5(h5)
106
+ if software_version:
107
+ version_pipeline = [v.strip() for v in software_version.split("|")]
108
+ last_version = version_pipeline[-1]
109
+ if last_version.startswith("dclab"):
110
+ dclab_version = last_version.split()[1]
111
+ # The fix was implemented in 0.48.2, but this method here
112
+ # was only implemented in 0.48.3, so we might have leaked
113
+ # old data into new files.
114
+ if parse_version(dclab_version) < parse_version("0.48.3"):
115
+ return True
116
+ return False
117
+
118
+
119
+ def is_defective_feature_inert_ratio_raw_cvx(h5):
120
+ """Additional check for `inert_ratio_raw` and `inert_ratio_cvx`
121
+
122
+ These features were computed with Shape-In and were very likely
123
+ computed correctly.
124
+
125
+ See https://github.com/DC-analysis/dclab/issues/224
126
+ """
127
+ if is_defective_feature_inert_ratio(h5):
128
+ # Possibly affected. Only return False if Shape-In check is negative
129
+ software_version = get_software_version_from_h5(h5)
130
+ version_pipeline = [v.strip() for v in software_version.split("|")]
131
+ first_version = version_pipeline[0]
132
+ if first_version.startswith("ShapeIn"):
133
+ si_version = first_version.split()[1]
134
+ elif "shapein-acquisition" in h5.get("logs", []):
135
+ # Later versions of Shape-In do not anymore write "ShapeIn" in the
136
+ # version string.
137
+ si_version = first_version
138
+ else:
139
+ # Some other software was used to record the data and dclab
140
+ # very likely stored the wrong inertia ratio.
141
+ return True
142
+
143
+ # We trust Shape-In >= 2.0.5
144
+ if parse_version(si_version) >= parse_version("2.0.5"):
145
+ return False
146
+
147
+ return True
148
+
149
+ return False
150
+
151
+
152
+ #: dictionary of defective features, defined by HDF5 attributes;
153
+ #: if a value matches the given HDF5 attribute, the feature is
154
+ #: considered defective
155
+ DEFECTIVE_FEATURES = {
156
+ # feature: [HDF5_attribute, matching_value]
157
+ "aspect": is_defective_feature_aspect,
158
+ "inert_ratio_cvx": is_defective_feature_inert_ratio_raw_cvx,
159
+ "inert_ratio_prnc": is_defective_feature_inert_ratio,
160
+ "inert_ratio_raw": is_defective_feature_inert_ratio_raw_cvx,
161
+ "tilt": is_defective_feature_inert_ratio,
162
+ "time": is_defective_feature_time,
163
+ "volume": is_defective_feature_volume,
164
+ }
@@ -0,0 +1,33 @@
1
+ class H5Logs:
2
+ def __init__(self, h5):
3
+ self.h5file = h5
4
+ self._cache_keys = None
5
+
6
+ def __getitem__(self, key):
7
+ if key in self.keys():
8
+ log = list(self.h5file["logs"][key])
9
+ if isinstance(log[0], bytes):
10
+ log = [li.decode("utf") for li in log]
11
+ else:
12
+ raise KeyError(
13
+ f"File {self.h5file.file.filename} does not have the log "
14
+ f"'{key}'. Available logs are {self.keys()}.")
15
+ return log
16
+
17
+ def __iter__(self):
18
+ # dict-like behavior
19
+ for key in self.keys():
20
+ yield key
21
+
22
+ def __len__(self):
23
+ return len(self.keys())
24
+
25
+ def keys(self):
26
+ if self._cache_keys is None:
27
+ names = []
28
+ if "logs" in self.h5file:
29
+ for key in self.h5file["logs"]:
30
+ if self.h5file["logs"][key].size:
31
+ names.append(key)
32
+ self._cache_keys = names
33
+ return self._cache_keys
@@ -0,0 +1,30 @@
1
+ class H5Tables:
2
+ def __init__(self, h5):
3
+ self.h5file = h5
4
+ self._cache_keys = None
5
+
6
+ def __getitem__(self, key):
7
+ if key in self.keys():
8
+ tab = self.h5file["tables"][key]
9
+ else:
10
+ raise KeyError(f"Table '{key}' not found or empty "
11
+ f"in {self.h5file.file.filename}!")
12
+ return tab
13
+
14
+ def __iter__(self):
15
+ # dict-like behavior
16
+ for key in self.keys():
17
+ yield key
18
+
19
+ def __len__(self):
20
+ return len(self.keys())
21
+
22
+ def keys(self):
23
+ if self._cache_keys is None:
24
+ names = []
25
+ if "tables" in self.h5file:
26
+ for key in self.h5file["tables"]:
27
+ if self.h5file["tables"][key].size:
28
+ names.append(key)
29
+ self._cache_keys = names
30
+ return self._cache_keys
@@ -0,0 +1,11 @@
1
+ # flake8: noqa: F401
2
+ from .base import RTDC_Hierarchy
3
+ from .events import (
4
+ ChildTrace, ChildTraceItem, ChildScalar, ChildContour, ChildNDArray,
5
+ ChildBase
6
+ )
7
+ from .hfilter import HierarchyFilter, HierarchyFilterError
8
+ from .mapper import (
9
+ map_indices_child2parent, map_indices_child2root,
10
+ map_indices_root2child, map_indices_parent2child
11
+ )