dclab 0.64.3__tar.gz → 0.66.0__tar.gz

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 (334) hide show
  1. {dclab-0.64.3 → dclab-0.66.0}/CHANGELOG +7 -0
  2. {dclab-0.64.3 → dclab-0.66.0}/PKG-INFO +1 -1
  3. {dclab-0.64.3 → dclab-0.66.0}/dclab/_version.py +2 -2
  4. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/core.py +3 -1
  5. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/export.py +6 -3
  6. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_basin.py +36 -16
  7. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/writer.py +26 -7
  8. {dclab-0.64.3 → dclab-0.66.0}/dclab.egg-info/PKG-INFO +1 -1
  9. {dclab-0.64.3 → dclab-0.66.0}/dclab.egg-info/SOURCES.txt +1 -0
  10. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_basins/index.rst +6 -0
  11. {dclab-0.64.3 → dclab-0.66.0}/scripts/requirements.txt +3 -1
  12. dclab-0.66.0/scripts/vid2dc.py +240 -0
  13. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_basin.py +28 -4
  14. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_writer.py +53 -0
  15. {dclab-0.64.3 → dclab-0.66.0}/.gitignore +0 -0
  16. {dclab-0.64.3 → dclab-0.66.0}/.readthedocs.yml +0 -0
  17. {dclab-0.64.3 → dclab-0.66.0}/LICENSE +0 -0
  18. {dclab-0.64.3 → dclab-0.66.0}/MANIFEST.in +0 -0
  19. {dclab-0.64.3 → dclab-0.66.0}/README.rst +0 -0
  20. {dclab-0.64.3 → dclab-0.66.0}/dclab/__init__.py +0 -0
  21. {dclab-0.64.3 → dclab-0.66.0}/dclab/cached.py +0 -0
  22. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/__init__.py +0 -0
  23. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/common.py +0 -0
  24. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_compress.py +0 -0
  25. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_condense.py +0 -0
  26. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_join.py +0 -0
  27. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_repack.py +0 -0
  28. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_split.py +0 -0
  29. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_tdms2rtdc.py +0 -0
  30. {dclab-0.64.3 → dclab-0.66.0}/dclab/cli/task_verify_dataset.py +0 -0
  31. {dclab-0.64.3 → dclab-0.66.0}/dclab/definitions/__init__.py +0 -0
  32. {dclab-0.64.3 → dclab-0.66.0}/dclab/definitions/feat_const.py +0 -0
  33. {dclab-0.64.3 → dclab-0.66.0}/dclab/definitions/feat_logic.py +0 -0
  34. {dclab-0.64.3 → dclab-0.66.0}/dclab/definitions/meta_const.py +0 -0
  35. {dclab-0.64.3 → dclab-0.66.0}/dclab/definitions/meta_logic.py +0 -0
  36. {dclab-0.64.3 → dclab-0.66.0}/dclab/definitions/meta_parse.py +0 -0
  37. {dclab-0.64.3 → dclab-0.66.0}/dclab/downsampling.pyx +0 -0
  38. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/__init__.py +0 -0
  39. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/packaging/LICENSE +0 -0
  40. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/packaging/LICENSE.APACHE +0 -0
  41. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/packaging/LICENSE.BSD +0 -0
  42. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/packaging/__init__.py +0 -0
  43. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/packaging/_structures.py +0 -0
  44. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/packaging/version.py +0 -0
  45. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/LICENSE +0 -0
  46. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/__init__.py +0 -0
  47. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/_find_contours.py +0 -0
  48. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/_find_contours_cy.pyx +0 -0
  49. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/_pnpoly.pyx +0 -0
  50. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/_shared/__init__.py +0 -0
  51. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/_shared/geometry.pxd +0 -0
  52. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/_shared/geometry.pyx +0 -0
  53. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/measure.py +0 -0
  54. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/skimage/pnpoly.py +0 -0
  55. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/statsmodels/LICENSE +0 -0
  56. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/statsmodels/__init__.py +0 -0
  57. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/statsmodels/nonparametric/__init__.py +0 -0
  58. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/statsmodels/nonparametric/_kernel_base.py +0 -0
  59. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/statsmodels/nonparametric/kernel_density.py +0 -0
  60. {dclab-0.64.3 → dclab-0.66.0}/dclab/external/statsmodels/nonparametric/kernels.py +0 -0
  61. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/__init__.py +0 -0
  62. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/bright.py +0 -0
  63. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/bright_bc.py +0 -0
  64. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/bright_perc.py +0 -0
  65. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/contour.py +0 -0
  66. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/__init__.py +0 -0
  67. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/load.py +0 -0
  68. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/lut_HE-2D-FEM-22.txt +0 -0
  69. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/lut_HE-3D-FEM-22.txt +0 -0
  70. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/lut_LE-2D-FEM-19.txt +0 -0
  71. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/pxcorr.py +0 -0
  72. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/scale_linear.py +0 -0
  73. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/emodulus/viscosity.py +0 -0
  74. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/fl_crosstalk.py +0 -0
  75. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/inert_ratio.py +0 -0
  76. {dclab-0.64.3 → dclab-0.66.0}/dclab/features/volume.py +0 -0
  77. {dclab-0.64.3 → dclab-0.66.0}/dclab/http_utils.py +0 -0
  78. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/__init__.py +0 -0
  79. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_HE-2D-FEM-22-area_um-deform.txt +0 -0
  80. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_HE-2D-FEM-22-volume-deform.txt +0 -0
  81. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_HE-3D-FEM-22-area_um-deform.txt +0 -0
  82. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_HE-3D-FEM-22-volume-deform.txt +0 -0
  83. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_LE-2D-FEM-19-area_um-deform.txt +0 -0
  84. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_LE-2D-FEM-19-volume-deform.txt +0 -0
  85. {dclab-0.64.3 → dclab-0.66.0}/dclab/isoelastics/iso_LE-2D-ana-18-area_um-deform.txt +0 -0
  86. {dclab-0.64.3 → dclab-0.66.0}/dclab/kde/__init__.py +0 -0
  87. {dclab-0.64.3 → dclab-0.66.0}/dclab/kde/base.py +0 -0
  88. {dclab-0.64.3 → dclab-0.66.0}/dclab/kde/contours.py +0 -0
  89. {dclab-0.64.3 → dclab-0.66.0}/dclab/kde/methods.py +0 -0
  90. {dclab-0.64.3 → dclab-0.66.0}/dclab/kde_contours.py +0 -0
  91. {dclab-0.64.3 → dclab-0.66.0}/dclab/kde_methods.py +0 -0
  92. {dclab-0.64.3 → dclab-0.66.0}/dclab/lme4/__init__.py +0 -0
  93. {dclab-0.64.3 → dclab-0.66.0}/dclab/lme4/lme4_template.R +0 -0
  94. {dclab-0.64.3 → dclab-0.66.0}/dclab/lme4/rsetup.py +0 -0
  95. {dclab-0.64.3 → dclab-0.66.0}/dclab/lme4/wrapr.py +0 -0
  96. {dclab-0.64.3 → dclab-0.66.0}/dclab/polygon_filter.py +0 -0
  97. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/__init__.py +0 -0
  98. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/check.py +0 -0
  99. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/config.py +0 -0
  100. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/copier.py +0 -0
  101. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/__init__.py +0 -0
  102. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/af_basic.py +0 -0
  103. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/af_emodulus.py +0 -0
  104. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/af_fl_max_ctc.py +0 -0
  105. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/af_image_contour.py +0 -0
  106. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/af_ml_class.py +0 -0
  107. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_core/ancillary_feature.py +0 -0
  108. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_ml/__init__.py +0 -0
  109. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_plugin/__init__.py +0 -0
  110. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_anc_plugin/plugin_feature.py +0 -0
  111. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/feat_temp.py +0 -0
  112. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/filter.py +0 -0
  113. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/__init__.py +0 -0
  114. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/access_token.py +0 -0
  115. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/api.py +0 -0
  116. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/base.py +0 -0
  117. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/basin.py +0 -0
  118. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/logs.py +0 -0
  119. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dcor/tables.py +0 -0
  120. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_dict.py +0 -0
  121. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/__init__.py +0 -0
  122. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/base.py +0 -0
  123. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/basin.py +0 -0
  124. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/events.py +0 -0
  125. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/feat_defect.py +0 -0
  126. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/logs.py +0 -0
  127. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hdf5/tables.py +0 -0
  128. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hierarchy/__init__.py +0 -0
  129. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hierarchy/base.py +0 -0
  130. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hierarchy/events.py +0 -0
  131. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hierarchy/hfilter.py +0 -0
  132. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_hierarchy/mapper.py +0 -0
  133. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_http.py +0 -0
  134. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_s3.py +0 -0
  135. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/__init__.py +0 -0
  136. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/event_contour.py +0 -0
  137. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/event_image.py +0 -0
  138. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/event_mask.py +0 -0
  139. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/event_trace.py +0 -0
  140. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/exc.py +0 -0
  141. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/fmt_tdms/naming.py +0 -0
  142. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/load.py +0 -0
  143. {dclab-0.64.3 → dclab-0.66.0}/dclab/rtdc_dataset/meta_table.py +0 -0
  144. {dclab-0.64.3 → dclab-0.66.0}/dclab/statistics.py +0 -0
  145. {dclab-0.64.3 → dclab-0.66.0}/dclab/util.py +0 -0
  146. {dclab-0.64.3 → dclab-0.66.0}/dclab/warn.py +0 -0
  147. {dclab-0.64.3 → dclab-0.66.0}/dclab.egg-info/dependency_links.txt +0 -0
  148. {dclab-0.64.3 → dclab-0.66.0}/dclab.egg-info/entry_points.txt +0 -0
  149. {dclab-0.64.3 → dclab-0.66.0}/dclab.egg-info/requires.txt +0 -0
  150. {dclab-0.64.3 → dclab-0.66.0}/dclab.egg-info/top_level.txt +0 -0
  151. {dclab-0.64.3 → dclab-0.66.0}/docs/.gitignore +0 -0
  152. {dclab-0.64.3 → dclab-0.66.0}/docs/README.md +0 -0
  153. {dclab-0.64.3 → dclab-0.66.0}/docs/conf.py +0 -0
  154. {dclab-0.64.3 → dclab-0.66.0}/docs/data/example.poly +0 -0
  155. {dclab-0.64.3 → dclab-0.66.0}/docs/data/example.rtdc +0 -0
  156. {dclab-0.64.3 → dclab-0.66.0}/docs/data/example_plugin.py +0 -0
  157. {dclab-0.64.3 → dclab-0.66.0}/docs/data/example_plugin_metadata.py +0 -0
  158. {dclab-0.64.3 → dclab-0.66.0}/docs/data/example_traces.rtdc +0 -0
  159. {dclab-0.64.3 → dclab-0.66.0}/docs/data/example_video.rtdc +0 -0
  160. {dclab-0.64.3 → dclab-0.66.0}/docs/dclab.bib +0 -0
  161. {dclab-0.64.3 → dclab-0.66.0}/docs/extensions/dclab_defs.py +0 -0
  162. {dclab-0.64.3 → dclab-0.66.0}/docs/extensions/fancy_include.py +0 -0
  163. {dclab-0.64.3 → dclab-0.66.0}/docs/extensions/github_changelog.py +0 -0
  164. {dclab-0.64.3 → dclab-0.66.0}/docs/extensions/simple_argparse.py +0 -0
  165. {dclab-0.64.3 → dclab-0.66.0}/docs/figures/DCOR_API_Token_website.png +0 -0
  166. {dclab-0.64.3 → dclab-0.66.0}/docs/index.rst +0 -0
  167. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/dc_logo.png +0 -0
  168. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/dc_logo.svg +0 -0
  169. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/dclab.png +0 -0
  170. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/dclab.svg +0 -0
  171. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/dclab_large_white.png +0 -0
  172. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/dclab_large_white.svg +0 -0
  173. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/favicon.ico +0 -0
  174. {dclab-0.64.3 → dclab-0.66.0}/docs/logo/favicon.svg +0 -0
  175. {dclab-0.64.3 → dclab-0.66.0}/docs/requirements.txt +0 -0
  176. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_advanced_usage.rst +0 -0
  177. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_basins/basin_example_workflows.svg +0 -0
  178. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_dc_io.rst +0 -0
  179. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_dc_usage.rst +0 -0
  180. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_dcor.rst +0 -0
  181. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_emodulus/.gitignore +0 -0
  182. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_emodulus/emodulus_20um_HE-2D-FEM-22.png +0 -0
  183. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_emodulus/emodulus_20um_HE-3D-FEM-22.png +0 -0
  184. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_emodulus/emodulus_20um_LE-2D-FEM-19.png +0 -0
  185. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_emodulus/plot_emodulus_lut.py +0 -0
  186. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_emodulus/requirements.txt +0 -0
  187. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_viscosity/LICENSE +0 -0
  188. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_viscosity/buyukurganci_22_fig3a.jpg +0 -0
  189. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/figures_viscosity/buyukurganci_22_fig3a.pdf +0 -0
  190. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_emodulus/index.rst +0 -0
  191. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_feat_plugin.rst +0 -0
  192. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_feat_temp.rst +0 -0
  193. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_fluorescence.rst +0 -0
  194. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_lme4.rst +0 -0
  195. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_notation.rst +0 -0
  196. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_s3.rst +0 -0
  197. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_av_scatter.rst +0 -0
  198. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_changelog.rst +0 -0
  199. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_cli.rst +0 -0
  200. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_code_reference.rst +0 -0
  201. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_examples.rst +0 -0
  202. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_getting_started.rst +0 -0
  203. {dclab-0.64.3 → dclab-0.66.0}/docs/sec_z_bib.rst +0 -0
  204. {dclab-0.64.3 → dclab-0.66.0}/examples/emodulus_dcor.jpg +0 -0
  205. {dclab-0.64.3 → dclab-0.66.0}/examples/emodulus_dcor.py +0 -0
  206. {dclab-0.64.3 → dclab-0.66.0}/examples/generate_example_images.py +0 -0
  207. {dclab-0.64.3 → dclab-0.66.0}/examples/isoelastics.jpg +0 -0
  208. {dclab-0.64.3 → dclab-0.66.0}/examples/isoelastics.py +0 -0
  209. {dclab-0.64.3 → dclab-0.66.0}/examples/isoelastics_custom.jpg +0 -0
  210. {dclab-0.64.3 → dclab-0.66.0}/examples/isoelastics_custom.py +0 -0
  211. {dclab-0.64.3 → dclab-0.66.0}/examples/lme4_glmer_diff.py +0 -0
  212. {dclab-0.64.3 → dclab-0.66.0}/examples/lme4_lmer.jpg +0 -0
  213. {dclab-0.64.3 → dclab-0.66.0}/examples/lme4_lmer.py +0 -0
  214. {dclab-0.64.3 → dclab-0.66.0}/examples/overview_plot.jpg +0 -0
  215. {dclab-0.64.3 → dclab-0.66.0}/examples/overview_plot.py +0 -0
  216. {dclab-0.64.3 → dclab-0.66.0}/examples/plugin_example.py +0 -0
  217. {dclab-0.64.3 → dclab-0.66.0}/examples/plugin_usage.jpg +0 -0
  218. {dclab-0.64.3 → dclab-0.66.0}/examples/plugin_usage.py +0 -0
  219. {dclab-0.64.3 → dclab-0.66.0}/examples/viscosity_models.jpg +0 -0
  220. {dclab-0.64.3 → dclab-0.66.0}/examples/viscosity_models.py +0 -0
  221. {dclab-0.64.3 → dclab-0.66.0}/pyproject.toml +0 -0
  222. {dclab-0.64.3 → dclab-0.66.0}/scripts/.gitignore +0 -0
  223. {dclab-0.64.3 → dclab-0.66.0}/scripts/README.md +0 -0
  224. {dclab-0.64.3 → dclab-0.66.0}/scripts/fem2iso_volume.py +0 -0
  225. {dclab-0.64.3 → dclab-0.66.0}/scripts/fem2lutiso_std.py +0 -0
  226. {dclab-0.64.3 → dclab-0.66.0}/scripts/fem2rtdc.py +0 -0
  227. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/__init__.py +0 -0
  228. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/LUT_analytical_linear-elastic_2Daxis.txt +0 -0
  229. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/README.md +0 -0
  230. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/__init__.py +0 -0
  231. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/common.py +0 -0
  232. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/he_2d_fem_22.py +0 -0
  233. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/he_3d_fem_22.py +0 -0
  234. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/hooks/le_2d_fem_19.py +0 -0
  235. {dclab-0.64.3 → dclab-0.66.0}/scripts/lut_recipes/lut_processor.py +0 -0
  236. {dclab-0.64.3 → dclab-0.66.0}/scripts/pixelation_correction.py +0 -0
  237. {dclab-0.64.3 → dclab-0.66.0}/scripts/pixelation_correction_2020.png +0 -0
  238. {dclab-0.64.3 → dclab-0.66.0}/scripts/pixelation_correction_2022.png +0 -0
  239. {dclab-0.64.3 → dclab-0.66.0}/setup.cfg +0 -0
  240. {dclab-0.64.3 → dclab-0.66.0}/setup.py +0 -0
  241. {dclab-0.64.3 → dclab-0.66.0}/tests/README.md +0 -0
  242. {dclab-0.64.3 → dclab-0.66.0}/tests/conftest.py +0 -0
  243. {dclab-0.64.3 → dclab-0.66.0}/tests/data/README.md +0 -0
  244. {dclab-0.64.3 → dclab-0.66.0}/tests/data/example_access_token.dcor-access +0 -0
  245. {dclab-0.64.3 → dclab-0.66.0}/tests/data/example_isoelastics.txt +0 -0
  246. {dclab-0.64.3 → dclab-0.66.0}/tests/data/feat_anc_plugin_creative.py +0 -0
  247. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_fl-no-contour_2019.zip +0 -0
  248. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_fl_2017.zip +0 -0
  249. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_fl_2018.zip +0 -0
  250. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_fl_wide-channel_2023.zip +0 -0
  251. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_image-bg_2020.zip +0 -0
  252. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_image-mask-blood_2021.zip +0 -0
  253. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_mask-contour_2018.zip +0 -0
  254. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_polygon_gate_2021.zip +0 -0
  255. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_raw-cytoshot-exported.zip +0 -0
  256. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_segfault-compound_2023.zip +0 -0
  257. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-hdf5_wide-channel_2023.zip +0 -0
  258. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_2fl-no-image_2017.zip +0 -0
  259. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_fl-image-bright_2017.zip +0 -0
  260. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_fl-image-large-fov_2017.zip +0 -0
  261. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_fl-image_2016.zip +0 -0
  262. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_fl_2015.zip +0 -0
  263. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_minimal_2016.zip +0 -0
  264. {dclab-0.64.3 → dclab-0.66.0}/tests/data/fmt-tdms_shapein-2.0.1-no-image_2017.zip +0 -0
  265. {dclab-0.64.3 → dclab-0.66.0}/tests/helper_methods.py +0 -0
  266. {dclab-0.64.3 → dclab-0.66.0}/tests/requirements.txt +0 -0
  267. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cache.py +0 -0
  268. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli.py +0 -0
  269. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli_argparse.py +0 -0
  270. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli_compress.py +0 -0
  271. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli_condense.py +0 -0
  272. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli_join.py +0 -0
  273. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli_repack.py +0 -0
  274. {dclab-0.64.3 → dclab-0.66.0}/tests/test_cli_split.py +0 -0
  275. {dclab-0.64.3 → dclab-0.66.0}/tests/test_config_value_mapping.py +0 -0
  276. {dclab-0.64.3 → dclab-0.66.0}/tests/test_dfn_feat.py +0 -0
  277. {dclab-0.64.3 → dclab-0.66.0}/tests/test_dfn_meta.py +0 -0
  278. {dclab-0.64.3 → dclab-0.66.0}/tests/test_downsampling.py +0 -0
  279. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_bright.py +0 -0
  280. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_bright_bc.py +0 -0
  281. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_bright_perc.py +0 -0
  282. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_contour.py +0 -0
  283. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_emodulus.py +0 -0
  284. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_emodulus_viscosity.py +0 -0
  285. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_fl_crosstalk.py +0 -0
  286. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_inert_ratio.py +0 -0
  287. {dclab-0.64.3 → dclab-0.66.0}/tests/test_feat_volume.py +0 -0
  288. {dclab-0.64.3 → dclab-0.66.0}/tests/test_http_utils.py +0 -0
  289. {dclab-0.64.3 → dclab-0.66.0}/tests/test_isoelastics.py +0 -0
  290. {dclab-0.64.3 → dclab-0.66.0}/tests/test_kde.py +0 -0
  291. {dclab-0.64.3 → dclab-0.66.0}/tests/test_kde_contours.py +0 -0
  292. {dclab-0.64.3 → dclab-0.66.0}/tests/test_kde_deprecations.py +0 -0
  293. {dclab-0.64.3 → dclab-0.66.0}/tests/test_kde_methods.py +0 -0
  294. {dclab-0.64.3 → dclab-0.66.0}/tests/test_lme4.py +0 -0
  295. {dclab-0.64.3 → dclab-0.66.0}/tests/test_lut_he_2d_fem_22.py +0 -0
  296. {dclab-0.64.3 → dclab-0.66.0}/tests/test_lut_he_3d_fem_22.py +0 -0
  297. {dclab-0.64.3 → dclab-0.66.0}/tests/test_polygon_contains.py +0 -0
  298. {dclab-0.64.3 → dclab-0.66.0}/tests/test_polygon_filter.py +0 -0
  299. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_check_dataset.py +0 -0
  300. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_config.py +0 -0
  301. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_copier.py +0 -0
  302. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_core_feat.py +0 -0
  303. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_downsampling.py +0 -0
  304. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_export.py +0 -0
  305. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_export_avi.py +0 -0
  306. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_export_fcs.py +0 -0
  307. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_export_hdf5.py +0 -0
  308. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_export_tsv.py +0 -0
  309. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_anc_core.py +0 -0
  310. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_anc_ml.py +0 -0
  311. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_anc_plugin.py +0 -0
  312. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_basin_mapped.py +0 -0
  313. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_basin_perishable.py +0 -0
  314. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_feat_temp.py +0 -0
  315. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_filter.py +0 -0
  316. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_dcor.py +0 -0
  317. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_dcor_access_token.py +0 -0
  318. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_dcor_basin.py +0 -0
  319. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_dcor_private.py +0 -0
  320. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_dict.py +0 -0
  321. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_hdf5.py +0 -0
  322. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_hdf5_basins.py +0 -0
  323. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_hdf5_basins_internal.py +0 -0
  324. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_hierarchy.py +0 -0
  325. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_http.py +0 -0
  326. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_http_basin.py +0 -0
  327. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_s3.py +0 -0
  328. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_s3_basin.py +0 -0
  329. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_fmt_tdms.py +0 -0
  330. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_hash.py +0 -0
  331. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_kde.py +0 -0
  332. {dclab-0.64.3 → dclab-0.66.0}/tests/test_rtdc_limit_events.py +0 -0
  333. {dclab-0.64.3 → dclab-0.66.0}/tests/test_statistics.py +0 -0
  334. {dclab-0.64.3 → dclab-0.66.0}/tests/test_util.py +0 -0
