dcscope 2.22.1__py3-none-any.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.
Files changed (267) hide show
  1. dcscope/__init__.py +17 -0
  2. dcscope/__main__.py +44 -0
  3. dcscope/_version.py +21 -0
  4. dcscope/extensions.py +250 -0
  5. dcscope/gui/__init__.py +2 -0
  6. dcscope/gui/analysis/__init__.py +10 -0
  7. dcscope/gui/analysis/ana_basins.py +110 -0
  8. dcscope/gui/analysis/ana_basins.ui +143 -0
  9. dcscope/gui/analysis/ana_filter.py +341 -0
  10. dcscope/gui/analysis/ana_filter.ui +364 -0
  11. dcscope/gui/analysis/ana_log.py +122 -0
  12. dcscope/gui/analysis/ana_log.ui +100 -0
  13. dcscope/gui/analysis/ana_meta.py +207 -0
  14. dcscope/gui/analysis/ana_meta.ui +141 -0
  15. dcscope/gui/analysis/ana_plot.py +638 -0
  16. dcscope/gui/analysis/ana_plot.ui +1060 -0
  17. dcscope/gui/analysis/ana_slot.py +504 -0
  18. dcscope/gui/analysis/ana_slot.ui +684 -0
  19. dcscope/gui/analysis/ana_tables.py +227 -0
  20. dcscope/gui/analysis/ana_tables.ui +195 -0
  21. dcscope/gui/analysis/ana_view.py +69 -0
  22. dcscope/gui/analysis/ana_view.ui +269 -0
  23. dcscope/gui/analysis/dlg_slot_reorder.py +55 -0
  24. dcscope/gui/analysis/dlg_slot_reorder.ui +138 -0
  25. dcscope/gui/bulk/__init__.py +2 -0
  26. dcscope/gui/bulk/bulk_emodulus.py +200 -0
  27. dcscope/gui/bulk/bulk_emodulus.ui +245 -0
  28. dcscope/gui/compute/__init__.py +3 -0
  29. dcscope/gui/compute/comp_lme4.py +115 -0
  30. dcscope/gui/compute/comp_lme4.ui +194 -0
  31. dcscope/gui/compute/comp_lme4_dataset.py +51 -0
  32. dcscope/gui/compute/comp_lme4_dataset.ui +92 -0
  33. dcscope/gui/compute/comp_lme4_results.py +120 -0
  34. dcscope/gui/compute/comp_lme4_results.ui +268 -0
  35. dcscope/gui/compute/comp_stats.py +223 -0
  36. dcscope/gui/compute/comp_stats.ui +187 -0
  37. dcscope/gui/dcor/__init__.py +304 -0
  38. dcscope/gui/dcor/dcor.ui +118 -0
  39. dcscope/gui/export/__init__.py +3 -0
  40. dcscope/gui/export/e2data.py +394 -0
  41. dcscope/gui/export/e2data.ui +367 -0
  42. dcscope/gui/export/e2filter.py +76 -0
  43. dcscope/gui/export/e2filter.ui +111 -0
  44. dcscope/gui/export/e2plot.py +94 -0
  45. dcscope/gui/export/e2plot.ui +175 -0
  46. dcscope/gui/main.py +1089 -0
  47. dcscope/gui/main.ui +579 -0
  48. dcscope/gui/matrix/__init__.py +4 -0
  49. dcscope/gui/matrix/block_matrix.py +141 -0
  50. dcscope/gui/matrix/block_matrix.ui +207 -0
  51. dcscope/gui/matrix/data_matrix.py +574 -0
  52. dcscope/gui/matrix/dm_dataset.py +116 -0
  53. dcscope/gui/matrix/dm_dataset.ui +348 -0
  54. dcscope/gui/matrix/dm_element.py +111 -0
  55. dcscope/gui/matrix/dm_element.ui +169 -0
  56. dcscope/gui/matrix/dm_filter.py +115 -0
  57. dcscope/gui/matrix/dm_filter.ui +287 -0
  58. dcscope/gui/matrix/plot_matrix.py +316 -0
  59. dcscope/gui/matrix/pm_element.py +39 -0
  60. dcscope/gui/matrix/pm_plot.py +86 -0
  61. dcscope/gui/matrix/pm_plot.ui +249 -0
  62. dcscope/gui/pipeline_plot.py +797 -0
  63. dcscope/gui/pipeline_plot.ui +66 -0
  64. dcscope/gui/preferences.py +380 -0
  65. dcscope/gui/preferences.ui +554 -0
  66. dcscope/gui/quick_view/__init__.py +1 -0
  67. dcscope/gui/quick_view/qv_main.py +1072 -0
  68. dcscope/gui/quick_view/qv_main.ui +1297 -0
  69. dcscope/gui/quick_view/qv_scatter.py +284 -0
  70. dcscope/gui/quick_view/qv_style.css +10 -0
  71. dcscope/gui/update.py +90 -0
  72. dcscope/gui/widgets/__init__.py +15 -0
  73. dcscope/gui/widgets/bg_thread.py +29 -0
  74. dcscope/gui/widgets/bulk_list.py +79 -0
  75. dcscope/gui/widgets/bulk_list.ui +95 -0
  76. dcscope/gui/widgets/double_spin_box_nan.py +75 -0
  77. dcscope/gui/widgets/feature_combobox.py +140 -0
  78. dcscope/gui/widgets/get_path.py +42 -0
  79. dcscope/gui/widgets/key_value_table_widget.css +12 -0
  80. dcscope/gui/widgets/key_value_table_widget.py +75 -0
  81. dcscope/gui/widgets/mdi_subwindow_wo_close.py +12 -0
  82. dcscope/gui/widgets/qrangeslider.py +262 -0
  83. dcscope/gui/widgets/rangecontrol.py +308 -0
  84. dcscope/gui/widgets/rangecontrol.ui +136 -0
  85. dcscope/gui/widgets/simple_image_view.py +55 -0
  86. dcscope/gui/widgets/simple_plot_widget.py +113 -0
  87. dcscope/gui/widgets/so_colorbaritem.py +29 -0
  88. dcscope/gui/widgets/wait_cursor.py +33 -0
  89. dcscope/idiom.py +26 -0
  90. dcscope/img/__init__.py +2 -0
  91. dcscope/img/icon-theme/breeze/COPYING-ICONS +209 -0
  92. dcscope/img/icon-theme/breeze/COPYING.LIB +510 -0
  93. dcscope/img/icon-theme/breeze/README +5 -0
  94. dcscope/img/icon-theme/breeze/actions/16/application-exit.svg +17 -0
  95. dcscope/img/icon-theme/breeze/actions/16/code-context.svg +13 -0
  96. dcscope/img/icon-theme/breeze/actions/16/dialog-cancel.svg +13 -0
  97. dcscope/img/icon-theme/breeze/actions/16/dialog-close.svg +17 -0
  98. dcscope/img/icon-theme/breeze/actions/16/dialog-messages.svg +13 -0
  99. dcscope/img/icon-theme/breeze/actions/16/dialog-ok-apply.svg +13 -0
  100. dcscope/img/icon-theme/breeze/actions/16/dialog-ok.svg +13 -0
  101. dcscope/img/icon-theme/breeze/actions/16/document-open-folder.svg +13 -0
  102. dcscope/img/icon-theme/breeze/actions/16/document-open.svg +13 -0
  103. dcscope/img/icon-theme/breeze/actions/16/document-save.svg +13 -0
  104. dcscope/img/icon-theme/breeze/actions/16/documentinfo.svg +12 -0
  105. dcscope/img/icon-theme/breeze/actions/16/draw-watercolor.svg +13 -0
  106. dcscope/img/icon-theme/breeze/actions/16/edit-clear-all.svg +13 -0
  107. dcscope/img/icon-theme/breeze/actions/16/edit-clear.svg +13 -0
  108. dcscope/img/icon-theme/breeze/actions/16/edit-paste.svg +13 -0
  109. dcscope/img/icon-theme/breeze/actions/16/globe.svg +16 -0
  110. dcscope/img/icon-theme/breeze/actions/16/gtk-preferences.svg +13 -0
  111. dcscope/img/icon-theme/breeze/actions/16/list-add.svg +13 -0
  112. dcscope/img/icon-theme/breeze/actions/16/messagebox_warning.svg +20 -0
  113. dcscope/img/icon-theme/breeze/actions/16/object-columns.svg +13 -0
  114. dcscope/img/icon-theme/breeze/actions/16/object-order-lower.svg +13 -0
  115. dcscope/img/icon-theme/breeze/actions/16/object-rows.svg +13 -0
  116. dcscope/img/icon-theme/breeze/actions/16/office-chart-line-stacked.svg +13 -0
  117. dcscope/img/icon-theme/breeze/actions/16/office-chart-ring.svg +13 -0
  118. dcscope/img/icon-theme/breeze/actions/16/office-chart-scatter.svg +13 -0
  119. dcscope/img/icon-theme/breeze/actions/16/path-mode-polyline.svg +13 -0
  120. dcscope/img/icon-theme/breeze/actions/16/preferences-activities.svg +13 -0
  121. dcscope/img/icon-theme/breeze/actions/16/remove.svg +10 -0
  122. dcscope/img/icon-theme/breeze/actions/16/search.svg +13 -0
  123. dcscope/img/icon-theme/breeze/actions/16/show-grid.svg +13 -0
  124. dcscope/img/icon-theme/breeze/actions/16/special_paste.svg +13 -0
  125. dcscope/img/icon-theme/breeze/actions/16/tools-wizard.svg +13 -0
  126. dcscope/img/icon-theme/breeze/actions/16/view-calendar-list.svg +13 -0
  127. dcscope/img/icon-theme/breeze/actions/16/view-filter.svg +13 -0
  128. dcscope/img/icon-theme/breeze/actions/16/view-list-tree.svg +13 -0
  129. dcscope/img/icon-theme/breeze/actions/16/view-statistics.svg +13 -0
  130. dcscope/img/icon-theme/breeze/actions/16/visibility.svg +21 -0
  131. dcscope/img/icon-theme/breeze/actions/22/application-exit.svg +13 -0
  132. dcscope/img/icon-theme/breeze/actions/22/code-context.svg +14 -0
  133. dcscope/img/icon-theme/breeze/actions/22/dialog-cancel.svg +14 -0
  134. dcscope/img/icon-theme/breeze/actions/22/dialog-close.svg +10 -0
  135. dcscope/img/icon-theme/breeze/actions/22/dialog-messages.svg +14 -0
  136. dcscope/img/icon-theme/breeze/actions/22/dialog-ok-apply.svg +14 -0
  137. dcscope/img/icon-theme/breeze/actions/22/dialog-ok.svg +14 -0
  138. dcscope/img/icon-theme/breeze/actions/22/document-open-folder.svg +14 -0
  139. dcscope/img/icon-theme/breeze/actions/22/document-open.svg +14 -0
  140. dcscope/img/icon-theme/breeze/actions/22/document-save.svg +14 -0
  141. dcscope/img/icon-theme/breeze/actions/22/documentinfo.svg +14 -0
  142. dcscope/img/icon-theme/breeze/actions/22/draw-watercolor.svg +14 -0
  143. dcscope/img/icon-theme/breeze/actions/22/edit-clear-all.svg +14 -0
  144. dcscope/img/icon-theme/breeze/actions/22/edit-clear.svg +14 -0
  145. dcscope/img/icon-theme/breeze/actions/22/edit-paste.svg +14 -0
  146. dcscope/img/icon-theme/breeze/actions/22/globe.svg +12 -0
  147. dcscope/img/icon-theme/breeze/actions/22/gtk-preferences.svg +13 -0
  148. dcscope/img/icon-theme/breeze/actions/22/list-add.svg +14 -0
  149. dcscope/img/icon-theme/breeze/actions/22/messagebox_warning.svg +17 -0
  150. dcscope/img/icon-theme/breeze/actions/22/object-columns.svg +14 -0
  151. dcscope/img/icon-theme/breeze/actions/22/object-order-lower.svg +17 -0
  152. dcscope/img/icon-theme/breeze/actions/22/object-rows.svg +17 -0
  153. dcscope/img/icon-theme/breeze/actions/22/office-chart-line-stacked.svg +17 -0
  154. dcscope/img/icon-theme/breeze/actions/22/office-chart-ring.svg +17 -0
  155. dcscope/img/icon-theme/breeze/actions/22/office-chart-scatter.svg +17 -0
  156. dcscope/img/icon-theme/breeze/actions/22/path-mode-polyline.svg +17 -0
  157. dcscope/img/icon-theme/breeze/actions/22/preferences-activities.svg +14 -0
  158. dcscope/img/icon-theme/breeze/actions/22/remove.svg +10 -0
  159. dcscope/img/icon-theme/breeze/actions/22/special_paste.svg +14 -0
  160. dcscope/img/icon-theme/breeze/actions/22/tools-wizard.svg +14 -0
  161. dcscope/img/icon-theme/breeze/actions/22/view-calendar-list.svg +14 -0
  162. dcscope/img/icon-theme/breeze/actions/22/view-filter.svg +14 -0
  163. dcscope/img/icon-theme/breeze/actions/22/view-list-tree.svg +14 -0
  164. dcscope/img/icon-theme/breeze/actions/22/view-statistics.svg +14 -0
  165. dcscope/img/icon-theme/breeze/actions/22/visibility.svg +14 -0
  166. dcscope/img/icon-theme/breeze/actions/24/application-exit.svg +12 -0
  167. dcscope/img/icon-theme/breeze/actions/24/code-context.svg +12 -0
  168. dcscope/img/icon-theme/breeze/actions/24/dialog-cancel.svg +12 -0
  169. dcscope/img/icon-theme/breeze/actions/24/dialog-close.svg +10 -0
  170. dcscope/img/icon-theme/breeze/actions/24/dialog-messages.svg +12 -0
  171. dcscope/img/icon-theme/breeze/actions/24/dialog-ok-apply.svg +12 -0
  172. dcscope/img/icon-theme/breeze/actions/24/dialog-ok.svg +14 -0
  173. dcscope/img/icon-theme/breeze/actions/24/document-open-folder.svg +12 -0
  174. dcscope/img/icon-theme/breeze/actions/24/document-open.svg +12 -0
  175. dcscope/img/icon-theme/breeze/actions/24/document-save.svg +12 -0
  176. dcscope/img/icon-theme/breeze/actions/24/documentinfo.svg +14 -0
  177. dcscope/img/icon-theme/breeze/actions/24/draw-watercolor.svg +12 -0
  178. dcscope/img/icon-theme/breeze/actions/24/edit-clear-all.svg +14 -0
  179. dcscope/img/icon-theme/breeze/actions/24/edit-clear.svg +12 -0
  180. dcscope/img/icon-theme/breeze/actions/24/edit-paste.svg +12 -0
  181. dcscope/img/icon-theme/breeze/actions/24/globe.svg +14 -0
  182. dcscope/img/icon-theme/breeze/actions/24/gtk-preferences.svg +13 -0
  183. dcscope/img/icon-theme/breeze/actions/24/list-add.svg +12 -0
  184. dcscope/img/icon-theme/breeze/actions/24/messagebox_warning.svg +13 -0
  185. dcscope/img/icon-theme/breeze/actions/24/object-columns.svg +12 -0
  186. dcscope/img/icon-theme/breeze/actions/24/object-order-lower.svg +15 -0
  187. dcscope/img/icon-theme/breeze/actions/24/object-rows.svg +15 -0
  188. dcscope/img/icon-theme/breeze/actions/24/office-chart-line-stacked.svg +15 -0
  189. dcscope/img/icon-theme/breeze/actions/24/office-chart-ring.svg +15 -0
  190. dcscope/img/icon-theme/breeze/actions/24/office-chart-scatter.svg +15 -0
  191. dcscope/img/icon-theme/breeze/actions/24/path-mode-polyline.svg +15 -0
  192. dcscope/img/icon-theme/breeze/actions/24/preferences-activities.svg +13 -0
  193. dcscope/img/icon-theme/breeze/actions/24/remove.svg +10 -0
  194. dcscope/img/icon-theme/breeze/actions/24/special_paste.svg +12 -0
  195. dcscope/img/icon-theme/breeze/actions/24/tools-wizard.svg +12 -0
  196. dcscope/img/icon-theme/breeze/actions/24/view-calendar-list.svg +12 -0
  197. dcscope/img/icon-theme/breeze/actions/24/view-filter.svg +12 -0
  198. dcscope/img/icon-theme/breeze/actions/24/view-list-tree.svg +12 -0
  199. dcscope/img/icon-theme/breeze/actions/24/view-statistics.svg +12 -0
  200. dcscope/img/icon-theme/breeze/actions/24/visibility.svg +14 -0
  201. dcscope/img/icon-theme/breeze/actions/32/application-exit.svg +8 -0
  202. dcscope/img/icon-theme/breeze/actions/32/dialog-cancel.svg +13 -0
  203. dcscope/img/icon-theme/breeze/actions/32/dialog-messages.svg +13 -0
  204. dcscope/img/icon-theme/breeze/actions/32/dialog-ok-apply.svg +1 -0
  205. dcscope/img/icon-theme/breeze/actions/32/dialog-ok.svg +1 -0
  206. dcscope/img/icon-theme/breeze/actions/32/document-open-folder.svg +13 -0
  207. dcscope/img/icon-theme/breeze/actions/32/document-open.svg +13 -0
  208. dcscope/img/icon-theme/breeze/actions/32/document-save.svg +18 -0
  209. dcscope/img/icon-theme/breeze/actions/32/gtk-preferences.svg +17 -0
  210. dcscope/img/icon-theme/breeze/actions/32/object-order-lower.svg +18 -0
  211. dcscope/img/icon-theme/breeze/actions/32/view-filter.svg +18 -0
  212. dcscope/img/icon-theme/breeze/actions/32/view-list-tree.svg +18 -0
  213. dcscope/img/icon-theme/breeze/places/16/folder-cloud.svg +13 -0
  214. dcscope/img/icon-theme/breeze/places/16/folder.svg +13 -0
  215. dcscope/img/icon-theme/breeze/places/22/folder-cloud.svg +13 -0
  216. dcscope/img/icon-theme/breeze/places/22/folder.svg +13 -0
  217. dcscope/img/icon-theme/breeze/places/24/folder-cloud.svg +12 -0
  218. dcscope/img/icon-theme/breeze/places/24/folder.svg +12 -0
  219. dcscope/img/icon-theme/breeze/places/32/folder-cloud.svg +35 -0
  220. dcscope/img/icon-theme/breeze/places/32/folder.svg +30 -0
  221. dcscope/img/icon-theme/breeze/places/64/folder-cloud.svg +35 -0
  222. dcscope/img/icon-theme/breeze/places/64/folder.svg +30 -0
  223. dcscope/img/icon-theme/breeze/status/16/dialog-error.svg +9 -0
  224. dcscope/img/icon-theme/breeze/status/16/dialog-information.svg +9 -0
  225. dcscope/img/icon-theme/breeze/status/16/dialog-question.svg +7 -0
  226. dcscope/img/icon-theme/breeze/status/16/dialog-warning.svg +9 -0
  227. dcscope/img/icon-theme/breeze/status/22/dialog-error.svg +9 -0
  228. dcscope/img/icon-theme/breeze/status/22/dialog-information.svg +9 -0
  229. dcscope/img/icon-theme/breeze/status/22/dialog-question.svg +7 -0
  230. dcscope/img/icon-theme/breeze/status/22/dialog-warning.svg +9 -0
  231. dcscope/img/icon-theme/breeze/status/24/dialog-error.svg +13 -0
  232. dcscope/img/icon-theme/breeze/status/24/dialog-information.svg +13 -0
  233. dcscope/img/icon-theme/breeze/status/24/dialog-question.svg +9 -0
  234. dcscope/img/icon-theme/breeze/status/24/dialog-warning.svg +1 -0
  235. dcscope/img/icon-theme/breeze/status/64/dialog-error.svg +25 -0
  236. dcscope/img/icon-theme/breeze/status/64/dialog-information.svg +25 -0
  237. dcscope/img/icon-theme/breeze/status/64/dialog-question.svg +25 -0
  238. dcscope/img/icon-theme/breeze/status/64/dialog-warning.svg +25 -0
  239. dcscope/img/icon-theme/collect_icons.py +124 -0
  240. dcscope/img/icon-theme/dcscope/dcor.png +0 -0
  241. dcscope/img/icon-theme/dcscope/edit-copy-anew.svg +13 -0
  242. dcscope/img/icon-theme/dcscope/emodulus.svg +69 -0
  243. dcscope/img/icon-theme/dcscope/filter_ray.svg +54 -0
  244. dcscope/img/icon-theme/dcscope/region_channel.svg +86 -0
  245. dcscope/img/icon-theme/dcscope/region_reservoir.svg +89 -0
  246. dcscope/img/icon-theme/dcscope/rlang.svg +108 -0
  247. dcscope/img/icon-theme/dcscope/statistical_significance.svg +106 -0
  248. dcscope/img/icon-theme/index.theme +81 -0
  249. dcscope/img/icon.png +0 -0
  250. dcscope/img/icon.svg +73 -0
  251. dcscope/img/splash.png +0 -0
  252. dcscope/meta_tool.py +143 -0
  253. dcscope/pipeline/__init__.py +5 -0
  254. dcscope/pipeline/core.py +632 -0
  255. dcscope/pipeline/dataslot.py +270 -0
  256. dcscope/pipeline/filter.py +161 -0
  257. dcscope/pipeline/filter_ray.py +170 -0
  258. dcscope/pipeline/plot.py +187 -0
  259. dcscope/plot_cache.py +79 -0
  260. dcscope/session.py +379 -0
  261. dcscope/util.py +34 -0
  262. dcscope-2.22.1.dist-info/METADATA +95 -0
  263. dcscope-2.22.1.dist-info/RECORD +267 -0
  264. dcscope-2.22.1.dist-info/WHEEL +5 -0
  265. dcscope-2.22.1.dist-info/entry_points.txt +2 -0
  266. dcscope-2.22.1.dist-info/licenses/LICENSE +621 -0
  267. dcscope-2.22.1.dist-info/top_level.txt +1 -0