@@ -1,3 +1,10 @@
1
+ 0.66.0
2
+ - feat: introduce optional identifiers for basins
3
+ - ref: rename `measurement_identifier` to `referrer_identifier`
4
+ in the `feat_basin` context to clarify which dataset it belongs to
5
+ 0.65.0
6
+ - scripts: add `vid2dc.py` for converting videos to raw .rtdc files
7
+ - enh: run identifier splits use "_" upon export and have increased length
1
8
  0.64.3
2
9
  - ci: use GitHub windows-latest runner for building wheel
3
10
  0.64.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dclab
3
- Version: 0.64.3
3
+ Version: 0.66.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>
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.64.3'
21
- __version_tuple__ = version_tuple = (0, 64, 3)
20
+ __version__ = version = '0.66.0'
21
+ __version_tuple__ = version_tuple = (0, 66, 0)
@@ -741,7 +741,9 @@ class RTDCBase(abc.ABC):
741
741
  # need the referring dataset.
742
742
  "mapping_referrer": self,
743
743
  # Make sure the measurement identifier is checked.
744
- "measurement_identifier": self.get_measurement_identifier(),
744
+ "referrer_identifier": self.get_measurement_identifier(),
745
+ # Make sure the basin identifier is checked.
746
+ "basin_identifier": bdict.get("identifier"),
745
747
  # allow to ignore basins
746
748
  "ignored_basins": bd_keys,
747
749
  # basin key
@@ -334,8 +334,8 @@ class Export(object):
334
334
  # Define a new measurement identifier, so that we are not running
335
335
  # into any problems with basins being defined for filtered data.
336
336
  ds_run_id = ds.get_measurement_identifier()
337
- random_ap = str(uuid.uuid4())[:4]
338
- meta["experiment"]["run identifier"] = f"{ds_run_id}-{random_ap}"
337
+ random_ap = f"dclab-{str(uuid.uuid4())[:7]}"
338
+ meta["experiment"]["run identifier"] = f"{ds_run_id}_{random_ap}"
339
339
 
340
340
  if filtered:
341
341
  filter_arr = ds.filter.all
@@ -438,7 +438,6 @@ class Export(object):
438
438
  if progress_callback:
439
439
  progress_callback(1 - 1 / (len(features) or 1),
440
440
  "writing basins")
441
-
442
441
  # We have to store basins. There are three options:
443
442
  # - filtering disabled: just copy basins
444
443
  # - filtering enabled
@@ -450,6 +449,8 @@ class Export(object):
450
449
  basin_list = [bn.as_dict() for bn in ds.basins]
451
450
  # In addition to the upstream basins, also store a reference
452
451
  # to the original file from which the export was done.