dcscope/__init__.py ADDED
@@ -0,0 +1,17 @@
1
+ """GUI for analysis and visualization of deformability cytometry datasets
2
+ Copyright (C) 2019 Paul Müller
3
+
4
+ This program is free software: you can redistribute it and/or modify it
5
+ under the terms of the GNU General Public License as published by the
6
+ Free Software Foundation, either version 3 of the License, or (at your
7
+ option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
+ for more details.
13
+
14
+ You should have received a copy of the GNU General Public License along
15
+ with this program. If not, see <https://www.gnu.org/licenses/>.
16
+ """
17
+ from ._version import version as __version__ # noqa: F401
dcscope/__main__.py ADDED
@@ -0,0 +1,44 @@
1
+ def main(splash=True):
2
+ import importlib.resources
3
+ import sys
4
+
5
+ from PyQt6.QtWidgets import QApplication
6
+ from PyQt6.QtCore import QEventLoop
7
+ # import before creating application
8
+ import pyqtgraph # noqa: F401
9
+
10
+ app = QApplication(sys.argv)
11
+
12
+ if splash:
13
+ from PyQt6.QtWidgets import QSplashScreen
14
+ from PyQt6.QtGui import QPixmap
15
+ ref = importlib.resources.files("dcscope.img") / "splash.png"
16
+ with importlib.resources.as_file(ref) as splash_path:
17
+ splash_pix = QPixmap(str(splash_path))
18
+ splash = QSplashScreen(splash_pix)
19
+ splash.setMask(splash_pix.mask())
20
+ splash.show()
21
+ # make sure Qt really displays the splash screen
22
+ app.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 300)
23
+
24
+ from PyQt6 import QtCore, QtGui
25
+ from .gui import DCscope
26
+
27
+ # Set Application Icon
28
+ ref = importlib.resources.files("dcscope.img") / "icon.png"
29
+ with importlib.resources.as_file(ref) as icon_path:
30
+ app.setWindowIcon(QtGui.QIcon(str(icon_path)))
31
+
32
+ # Use dots as decimal separators
33
+ QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.Language.C))
34
+
35
+ window = DCscope(*app.arguments()[1:])
36
+
37
+ if splash:
38
+ splash.finish(window)
39
+
40
+ sys.exit(app.exec())
41
+
42
+
43
+ if __name__ == "__main__":
44
+ main()
dcscope/_version.py ADDED
@@ -0,0 +1,21 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
6
+ TYPE_CHECKING = False
7
+ if TYPE_CHECKING:
8
+ from typing import Tuple
9
+ from typing import Union
10
+
11
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
12
+ else:
13
+ VERSION_TUPLE = object
14
+
15
+ version: str
16
+ __version__: str
17
+ __version_tuple__: VERSION_TUPLE
18
+ version_tuple: VERSION_TUPLE
19
+
20
+ __version__ = version = '2.22.1'
21
+ __version_tuple__ = version_tuple = (2, 22, 1)
dcscope/extensions.py ADDED
@@ -0,0 +1,250 @@
1
+ import collections
2
+ import functools
3
+ import pathlib
4
+ import shutil
5
+
6
+ from dclab.util import hashfile
7
+ from dclab.rtdc_dataset.feat_anc_plugin import plugin_feature
8
+
9
+
10
+ SUPPORTED_FORMATS = [
11
+ ".py",
12
+ ]
13
+
14
+
15
+ class ExtensionManager:
16
+ def __init__(self, store_path):
17
+ """Extension manager
18
+
19
+ This class can be used to maintain a set of extensions
20
+ (plugin features or machine-learning features) at a
21
+ specific location `store_path` on the file system.
22
+
23
+ All extensions are loaded during instantiation. It is
24
+ possible to disable individual extensions (without
25
+ deleting them) on-the-fly.
26
+ """
27
+ self.store_path = pathlib.Path(store_path)
28
+ self.store_path.mkdir(exist_ok=True, parents=True)
29
+ self.extension_hash_dict = collections.OrderedDict()
30
+ self.load_extensions_from_store()
31
+
32
+ def __contains__(self, key):
33
+ if isinstance(key, Extension):
34
+ key = key.hash
35
+ return key in self.extension_hash_dict
36
+
37
+ def __getitem__(self, key):
38
+ return self.get_extension_or_bust(key)
39
+
40
+ def __iter__(self):
41
+ for ahash in self.extension_hash_dict:
42
+ yield self.extension_hash_dict[ahash]
43
+
44
+ def __len__(self):
45
+ return len(self.extension_hash_dict)
46
+
47
+ def get_extension_or_bust(self, ext):
48
+ """Return an Extension instance or raise ValueError
49
+
50
+ Parameter `ext` can be an instance of Extension, an
51
+ extension hash, or an index. If an Extension or a
52
+ hash is provided, this function checks whether the
53
+ extension is maintained by this manager and returns
54
+ the correct instance.
55
+
56
+ Parameters
57
+ ----------
58
+ ext: Extension
59
+ Extension instance
60
+ """
61
+ if isinstance(ext, Extension):
62
+ the_hash = ext.hash
63
+ elif isinstance(ext, int):
64
+ the_hash = list(self.extension_hash_dict.keys())[ext]
65
+ else:
66
+ the_hash = ext
67
+ if the_hash in self.extension_hash_dict:
68
+ return self.extension_hash_dict[the_hash]
69
+ else:
70
+ raise ValueError(f"Extension not in {self.store_path}: {the_hash}")
71
+
72
+ def import_extension_from_path(self, path):
73
+ """Import an extension file to `self.store_path`"""
74
+ ext = Extension(path)
75
+ if ext.hash not in self.extension_hash_dict:
76
+ new_name = f"ext_{ext.type}_{ext.hash}{ext.suffix}"
77
+ new_path = self.store_path / new_name
78
+ shutil.copy2(path, new_path)
79
+ ext.path = new_path
80
+ self.extension_load(ext)
81
+ return ext
82
+
83
+ def load_extensions_from_store(self):
84
+ """Load all extensions from `self.store_path`
85
+
86
+ This function is called during initialization.
87
+ """
88
+ failed = []
89
+ # load all (enabled) extensions
90
+ for pp in self.store_path.glob("ext_*"):
91
+ if pp.suffix in SUPPORTED_FORMATS:
92
+ ext = Extension(pp)
93
+ try:
94
+ self.extension_load(ext)
95
+ except BaseException:
96
+ failed.append(ext)
97
+ if failed:
98
+ raise ValueError(f"Could not load these extensions: {failed}")
99
+
100
+ def extension_load(self, ext):
101
+ """Load a single extension
102
+
103
+ Parameters
104
+ ----------
105
+ ext: Extension
106
+ Extension instance
107
+ """
108
+ # add to hash dict first in case it gets disabled
109
+ self.extension_hash_dict[ext.hash] = ext
110
+ ext.load()
111
+
112
+ def extension_remove(self, ext):
113
+ """Remove an extension from `self.store_path` and unload it
114
+
115
+ Parameters
116
+ ----------
117
+ ext: Extension or str or int
118
+ Extension instance, its hash or its index in
119
+ ExtensionManager
120
+ """
121
+ ext = self.get_extension_or_bust(ext)
122
+ self.extension_hash_dict.pop(ext.hash)
123
+ # re-instantiate ext to get the path right
124
+ ext.destroy()
125
+
126
+ def extension_set_enabled(self, ext, enabled):
127
+ """Enable or disable an extension
128
+
129
+ Parameters
130
+ ----------
131
+ ext: Extension or str or int
132
+ Extension instance, its hash or its index in
133
+ ExtensionManager
134
+ enabled: bool
135
+ Whether to enable the extension.
136
+ """
137
+ ext = self.get_extension_or_bust(ext)
138
+ ext.set_enabled(enabled)
139
+
140
+
141
+ class Extension:
142
+ def __init__(self, path):
143
+ """Helper class for managing individual extensions"""
144
+ self.path = pathlib.Path(path)
145
+ self.suffix = self.path.suffix
146
+
147
+ def __repr__(self):
148
+ return f"<DCscope Extension {self.path} at {hex(id(self))}>"
149
+
150
+ @property
151
+ def description(self):
152
+ """Description of the extension"""
153
+ description = "No description provided."
154
+ if self.loaded:
155
+ if self.type == "feat_anc_plugin":
156
+ pfinst = self.get_plugin_feature_instances()[0]
157
+ info = pfinst.plugin_feature_info
158
+ description = info['long description']
159
+ return description
160
+
161
+ @property
162
+ def enabled(self):
163
+ """Whether the extension is enabled"""
164
+ return not self.path_lock_disabled.exists()
165
+
166
+ @property
167
+ @functools.lru_cache()
168
+ def hash(self):
169
+ """MD5 hash of the extension"""
170
+ return hashfile(self.path)
171
+
172
+ @property
173
+ def loaded(self):
174
+ """Whether the extension is currently loaded"""
175
+ if self.type == "feat_anc_plugin":
176
+ return bool(self.get_plugin_feature_instances())
177
+
178
+ @property
179
+ def path_lock_disabled(self):
180
+ return self.path.with_name(self.path.name + "_disabled")
181
+
182
+ @property
183
+ def title(self):
184
+ """Descriptive title including version of the extension"""
185
+ title = self.path.name # fallback
186
+ if self.loaded:
187
+ if self.type == "feat_anc_plugin":
188
+ pfinst = self.get_plugin_feature_instances()[0]
189
+ info = pfinst.plugin_feature_info
190
+ title = f"{info['description']} " \
191
+ + f"({info['version']}-{info['identifier'][:4]})"
192
+ return title
193
+
194
+ @property
195
+ @functools.lru_cache()
196
+ def type(self):
197
+ """Type of the extension (e.g. "feat_anc_plugin")"""
198
+ if self.path.suffix == ".py":
199
+ return "feat_anc_plugin"
200
+ else:
201
+ raise ValueError(f"Cannot determine extension type: {self.path}!")
202
+
203
+ def get_plugin_feature_instances(self):
204
+ """Return a list of all PlugInFeature instances for this extension"""
205
+ pf_instances = []
206
+ for inst in plugin_feature.PlugInFeature.features:
207
+ if (isinstance(inst, plugin_feature.PlugInFeature)
208
+ and self.path.samefile(inst.plugin_path)):
209
+ pf_instances.append(inst)
210
+ return pf_instances
211
+
212
+ def set_enabled(self, enabled):
213
+ """Set this extension to enabled (True) or disabled (False)
214
+
215
+ The extension is also loaded (True) or unloaded (False).
216
+ """
217
+ if enabled:
218
+ # set enabled so that `load` works
219
+ self.path_lock_disabled.unlink(missing_ok=True)
220
+ self.load()
221
+ else:
222
+ self.unload()
223
+ self.path_lock_disabled.touch()
224
+
225
+ def load(self):
226
+ """Load the extension if it is enabled and not loaded"""
227
+ if not self.enabled or self.loaded:
228
+ # do not load disabled extensions or extensions already loaded
229
+ return
230
+
231
+ try:
232
+ if self.type == "feat_anc_plugin":
233
+ plugin_feature.load_plugin_feature(self.path)
234
+ except BaseException:
235
+ # If loading the extension fails, disable it and only then
236
+ # raise the exception.
237
+ self.set_enabled(False)
238
+ raise
239
+
240
+ def unload(self):
241
+ """Unload the extension"""
242
+ if self.type == "feat_anc_plugin":
243
+ for inst in self.get_plugin_feature_instances():
244
+ plugin_feature.remove_plugin_feature(inst)
245
+
246
+ def destroy(self):
247
+ """Unload and remove the extension"""
248
+ self.unload()
249
+ self.path_lock_disabled.unlink(missing_ok=True)
250
+ self.path.unlink(missing_ok=True)
@@ -0,0 +1,2 @@
1
+ from .main import DCscope # noqa: F401
2
+ from . import widgets # noqa: F401
@@ -0,0 +1,10 @@
1
+ # flake8: noqa: F401
2
+ from .dlg_slot_reorder import DlgSlotReorder
3
+ from .ana_basins import BasinsPanel
4
+ from .ana_filter import FilterPanel
5
+ from .ana_log import LogPanel
6
+ from .ana_meta import MetaPanel
7
+ from .ana_plot import PlotPanel
8
+ from .ana_slot import SlotPanel
9
+ from .ana_tables import TablesPanel
10
+ from .ana_view import AnalysisView
@@ -0,0 +1,110 @@
1
+ import importlib.resources
2
+ import json
3
+
4
+ from pygments import highlight, lexers, formatters
5
+ from PyQt6 import uic, QtCore, QtWidgets
6
+
7
+
8
+ class BasinsPanel(QtWidgets.QWidget):
9
+ """Tables panel widget
10
+
11
+ Visualizes tables stored in the .rtdc file
12
+ """
13
+
14
+ def __init__(self, *args, **kwargs):
15
+ super(BasinsPanel, self).__init__(*args, **kwargs)
16
+ ref = importlib.resources.files(
17
+ "dcscope.gui.analysis") / "ana_basins.ui"
18
+ with importlib.resources.as_file(ref) as path_ui:
19
+ uic.loadUi(path_ui, self)
20
+ # current DCscope pipeline
21
+ self._pipeline = None
22
+ self.data_role = QtCore.Qt.ItemDataRole.UserRole + 2
23
+ self.treeWidget_basin_name.setColumnCount(1)
24
+
25
+ self.listWidget_dataset.currentRowChanged.connect(
26
+ self.on_select_dataset)
27
+ self.treeWidget_basin_name.currentItemChanged.connect(
28
+ self.on_select_basin)
29
+ self.update_content()
30
+
31
+ @property
32
+ def pipeline(self):
33
+ return self._pipeline
34
+
35
+ def add_basin_nodes(self, parent_widget, ds):
36
+ for bd in ds.basins_get_dicts():
37
+ # Get all basins
38
+ item = QtWidgets.QTreeWidgetItem(parent_widget)
39
+ item.setText(0, bd["name"])
40
+ item.setData(0, self.data_role, (ds, bd))
41
+
42
+ @QtCore.pyqtSlot(int)
43
+ def on_select_dataset(self, ds_idx):
44
+ """Show the tables of the dataset in the right-hand list widget"""
45
+ self.treeWidget_basin_name.clear()
46
+ if ds_idx >= 0:
47
+ ds = self._pipeline.slots[ds_idx].get_dataset()
48
+ self.add_basin_nodes(parent_widget=self.treeWidget_basin_name,
49
+ ds=ds)
50
+
51
+ @QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, QtWidgets.QTreeWidgetItem)
52
+ def on_select_basin(self, current, previous=None):
53
+ """Show the tables of the dataset in the right-hand list widget"""
54
+ ds_idx = self.listWidget_dataset.currentRow()
55
+ if current is not None and ds_idx >= 0:
56
+ # Get the correct basin
57
+ ds, bd = current.data(0, self.data_role)
58
+ # try to access that basin in `ds`
59
+ for bn in ds.basins:
60
+ if bn.key == bd["key"]:
61
+ # We've got a match
62
+ loaded = True
63
+ available = bn.is_available()
64
+ break
65
+ else:
66
+ loaded = False
67
+ available = False
68
+ bn = None
69
+
70
+ # Display the basin information
71
+ self.label_status.setText(f"{loaded=}, {available=}")
72
+ self.label_id.setText(f"{bd.get('name')} ({bd['key']})")
73
+ self.textEdit_def.setText(
74
+ highlight(json.dumps(bd, sort_keys=True, indent=2),
75
+ lexers.JsonLexer(),
76
+ formatters.HtmlFormatter(full=True,
77
+ noclasses=True,
78
+ nobackground=True))
79
+ )
80
+
81
+ if available and bn is not None and not current.childCount():
82
+ # Add child tree nodes
83
+ self.add_basin_nodes(parent_widget=current,
84
+ ds=bn.ds)
85
+ current.setExpanded(True)
86
+ else:
87
+ self.textEdit_def.clear()
88
+ self.label_status.setText("")
89
+ self.label_id.setText("")
90
+
91
+ def set_pipeline(self, pipeline):
92
+ self._pipeline = pipeline
93
+
94
+ def update_content(self, slot_index=None, **kwargs):
95
+ if self._pipeline and self._pipeline.slots:
96
+ self.setEnabled(True)
97
+ self.setUpdatesEnabled(False)
98
+ self.listWidget_dataset.clear()
99
+ self.treeWidget_basin_name.clear()
100
+ for slot in self._pipeline.slots:
101
+ self.listWidget_dataset.addItem(slot.name)
102
+ self.setUpdatesEnabled(True)
103
+ if slot_index is None or slot_index < 0:
104
+ slot_index = max(0, self.listWidget_dataset.currentRow())
105
+ slot_index = min(slot_index, self._pipeline.num_slots - 1)
106
+ self.listWidget_dataset.setCurrentRow(slot_index)
107
+ else:
108
+ self.setEnabled(False)
109
+ self.listWidget_dataset.clear()
110
+ self.treeWidget_basin_name.clear()
@@ -0,0 +1,143 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>701</width>
10
+ <height>538</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Form</string>
15
+ </property>
16
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
17
+ <item>
18
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
19
+ <item>
20
+ <layout class="QVBoxLayout" name="verticalLayout_2">
21
+ <item>
22
+ <widget class="QLabel" name="label">
23
+ <property name="text">
24
+ <string>Dataset</string>
25
+ </property>
26
+ </widget>
27
+ </item>
28
+ <item>
29
+ <widget class="QListWidget" name="listWidget_dataset">
30
+ <property name="minimumSize">
31
+ <size>
32
+ <width>200</width>
33
+ <height>0</height>
34
+ </size>
35
+ </property>
36
+ <property name="showDropIndicator" stdset="0">
37
+ <bool>false</bool>
38
+ </property>
39
+ <property name="alternatingRowColors">
40
+ <bool>true</bool>
41
+ </property>
42
+ <property name="selectionBehavior">
43
+ <enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
44
+ </property>
45
+ </widget>
46
+ </item>
47
+ </layout>
48
+ </item>
49
+ <item>
50
+ <layout class="QVBoxLayout" name="verticalLayout_3">
51
+ <item>
52
+ <widget class="QLabel" name="label_2">
53
+ <property name="text">
54
+ <string>Basins</string>
55
+ </property>
56
+ </widget>
57
+ </item>
58
+ <item>
59
+ <widget class="QTreeWidget" name="treeWidget_basin_name">
60
+ <property name="showDropIndicator" stdset="0">
61
+ <bool>false</bool>
62
+ </property>
63
+ <property name="alternatingRowColors">
64
+ <bool>true</bool>
65
+ </property>
66
+ <property name="autoExpandDelay">
67
+ <number>0</number>
68
+ </property>
69
+ <property name="uniformRowHeights">
70
+ <bool>true</bool>
71
+ </property>
72
+ <property name="headerHidden">
73
+ <bool>true</bool>
74
+ </property>
75
+ <column>
76
+ <property name="text">
77
+ <string notr="true">1</string>
78
+ </property>
79
+ </column>
80
+ </widget>
81
+ </item>
82
+ </layout>
83
+ </item>
84
+ </layout>
85
+ </item>
86
+ <item>
87
+ <widget class="Line" name="line">
88
+ <property name="orientation">
89
+ <enum>Qt::Orientation::Horizontal</enum>
90
+ </property>
91
+ </widget>
92
+ </item>
93
+ <item>
94
+ <layout class="QFormLayout" name="formLayout">
95
+ <item row="0" column="0">
96
+ <widget class="QLabel" name="label_3">
97
+ <property name="text">
98
+ <string>Basin</string>
99
+ </property>
100
+ </widget>
101
+ </item>
102
+ <item row="0" column="1">
103
+ <widget class="QLabel" name="label_id">
104
+ <property name="text">
105
+ <string/>
106
+ </property>
107
+ </widget>
108
+ </item>
109
+ <item row="1" column="0">
110
+ <widget class="QLabel" name="label_6">
111
+ <property name="text">
112
+ <string>Status</string>
113
+ </property>
114
+ </widget>
115
+ </item>
116
+ <item row="2" column="0">
117
+ <widget class="QLabel" name="label_5">
118
+ <property name="text">
119
+ <string>Definition</string>
120
+ </property>
121
+ </widget>
122
+ </item>
123
+ <item row="2" column="1">
124
+ <widget class="QTextEdit" name="textEdit_def">
125
+ <property name="readOnly">
126
+ <bool>true</bool>
127
+ </property>
128
+ </widget>
129
+ </item>
130
+ <item row="1" column="1">
131
+ <widget class="QLabel" name="label_status">
132
+ <property name="text">
133
+ <string/>
134
+ </property>
135
+ </widget>
136
+ </item>
137
+ </layout>
138
+ </item>
139
+ </layout>
140
+ </widget>
141
+ <resources/>
142
+ <connections/>
143
+ </ui>