452
+ # Get the identifier of the current dataset for the new basins.
453
+ basin_id = ds.get_measurement_identifier()
453
454
  if ds.format in get_basin_classes():
454
455
  # The dataset has a format that matches a basin format
455
456
  # directly.
@@ -464,6 +465,7 @@ class Export(object):
464
465
  "basin_format": ds.format,
465
466
  "basin_locs": basin_locs,
466
467
  "basin_descr": f"Exported with dclab {version}",
468
+ "basin_id": basin_id,
467
469
  })
468
470
  elif (ds.format == "hierarchy"
469
471
  and ds.get_root_parent().format in get_basin_classes()):
@@ -497,6 +499,7 @@ class Export(object):
497
499
  child=ds,
498
500
  child_indices=np.arange(len(ds))
499
501
  ),
502
+ "basin_id": basin_id,
500
503
  })
501
504
 
502
505
  for bn_dict in basin_list:
@@ -176,7 +176,8 @@ class Basin(abc.ABC):
176
176
  name: str = None,
177
177
  description: str = None,
178
178
  features: List[str] = None,
179
- measurement_identifier: str = None,
179
+ referrer_identifier: str = None,
180
+ basin_identifier: str = None,
180
181
  mapping: Literal["same",
181
182
  "basinmap0",
182
183
  "basinmap1",
@@ -208,10 +209,18 @@ class Basin(abc.ABC):
208
209
  features: list of str
209
210
  List of features this basin provides; This list is enforced,
210
211
  even if the basin actually contains more features.
211
- measurement_identifier: str
212
+ referrer_identifier: str
212
213
  A measurement identifier against which to check the basin.
214
+ If the basin mapping is "same", then this must match the
215
+ identifier of the basin exactly, otherwise it must start
216
+ with the basin identifier (e.g. "basin-id_referrer-sub-id").
213
217
  If this is set to None (default), there is no certainty
214
218
  that the downstream dataset is from the same measurement.
219
+ basin_identifier: str
220
+ A measurement identifier that must match the basin exactly.
221
+ In contrast to `referrer_identifier`, the basin identifier is
222
+ the identifier of the basin file. If `basin_identifier` is
223
+ specified, the identifier of the basin must be identical to it.
215
224
  mapping: str
216
225
  Which type of mapping to use. This can be either "same"
217
226
  when the event list of the basin is identical to that
@@ -261,8 +270,9 @@ class Basin(abc.ABC):
261
270
  # features this basin provides
262
271
  self._features = features
263
272
  #: measurement identifier of the referencing dataset
264
- self.measurement_identifier = measurement_identifier
265
- self._measurement_identifier_verified = False
273
+ self.referrer_identifier = referrer_identifier
274
+ self.basin_identifier = basin_identifier or None
275
+ self._identifiers_verification = None
266
276
  #: ignored basins
267
277
  self.ignored_basins = ignored_basins or []
268
278
  #: additional keyword arguments passed to the basin
@@ -304,13 +314,13 @@ class Basin(abc.ABC):
304
314
 
305
315
  return f"<{self.__class__.__name__} ({opt_str}) at {hex(id(self))}>"
306
316
 
307
- def _assert_measurement_identifier(self):
317
+ def _assert_referrer_identifier(self):
308
318
  """Make sure the basin matches the measurement identifier
309
319
  """
310
320
  if not self.verify_basin(run_identifier=True):
311
321
  raise KeyError(f"Measurement identifier of basin {self.ds} "
312
322
  f"({self.get_measurement_identifier()}) does "
313
- f"not match {self.measurement_identifier}!")
323
+ f"not match {self.referrer_identifier}!")
314
324
 
315
325
  @property
316
326
  def basinmap(self):
@@ -410,7 +420,7 @@ class Basin(abc.ABC):
410
420
 
411
421
  def get_feature_data(self, feat):
412
422
  """Return an object representing feature data of the basin"""
413
- self._assert_measurement_identifier()
423
+ self._assert_referrer_identifier()
414
424
  return self.ds[feat]
415
425
 
416
426
  def get_measurement_identifier(self):
@@ -455,20 +465,30 @@ class Basin(abc.ABC):
455
465
  # Only check for run identifier if requested and if the availability
456
466
  # check did not fail.
457
467
  if run_identifier and check_avail:
458
- if not self._measurement_identifier_verified:
459
- if self.measurement_identifier is None:
468
+ if self._identifiers_verification is None:
469
+ # This is the measurement identifier of the basin.
470
+ basin_identifier = self.get_measurement_identifier()
471
+
472
+ # Perform a sanity check for the basin identifier.
473
+ if (self.basin_identifier
474
+ and self.basin_identifier != basin_identifier):
475
+ # We should not proceed any further with this basin.
476
+ self._identifiers_verification = False
477
+ warnings.warn(
478
+ f"Basin identifier mismatch for {self}. Expected "
479
+ f"'{self.basin_identifier}', got '{basin_identifier}'")
480
+
481
+ if self.referrer_identifier is None:
460
482
  # No measurement identifier was presented by the
461
483
  # referencing dataset. We are in the dark.
462
484
  # Don't perform any checks.
463
- self._measurement_identifier_verified = True
485
+ self._identifiers_verification = True
464
486
  else:
465
- # This is the measurement identifier of the basin.
466
- basin_identifier = self.get_measurement_identifier()
467
487
  if basin_identifier is None:
468
488
  # Again, we are in the dark, because the basin dataset
469
489
  # does not have an identifier. This is an undesirable
470
490
  # situation, but there is nothing we can do about it.
471
- self._measurement_identifier_verified = True
491
+ self._identifiers_verification = True
472
492
  else:
473
493
  if self.mapping == "same":
474
494
  # When we have identical mapping, then the
@@ -479,10 +499,10 @@ class Basin(abc.ABC):
479
499
  # data), then the measurement identifier has to
480
500
  # partially match.
481
501
  verifier = str.startswith
482
- self._measurement_identifier_verified = verifier(
483
- self.measurement_identifier, basin_identifier)
502
+ self._identifiers_verification = verifier(
503
+ self.referrer_identifier, basin_identifier)
484
504
 
485
- check_rid = self._measurement_identifier_verified
505
+ check_rid = self._identifiers_verification
486
506
  else:
487
507
  check_rid = True
488
508
 
@@ -207,6 +207,7 @@ class RTDCWriter:
207
207
  basin_descr: str | None = None,
208
208
  basin_feats: List[str] = None,
209
209
  basin_map: np.ndarray | Tuple[str, np.ndarray] = None,
210
+ basin_id: str = None,
210
211
  internal_data: Dict | h5py.Group = None,
211
212
  verify: bool = True,
212
213
  perishable: bool = False,
@@ -243,6 +244,12 @@ class RTDCWriter:
243
244
  a case, you may specify a tuple `(feature_name, mapping_array)`
244
245
  where `feature_name` is the explicit mapping name, e.g.
245
246
  `"basinmap3"`.
247
+ basin_id: str
248
+ Identifier of the basin. This is the string returned by
249
+ :meth:`.RTDCBase.get_measurement_identifier`. This is
250
+ a unique string that identifies the data within a basin.
251
+ If not specified and `verify=True`, this value is automatically
252
+ taken from the basin file.
246
253
  internal_data: dict or instance of h5py.Group
247
254
  A dictionary or an `h5py.Group` containing the basin data.
248
255
  The data are copied to the "basin_events" group, if
@@ -310,19 +317,30 @@ class RTDCWriter:
310
317
  # We have to import this here to avoid circular imports
311
318
  from .load import new_dataset
312
319
  # Make sure the basin can be opened by dclab, verify its ID
313
- cur_id = self.h5file.attrs.get("experiment:run identifier")
320
+ ref_id = self.h5file.attrs.get("experiment:run identifier")
314
321
  for loc in basin_locs:
315
322
  with new_dataset(loc) as ds:
316
323
  # We can open the file, which is great.
317
- if cur_id:
318
- # Compare the IDs.
319
- ds_id = ds.get_measurement_identifier()
320
- if not (ds_id == cur_id
324
+ # Compare the IDs.
325
+ bn_id = ds.get_measurement_identifier()
326
+ # Check whether `basin_id` matches the actual basin
327
+ if basin_id:
328
+ if basin_id != bn_id:
329
+ raise ValueError(
330
+ f"Measurement identifier mismatch for "
331
+ f"{loc}: got {bn_id}, expected {basin_id=})!")
332
+ else:
333
+ # If `basin_id` was not specified, set it here for
334
+ # user convenience.
335
+ basin_id = bn_id or None
336
+ # Check whether the referrer ID matches the basin ID.
337
+ if ref_id:
338
+ if not (bn_id == ref_id
321
339
  or (basin_map is not None
322
- and cur_id.startswith(ds_id))):
340
+ and ref_id.startswith(bn_id))):
323
341
  raise ValueError(
324
342
  f"Measurement identifier mismatch between "
325
- f"{self.path} ({cur_id}) and {loc} ({ds_id})!")
343
+ f"{self.path} ({ref_id}) and {loc} ({bn_id})!")
326
344
  if basin_feats:
327
345
  for feat in basin_feats:
328
346
  if not dfn.feature_exists(feat):
@@ -389,6 +407,7 @@ class RTDCWriter:
389
407
  "features": None if basin_feats is None else sorted(basin_feats),
390
408
  "mapping": basin_map_name,
391
409
  "perishable": perishable,
410
+ "identifier": basin_id,
392
411
  }
393
412
  if basin_type == "file":
394
413
  flocs = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dclab
3
- Version: 0.64.3
3
+ Version: 0.66.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>
@@ -224,6 +224,7 @@ scripts/pixelation_correction.py
224
224
  scripts/pixelation_correction_2020.png
225
225
  scripts/pixelation_correction_2022.png
226
226
  scripts/requirements.txt
227
+ scripts/vid2dc.py
227
228
  scripts/lut_recipes/__init__.py
228
229
  scripts/lut_recipes/lut_processor.py
229
230
  scripts/lut_recipes/hooks/LUT_analytical_linear-elastic_2Daxis.txt
@@ -409,6 +409,7 @@ the json data looks like this:
409
409
  "type": "file",
410
410
  "features": null,
411
411
  "mapping": "basinmap0",
412
+ "identifier": "1231ae-31f23-342-232-42b1c",
412
413
  "paths": [
413
414
  "/absolute/path/to/input.rtdc",
414
415
  "input.rtdc"
@@ -427,6 +428,11 @@ are a few things to notice:
427
428
  ``/events/basinmap0`` in the output file. Note that the fact that this mapping
428
429
  information is stored *as a feature* means that it is also properly
429
430
  gated when you define basins iteratively.
431
+ - The *identifier* is a string that matches the identifier of the dataset.
432
+ When creating basins without a "same" mapping (as in this case), then the
433
+ referrer will obtain an identifier that starts with this identifier, but
434
+ contains additional text. This means identifiers are effectively cryptic
435
+ data analysis trackers.
430
436
  - There are two *paths* defined, an absolute path (from the root of the file
431
437
  system) and a relative path (relative to the directory of the output file).
432
438
  This relative path makes it possible to copy-paste these two files *together* to
@@ -1,5 +1,7 @@
1
- dclab>=0.23.0
1
+ click
2
+ dclab[tdms]>=0.23.0
2
3
  h5py
4
+ imageio[pyav]
3
5
  lmfit
4
6
  numpy
5
7
  matplotlib
@@ -0,0 +1,240 @@
1
+ """vid2dc
2
+
3
+ Convert video files to .rtdc files. This script generates a valid .rtdc
4
+ file from a video file (e.g. an .avi file). This script does not perform
5
+ segmentation and feature extraction, a feature that is available via the
6
+ ChipStream package (https://github.com/DC-analysis/ChipStream).
7
+
8
+ Prerequisites:
9
+
10
+ pip install dclab[tdms] imageio[pyav] click
11
+
12
+ Author: Paul Müller
13
+ License: GPLv3+
14
+ """
15
+ import configparser
16
+ import logging
17
+ import pathlib
18
+ import time
19
+ import traceback
20
+
21
+ import click
22
+ from dclab.rtdc_dataset import fmt_tdms
23
+ from dclab.util import hashfile, hashobj
24
+ from dclab import RTDCWriter
25
+ import h5py
26
+ import imageio.v3 as iio
27
+ import numpy as np
28
+
29
+
30
+ logger = logging.getLogger("vid2dc")
31
+ logging.basicConfig(level=logging.INFO)
32
+
33
+
34
+ __version__ = "2025.07.07"
35
+
36
+
37
+ @click.command()
38
+ @click.argument("path_in",
39
+ type=click.Path(exists=True,
40
+ dir_okay=True,
41
+ resolve_path=True,
42
+ path_type=pathlib.Path))
43
+ @click.argument("path-out",
44
+ required=False,
45
+ type=click.Path(dir_okay=False,
46
+ writable=True,
47
+ resolve_path=True,
48
+ path_type=pathlib.Path),
49
+ )
50
+ def vid2dc(path_in: pathlib.Path,
51
+ path_out: pathlib.Path | None = None):
52
+ """Convert raw video data to raw .rtdc data
53
+
54
+ Use this command to convert a video file (e.g. from a legacy
55
+ .tdms measurement or from a custom setup) to a raw .rtdc file.
56
+ No segmentation or feature extraction will take place.
57
+
58
+ You may also specify an input directory instead of a single file
59
+ for batch conversion.
60
+ """
61
+ if path_in.is_dir():
62
+ if path_out is not None:
63
+ raise NotImplementedError("If you pass an input directory, you "
64
+ "must omit the output directory.")
65
+ for ext in [".avi", ".mp4", ".mpg", ".wmv", ".mkv"]:
66
+ for pp in path_in.rglob(f"*{ext}"):
67
+ try:
68
+ convert_video_to_dc(video_path=pp)
69
+ except BaseException:
70
+ elog = pp.with_name(pp.stem + "_vid2dc_error.log")
71
+ elog.write_text(traceback.format_exc())
72
+ click.secho(f"Could not process {pp}, wrote error log "
73
+ f"to {elog}.",
74
+ bold=True, fg="red")
75
+ else:
76
+ convert_video_to_dc(video_path=path_in, dc_path=path_out)
77
+
78
+
79
+ def convert_video_to_dc(video_path: str | pathlib.Path,
80
+ dc_path: str | pathlib.Path = None,
81
+ ):
82
+ """Convert an .avi file to an .rtdc file
83
+
84
+ A valid .rtdc file is produced. Metadata are guessed, but you
85
+ can put metadata in camera.ini files. This is not fully supported yet.
86
+ Please check the metadata of the output .rtdc file.
87
+
88
+ Parameters
89
+ ----------
90
+ video_path:
91
+ Path to a video file (e.g. an .avi file) to convert to .rtdc.
92
+ dc_path:
93
+ Path to an .rtdc file that is created from the video file.
94
+ If the .rtdc file already exists, it will only be overridden
95
+ if the input file or metadata changed.
96
+ """
97
+ video_path = pathlib.Path(video_path)
98
+ if dc_path is None:
99
+ dc_path = video_path.with_name(video_path.stem + "_raw.rtdc")
100
+ dc_path = pathlib.Path(dc_path)
101
+
102
+ # get the dataset configuration
103
+ config, log_paths = fmt_tdms.RTDC_TDMS.extract_tdms_config(
104
+ video_path, ret_source_files=True, ignore_missing=True)
105
+
106
+ # RecoTeem stores an ini file next to the measurement
107
+ prt = video_path.with_suffix(".ini")
108
+ if prt.exists():
109
+ log_paths.append(prt)
110
+
111
+ # read logs
112
+ logs = {}
113
+ for ppl in log_paths:
114
+ logs[ppl.name] = ppl.read_text().split("\n")
115
+
116
+ vmeta = iio.improps(video_path)
117
+ width = vmeta.shape[2]
118
+ height = vmeta.shape[1]
119
+
120
+ config["imaging"].setdefault("frame rate", 2000)
121
+ config["imaging"].setdefault("pixel size", 0.34)
122
+ config["imaging"]["roi size x"] = width
123
+ config["imaging"]["roi size y"] = height
124
+
125
+ # extract additional information from an optional ini file (RecoTeem)
126
+ if prt.exists():
127
+ # measurement index
128
+ if prt.name.startswith("M") and prt.name.count("_"):
129
+ mid = video_path.name.split("_")[0]
130
+ config["experiment"]["run index"] = int(mid[1:])
131
+ cp = configparser.RawConfigParser(allow_no_value=True)
132
+ # Allow upper-case keys (comment for sample name)
133
+ cp.optionxform = lambda x: x
134
+ cp.read(prt)
135
+ rt_fr = cp.getint("set parameter", "frame rate [fps]", fallback=None)
136
+ # frame rate
137
+ if rt_fr is not None:
138
+ config["imaging"]["frame rate"] = rt_fr
139
+ rt_dur = cp.getfloat("set parameter", "set record time [s]",
140
+ fallback=None)
141
+ # duration
142
+ if rt_dur is not None:
143
+ config["online_filter"]["target duration"] = rt_dur / 60
144
+ # sample name
145
+ if cp.has_section("Optional Text"):
146
+ descr = list(cp["Optional Text"].keys())[0]
147
+ config["experiment"]["sample"] = descr
148
+
149
+ # Set the time of the input file
150
+ tse = video_path.stat().st_mtime
151
+ loct = time.localtime(tse)
152
+ # Start time of measurement ('HH:MM:SS')
153
+ timestr = time.strftime("%H:%M:%S", loct)
154
+ config["experiment"].setdefault("time", timestr)
155
+ # Date of measurement ('YYYY-MM-DD')
156
+ datestr = time.strftime("%Y-%m-%d", loct)
157
+ config["experiment"].setdefault("date", datestr)
158
+ config["experiment"].setdefault("sample", video_path.name)
159
+
160
+ config["setup"].setdefault("chip region", "channel")
161
+ config["setup"].setdefault("flow rate", 0)
162
+ config["setup"].setdefault("software version", f"vid2dc {__version__}")
163
+
164
+ config = dict(config)
165
+ if "filtering" in config:
166
+ config.pop("filtering")
167
+
168
+ # Compute a unique hash of the input files
169
+ video_hash = hashobj([hashobj(config),
170
+ hashfile(video_path),
171
+ video_path.stat().st_size,
172
+ ])
173
+
174
+ # If the output file already exists, check whether the hashes match.
175
+ log_name = "vid2dc"
176
+ if dc_path.exists():
177
+ with h5py.File(dc_path) as h5:
178
+ if (log_name in h5.get("logs", [])
179
+ and h5["logs"][log_name].attrs.get("hash") == video_hash):
180
+ # We can reuse this file
181
+ logger.info(f"Reusing existing file {dc_path}")
182
+ return
183
+ else:
184
+ logger.info(f"Rewriting existing {dc_path} (hash mismatch)")
185
+ dc_path.unlink()
186
+
187
+ vid = iio.imiter(video_path)
188
+
189
+ # This is the actual workload of this function. Populate the .rtdc
190
+ # file with the image data.
191
+ logger.info(f"Writing .rtdc file {dc_path}")
192
+ with RTDCWriter(dc_path, mode="reset") as hw:
193
+ # store the image data to the output file in chunks
194
+ chunk_size = hw.get_best_nd_chunks(item_shape=(height, width),
195
+ item_dtype=np.uint8)[0]
196
+ image_chunk = np.zeros((chunk_size, height, width), dtype=np.uint8)
197
+ ii = 0
198
+ for image in vid:
199
+ if len(image.shape) == 3:
200
+ image = image[:, :, 0]
201
+ image_chunk[ii] = image
202
+ ii += 1
203
+ if ii == chunk_size:
204
+ ii = 0
205
+ hw.store_feature("image", image_chunk)
206
+ # store the rest
207
+ if ii:
208
+ hw.store_feature("image", image_chunk[:ii])
209
+
210
+ event_count = hw.h5file["events/image"].shape[0]
211
+ config["experiment"]["event count"] = event_count
212
+ hw.store_metadata(config)
213
+
214
+ # store the input file information as a log
215
+ hw.store_log(
216
+ name=log_name,
217
+ lines=[
218
+ f"Input filename: {video_path.name}",
219
+ f"Output filename: {dc_path.name}",
220
+ f"Input file size: {video_path.stat().st_size}",
221
+ f"Input last edited: {video_path.stat().st_mtime}",
222
+ f"Unique conversion hash: {video_hash}",
223
+ ]
224
+ )
225
+
226
+ # store time
227
+ hw.store_feature(
228
+ "time",
229
+ np.arange(event_count) / config["imaging"]["frame rate"])
230
+ # index starts at 1
231
+ hw.store_feature("index", np.arange(1, event_count + 1))
232
+ # frame is an ascending number, just start with 1
233
+ hw.store_feature("frame", np.arange(1, event_count + 1))
234
+
235
+ # only store hash attribute when successful
236
+ hw.h5file["logs"][log_name].attrs["hash"] = video_hash
237
+
238
+
239
+ if __name__ == "__main__":
240
+ vid2dc()
@@ -358,7 +358,10 @@ def test_basin_relative_paths(path_sep):
358
358
  @pytest.mark.filterwarnings(
359
359
  "ignore::dclab.rtdc_dataset.config.WrongConfigurationTypeWarning")
360
360
  def test_basin_key_reproducible():
361
- """Since 0.62.9 we sort basin keys"""
361
+ """
362
+ Since 0.62.9 we sort basin keys
363
+ Since 0.66.0 we have identifiers in the basins
364
+ """
362
365
  h5path = retrieve_data("fmt-hdf5_fl_wide-channel_2023.zip")
363
366
  h5path_small = h5path.parent / "subdirectory" / "relative.rtdc"
364
367
  h5path_small.parent.mkdir()
@@ -409,12 +412,11 @@ def test_basin_key_reproducible():
409
412
  # from the input file.
410
413
  with dclab.new_dataset(h5path_small_2) as ds:
411
414
  assert len(ds.basins) == 1
412
- # dclab 0.62.9
413
415
  assert ds.basins[0].key in [
414
416
  # posix linesep
415
- "08dadcb6873a2cf1e5ce781a8887f00f",
417
+ "b125c0e7d4ab1aff1030f40b87d670c3",
416
418
  # win linesep
417
- "a1b2aa154724cf46263ad2d41b5b2e1d",
419
+ "93bc9ab45b50c094c1b585cc8702ca92",
418
420
  ]
419
421
 
420
422
 
@@ -460,6 +462,28 @@ def test_basin_run_identifier_unknown():
460
462
  assert ds["image"][0][0, 0] == 126
461
463
 
462
464
 
465
+ def test_basin_run_identifier_verify():
466
+ h5path = retrieve_data("fmt-hdf5_fl_wide-channel_2023.zip")
467
+ export_same = h5path.with_name("same.rtdc")
468
+
469
+ # export a subset with basins.
470
+ with dclab.new_dataset(h5path) as ds:
471
+ # export without filters
472
+ ds.export.hdf5(export_same, features=["deform"], basins=True)
473
+
474
+ # change the run identifier of the original file
475
+ with h5py.File(h5path, "a") as h5:
476
+ h5.attrs["experiment:run identifier"] = "Uiiiid!"
477
+
478
+ with dclab.new_dataset(h5path) as ds:
479
+ assert ds.get_measurement_identifier() == "Uiiiid!"
480
+
481
+ with dclab.new_dataset(export_same) as ds2:
482
+ with pytest.warns(UserWarning, match="identifier mismatch"):
483
+ with pytest.raises(KeyError, match="does not exist"):
484
+ ds2["area_um"][0]
485
+
486
+
463
487
  def test_basin_sorting_basic():
464
488
  bnlist = [
465
489
  {"type": "remote", "format": "dcor", "ident": 0},