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
@@ -0,0 +1,284 @@
1
+ import numpy as np
2
+ from PyQt6 import QtCore
3
+ import pyqtgraph as pg
4
+ from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
5
+
6
+ from ... import plot_cache
7
+
8
+ from .. import pipeline_plot
9
+ from ..widgets import SimplePlotWidget, SimpleViewBox
10
+
11
+
12
+ class QuickViewScatterWidget(SimplePlotWidget):
13
+ update_hover_pos = QtCore.pyqtSignal(QtCore.QPointF)
14
+
15
+ def __init__(self, *args, **kwargs):
16
+ self._view_box = QuickViewViewBox()
17
+ super(QuickViewScatterWidget, self).__init__(viewBox=self._view_box,
18
+ *args, **kwargs)
19
+ self._view_box.update_hover_pos.connect(self.update_hover_pos)
20
+ self.scatter = RTDCScatterPlot()
21
+ self.select = pg.PlotDataItem(x=[1], y=[2], symbol="o")
22
+ #: List of isoelasticity line plots
23
+ self.isoelastics = []
24
+ self.addItem(self.scatter)
25
+ self.addItem(self.select)
26
+ self.select.hide()
27
+ self.xscale = "linear"
28
+ self.yscale = "linear"
29
+ self.kde_type = "none",
30
+ self.kde_kwargs = {}
31
+ self.hue_type = "none"
32
+ self.hue_kwargs = {}
33
+ #: Boolean array identifying the plotted events w.r.t. the full
34
+ #: dataset
35
+ self.events_plotted = None
36
+ #: Unfiltered and not-downsampled x component of current scatter plot
37
+ self.data_x = None
38
+ #: Unfiltered and not-downsampled y component of current scatter plot
39
+ self.data_y = None
40
+
41
+ # polygon editing ROI
42
+ self.poly_line_roi = None
43
+
44
+ # Signals for mouse click
45
+ # let view box update the selected event in the scatter plot
46
+ self._view_box.set_scatter_point.connect(self.scatter.set_point)
47
+ # let view box update self.poly_line_roi
48
+ self._view_box.add_poly_vertex.connect(self.add_poly_vertex)
49
+
50
+ def activate_poly_mode(self, points=None):
51
+ if points is None:
52
+ points = []
53
+ if self.poly_line_roi is None:
54
+ self.poly_line_roi = pg.PolyLineROI([], closed=True)
55
+ self.poly_line_roi.setPen("k")
56
+ self.addItem(self.poly_line_roi)
57
+ if len(points):
58
+ mode = "poly-modify"
59
+ self.set_poly_points(points)
60
+ else:
61
+ mode = "poly-create"
62
+ self.set_mouse_click_mode(mode)
63
+ return self.poly_line_roi
64
+
65
+ def activate_scatter_mode(self):
66
+ if self.poly_line_roi is not None:
67
+ self.removeItem(self.poly_line_roi)
68
+ self.poly_line_roi = None
69
+ self.set_mouse_click_mode("scatter")
70
+
71
+ def add_poly_vertex(self, pos):
72
+ state = self.poly_line_roi.getState()
73
+ state["points"].append([pos.x(), pos.y()])
74
+ self.poly_line_roi.setState(state)
75
+
76
+ def get_poly_points(self):
77
+ if self.poly_line_roi is None:
78
+ raise ValueError("No polygon selection active!")
79
+ state = self.poly_line_roi.getState()
80
+ points = np.array([[p.x(), p.y()] for p in state["points"]])
81
+ # Take into account manual movements of the entire ROI (issue #115)
82
+ points[:, 0] += state["pos"][0]
83
+ points[:, 1] += state["pos"][1]
84
+ if self.xscale == "log":
85
+ points[:, 0] = 10**points[:, 0]
86
+ if self.yscale == "log":
87
+ points[:, 1] = 10**points[:, 1]
88
+ return points
89
+
90
+ def plot_data(self, rtdc_ds, slot, xax="area_um", yax="deform",
91
+ xscale="linear", yscale="linear", downsample=False,
92
+ hue_type="none", hue_kwargs=None, isoelastics=False,
93
+ lut_identifier=None):
94
+ self.rtdc_ds = rtdc_ds
95
+ self.slot = slot
96
+ self.xax = xax
97
+ self.yax = yax
98
+ self.xscale = xscale
99
+ self.yscale = yscale
100
+ self.hue_type = hue_type
101
+ self.hue_kwargs = hue_kwargs if hue_kwargs else {}
102
+ if hue_type != "kde":
103
+ self.kde_type = "none"
104
+ self.kde_kwargs = {}
105
+ else:
106
+ self.kde_type = hue_kwargs["kde_type"]
107
+ self.kde_kwargs = hue_kwargs.get("kde_kwargs")
108
+ x, y, kde, idx = plot_cache.get_scatter_data(
109
+ rtdc_ds=self.rtdc_ds,
110
+ downsample=downsample,
111
+ xax=self.xax,
112
+ yax=self.yax,
113
+ xscale=self.xscale,
114
+ yscale=self.yscale,
115
+ kde_type=self.kde_type,
116
+ kde_kwargs=self.kde_kwargs)
117
+ self.events_plotted = idx
118
+ #: unfiltered x data
119
+ self.data_x = self.rtdc_ds[self.xax]
120
+ #: unfiltered y data
121
+ self.data_y = self.rtdc_ds[self.yax]
122
+ if self.hue_type == "none":
123
+ brush = "k"
124
+ else:
125
+ # define colormap
126
+ brush = []
127
+ cmap = pg.ColorMap(*zip(*Gradients["viridis"]["ticks"]))
128
+ if self.hue_type == "kde":
129
+ for k in kde:
130
+ brush.append(cmap.mapToQColor(k))
131
+ elif self.hue_type == "feature":
132
+ fdata = self.rtdc_ds[self.hue_kwargs["feat"]][idx]
133
+ fdata -= fdata.min()
134
+ fdata = np.array(fdata, dtype=float) # cast int to float
135
+ fdata /= fdata.max()
136
+ for f in fdata:
137
+ brush.append(cmap.mapToQColor(f))
138
+
139
+ if x.size: # test for empty x/y (#37)
140
+ # set viewbox
141
+ pipeline_plot.set_viewbox(plot=self,
142
+ range_x=(x.min(), x.max()),
143
+ range_y=(y.min(), y.max()),
144
+ scale_x=self.xscale,
145
+ scale_y=self.yscale,
146
+ padding=0.05)
147
+ # set data
148
+ self.setData(x, y, brush=brush)
149
+ # set axes labels (replace with user-defined flourescence names)
150
+ left = pipeline_plot.get_axis_label_from_feature(
151
+ self.yax, slot_state=self.slot.__getstate__())
152
+ bottom = pipeline_plot.get_axis_label_from_feature(
153
+ self.xax, slot_state=self.slot.__getstate__())
154
+ self.plotItem.setLabels(left=left, bottom=bottom)
155
+
156
+ # Force updating the plot item size, otherwise axes labels
157
+ # may have an offset.
158
+ s = self.plotItem.size()
159
+ self.plotItem.resize(s.width()+1, s.height())
160
+ self.plotItem.resize(s)
161
+
162
+ # Isoelastics
163
+ # remove old isoelastics
164
+ for lp in self.isoelastics:
165
+ self.removeItem(lp)
166
+ if isoelastics:
167
+ cfg = self.rtdc_ds.config
168
+ self.isoelastics = pipeline_plot.add_isoelastics(
169
+ plot_item=self.plotItem,
170
+ axis_x=self.xax,
171
+ axis_y=self.yax,
172
+ channel_width=cfg["setup"]["channel width"],
173
+ pixel_size=cfg["imaging"]["pixel size"],
174
+ lut_identifier=lut_identifier)
175
+
176
+ def set_mouse_click_mode(self, mode):
177
+ allowed = ["scatter", "poly-create", "poly-modify"]
178
+ if mode not in allowed:
179
+ raise ValueError("Invalid mouse mode: {}, ".format(mode)
180
+ + "expected one of {}".format(allowed))
181
+ if mode in ["poly-create", "poly-modify"]:
182
+ if self.poly_line_roi is None:
183
+ raise ValueError("Please set self.poly_line_roi before "
184
+ + "setting the click mode!")
185
+ self._view_box.mode = mode
186
+
187
+ def set_poly_points(self, points):
188
+ if self.poly_line_roi is None:
189
+ raise ValueError("No polygon selection active!")
190
+ points = np.array(points, copy=True)
191
+ if points.size:
192
+ if self.xscale == "log":
193
+ points[:, 0] = np.log10(points[:, 0])
194
+ if self.yscale == "log":
195
+ points[:, 1] = np.log10(points[:, 1])
196
+ state = self.poly_line_roi.getState()
197
+ state["points"] = points.tolist()
198
+ self.poly_line_roi.setState(state)
199
+
200
+ def setData(self, x, y, **kwargs):
201
+ # convert to log-scale if applicable
202
+ if self.xscale == "log":
203
+ x = np.log10(x)
204
+ if self.yscale == "log":
205
+ y = np.log10(y)
206
+ # set data
207
+ self.scatter.setData(x=x, y=y, **kwargs)
208
+
209
+ def setSelection(self, event_index):
210
+ x = self.data_x[event_index]
211
+ y = self.data_y[event_index]
212
+ self.select.setData([x], [y])
213
+
214
+
215
+ class QuickViewViewBox(SimpleViewBox):
216
+ set_scatter_point = QtCore.pyqtSignal(QtCore.QPointF)
217
+ add_poly_vertex = QtCore.pyqtSignal(QtCore.QPointF)
218
+ update_hover_pos = QtCore.pyqtSignal(QtCore.QPointF)
219
+
220
+ def __init__(self, *args, **kwargs):
221
+ super(QuickViewViewBox, self).__init__(*args, **kwargs)
222
+ self.mode = "scatter"
223
+
224
+ #: allowed right-click menu options with new name
225
+ self.right_click_actions["View All"] = "View All Content"
226
+ self.right_click_actions["Mouse Mode"] = "Change Mouse mode"
227
+
228
+ def mouseClickEvent(self, ev):
229
+ if ev.button() == QtCore.Qt.MouseButton.LeftButton:
230
+ pos = self.mapToView(ev.pos())
231
+ if self.mode == "scatter":
232
+ self.set_scatter_point.emit(pos)
233
+ elif self.mode == "poly-create":
234
+ self.add_poly_vertex.emit(pos)
235
+ ev.accept()
236
+ else:
237
+ # right mouse button shows menu
238
+ super(QuickViewViewBox, self).mouseClickEvent(ev)
239
+
240
+ def hoverEvent(self, ev):
241
+ if hasattr(ev, "_scenePos"):
242
+ pos = self.mapToView(ev.pos())
243
+ self.update_hover_pos.emit(pos)
244
+
245
+
246
+ class RTDCScatterPlot(pg.ScatterPlotItem):
247
+ def __init__(self, size=3, pen=None, brush=None, *args, **kwargs):
248
+ if pen is None:
249
+ pen = pg.mkPen(color=(0, 0, 0, 0))
250
+ if brush is None:
251
+ brush = pg.mkBrush("k")
252
+ super(RTDCScatterPlot, self).__init__(size=size,
253
+ pen=pen,
254
+ brush=brush,
255
+ symbol="s",
256
+ *args,
257
+ **kwargs)
258
+ self.setData(x=range(10), y=range(10), brush=brush)
259
+
260
+ def pointAt(self, pos):
261
+ """Unlike `ScatterPlotItem.pointsAt`, return the closest point"""
262
+ x = pos.x()
263
+ y = pos.y()
264
+
265
+ pw = self.pixelWidth()
266
+ ph = self.pixelHeight()
267
+
268
+ # compute the distances of all points to x and y
269
+ dists = np.abs((self.data["x"] - x)/pw) \
270
+ + np.abs((self.data["y"] - y)/ph)
271
+ ide = np.argmin(dists)
272
+
273
+ # calling `self.points` populates the data["item"] column.
274
+ return self.points()[ide]
275
+
276
+ def set_point(self, view_pos):
277
+ pos = self.mapFromView(view_pos)
278
+ pt = self.pointAt(pos)
279
+ self.ptClicked = pt
280
+ self.sigClicked.emit(self, self.ptClicked, None)
281
+
282
+ def mouseClickEvent(self, ev):
283
+ """Override that does not handle events"""
284
+ ev.ignore() # clicks are handles by CustomViewBox
@@ -0,0 +1,10 @@
1
+ QGroupBox {
2
+ border: 1px solid #E0E0E0;
3
+ border-radius: 0px;
4
+ margin-top: 1em;
5
+ }
6
+
7
+ QGroupBox::title {
8
+ padding-top: -1.5em;
9
+ padding-left: 0px;
10
+ }
dcscope/gui/update.py ADDED
@@ -0,0 +1,90 @@
1
+ import json
2
+ import os
3
+ import struct
4
+ import sys
5
+ import traceback
6
+ import urllib.request
7
+
8
+ from dclab.external.packaging import parse as parse_version
9
+ from PyQt6 import QtCore
10
+
11
+
12
+ class UpdateWorker(QtCore.QObject):
13
+ finished = QtCore.pyqtSignal()
14
+ data_ready = QtCore.pyqtSignal(dict)
15
+
16
+ @QtCore.pyqtSlot(str, str)
17
+ def processUpdate(self, version, ghrepo):
18
+ mdict = check_release(ghrepo, version)
19
+ if mdict["update available"]:
20
+ self.data_ready.emit(mdict)
21
+ self.finished.emit()
22
+
23
+
24
+ def check_for_update(version, ghrepo):
25
+ thread = QtCore.QThread()
26
+ obj = UpdateWorker()
27
+ obj.moveToThread(thread)
28
+ obj.finished.connect(thread.quit)
29
+ thread.start()
30
+
31
+ QtCore.QMetaObject.invokeMethod(obj, 'processUpdate',
32
+ QtCore.Qt.ConnectionType.QueuedConnection,
33
+ QtCore.Q_ARG(str, version),
34
+ QtCore.Q_ARG(str, ghrepo),
35
+ )
36
+
37
+
38
+ def check_release(ghrepo="user/repo", version=None, timeout=20):
39
+ """Check GitHub repository for latest release"""
40
+ url = "https://api.github.com/repos/{}/releases/latest".format(ghrepo)
41
+ if "GITHUB_TOKEN" in os.environ:
42
+ hdr = {'authorization': os.environ["GITHUB_TOKEN"]}
43
+ else:
44
+ hdr = {}
45
+ web = "https://github.com/{}/releases".format(ghrepo)
46
+ errors = None # error messages (str)
47
+ update = False # whether an update is available
48
+ binary = None # download link to binary file
49
+ new_version = None # string identifying new version
50
+ try:
51
+ req = urllib.request.Request(url, headers=hdr)
52
+ data = urllib.request.urlopen(req, timeout=timeout).read()
53
+ except BaseException:
54
+ errors = traceback.format_exc()
55
+ else:
56
+ j = json.loads(data)
57
+
58
+ newversion = j["tag_name"]
59
+
60
+ if version is not None:
61
+ new = parse_version(newversion)
62
+ old = parse_version(version)
63
+ if new > old:
64
+ update = True
65
+ new_version = newversion
66
+ if hasattr(sys, "frozen"):
67
+ # determine which binary URL we need
68
+ if sys.platform == "win32":
69
+ nbit = 8 * struct.calcsize("P")
70
+ if nbit == 32:
71
+ dlid = "win_32bit_setup.exe"
72
+ else:
73
+ dlid = "win_64bit_setup.exe"
74
+ elif sys.platform == "darwin":
75
+ dlid = ".pkg"
76
+ else:
77
+ dlid = False
78
+ # search for binary download file
79
+ if dlid:
80
+ for a in j["assets"]:
81
+ if a["browser_download_url"].count(dlid):
82
+ binary = a["browser_download_url"]
83
+ break
84
+ mdict = {"releases url": web,
85
+ "binary url": binary,
86
+ "version": new_version,
87
+ "update available": update,
88
+ "errors": errors,
89
+ }
90
+ return mdict
@@ -0,0 +1,15 @@
1
+ # flake8: noqa: F401
2
+ from .bg_thread import run_async
3
+ from .double_spin_box_nan import DoubleSpinBoxNan
4
+ from .feature_combobox import FeatureComboBox
5
+ from .get_path import get_directory
6
+ from .key_value_table_widget import KeyValueTableWidget
7
+ from .mdi_subwindow_wo_close import MDISubWindowWOButtons
8
+ from .qrangeslider import QRangeSlider
9
+ from .rangecontrol import RangeControl
10
+ from .simple_image_view import SimpleImageView
11
+ from .simple_plot_widget import (SimplePlotItem,
12
+ SimplePlotWidget,
13
+ SimpleViewBox)
14
+ from .so_colorbaritem import DCscopeColorBarItem
15
+ from .wait_cursor import show_wait_cursor, ShowWaitCursor
@@ -0,0 +1,29 @@
1
+ """https://stackoverflow.com/questions/39304951/"""
2
+ from functools import wraps
3
+
4
+ from PyQt6 import QtCore
5
+
6
+
7
+ class Runner(QtCore.QThread):
8
+ """Runs a function in the background"""
9
+
10
+ def __init__(self, target, *args, **kwargs):
11
+ super().__init__(*args, **kwargs)
12
+ self._target = target
13
+ self._args = args
14
+ self._kwargs = kwargs
15
+
16
+ def run(self):
17
+ self._target(*self._args, **self._kwargs)
18
+
19
+
20
+ def run_async(func):
21
+ """Decorator for running a function in the background"""
22
+ @wraps(func)
23
+ def async_func(*args, **kwargs):
24
+ runner = Runner(func, *args, **kwargs)
25
+ # Keep the runner somewhere or it will be destroyed
26
+ func.__runner = runner
27
+ runner.start()
28
+
29
+ return async_func
@@ -0,0 +1,79 @@
1
+ import importlib.resources
2
+
3
+ from PyQt6 import uic, QtCore, QtWidgets
4
+
5
+
6
+ class BulkList(QtWidgets.QWidget):
7
+
8
+ def __init__(self, parent, title=None, items=None, *args, **kwargs):
9
+ """A checkable list with bulk (de-)selection button"""
10
+ super(BulkList, self).__init__(parent=parent, *args, **kwargs)
11
+ ref = importlib.resources.files(
12
+ "dcscope.gui.widgets") / "bulk_list.ui"
13
+ with importlib.resources.as_file(ref) as path_ui:
14
+ uic.loadUi(path_ui, self)
15
+
16
+ if title is not None:
17
+ self.set_title(title)
18
+
19
+ if items is not None:
20
+ self.set_items(items)
21
+
22
+ # select none by default
23
+ self.on_select_none()
24
+
25
+ # signals
26
+ self.toolButton_all.clicked.connect(self.on_select_all)
27
+ self.toolButton_none.clicked.connect(self.on_select_none)
28
+
29
+ def get_selection(self):
30
+ items = []
31
+ for ii in range(self.listWidget.count()):
32
+ wid = self.listWidget.item(ii)
33
+ if wid.checkState() == QtCore.Qt.CheckState.Checked:
34
+ items.append(wid.data(101))
35
+ return items
36
+
37
+ def set_items(self, items, labels=None):
38
+ """Set the items of the list widget
39
+
40
+ Parameters
41
+ ----------
42
+ items: list
43
+ A list of the items in the list. If `labels` is
44
+ None then this must be a list of strings. This
45
+ is what is returned by `get_selection`.
46
+ labels: list of str
47
+ If set, use these strings as placeholders in the
48
+ list widget.
49
+ """
50
+ if labels is None:
51
+ labels = items
52
+ self.listWidget.clear()
53
+ for item, label in zip(items, labels):
54
+ wid = QtWidgets.QListWidgetItem(label)
55
+ wid.setData(101, item)
56
+ wid.setCheckState(QtCore.Qt.CheckState.Unchecked)
57
+ self.listWidget.addItem(wid)
58
+
59
+ def set_title(self, title):
60
+ """Set the title of the group box"""
61
+ self.groupBox.setTitle(title)
62
+
63
+ @QtCore.pyqtSlot()
64
+ def on_select_all(self):
65
+ """Select all items"""
66
+ self.toolButton_none.setVisible(True)
67
+ self.toolButton_all.setVisible(False)
68
+ for ii in range(self.listWidget.count()):
69
+ wid = self.listWidget.item(ii)
70
+ wid.setCheckState(QtCore.Qt.CheckState.Checked)
71
+
72
+ @QtCore.pyqtSlot()
73
+ def on_select_none(self):
74
+ """Deselect all items"""
75
+ self.toolButton_none.setVisible(False)
76
+ self.toolButton_all.setVisible(True)
77
+ for ii in range(self.listWidget.count()):
78
+ wid = self.listWidget.item(ii)
79
+ wid.setCheckState(QtCore.Qt.CheckState.Unchecked)
@@ -0,0 +1,95 @@
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>400</width>
10
+ <height>300</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Form</string>
15
+ </property>
16
+ <layout class="QVBoxLayout" name="verticalLayout">
17
+ <property name="leftMargin">
18
+ <number>0</number>
19
+ </property>
20
+ <property name="topMargin">
21
+ <number>0</number>
22
+ </property>
23
+ <property name="rightMargin">
24
+ <number>0</number>
25
+ </property>
26
+ <property name="bottomMargin">
27
+ <number>0</number>
28
+ </property>
29
+ <item>
30
+ <widget class="QGroupBox" name="groupBox">
31
+ <property name="sizePolicy">
32
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
33
+ <horstretch>0</horstretch>
34
+ <verstretch>0</verstretch>
35
+ </sizepolicy>
36
+ </property>
37
+ <property name="title">
38
+ <string>List content</string>
39
+ </property>
40
+ <property name="checkable">
41
+ <bool>false</bool>
42
+ </property>
43
+ <layout class="QVBoxLayout" name="verticalLayout_2">
44
+ <item>
45
+ <widget class="QListWidget" name="listWidget"/>
46
+ </item>
47
+ <item>
48
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
49
+ <item>
50
+ <widget class="QLabel" name="label_help_selection">
51
+ <property name="text">
52
+ <string>&lt;a href=&quot;https://dcscope.readthedocs.io/en/stable/sec_qg_export_data.html#sec-qg-export-data-faq&quot;&gt;Why are not all selected?&lt;/a&gt;</string>
53
+ </property>
54
+ <property name="openExternalLinks">
55
+ <bool>true</bool>
56
+ </property>
57
+ </widget>
58
+ </item>
59
+ <item>
60
+ <spacer name="horizontalSpacer">
61
+ <property name="orientation">
62
+ <enum>Qt::Horizontal</enum>
63
+ </property>
64
+ <property name="sizeHint" stdset="0">
65
+ <size>
66
+ <width>40</width>
67
+ <height>20</height>
68
+ </size>
69
+ </property>
70
+ </spacer>
71
+ </item>
72
+ <item>
73
+ <widget class="QToolButton" name="toolButton_none">
74
+ <property name="text">
75
+ <string>select none</string>
76
+ </property>
77
+ </widget>
78
+ </item>
79
+ <item>
80
+ <widget class="QToolButton" name="toolButton_all">
81
+ <property name="text">
82
+ <string>select all</string>
83
+ </property>
84
+ </widget>
85
+ </item>
86
+ </layout>
87
+ </item>
88
+ </layout>
89
+ </widget>
90
+ </item>
91
+ </layout>
92
+ </widget>
93
+ <resources/>
94
+ <connections/>
95
+ </ui>
@@ -0,0 +1,75 @@
1
+ import numpy as np
2
+ from PyQt6 import QtWidgets, QtGui
3
+
4
+
5
+ class DoubleSpinBoxNan(QtWidgets.QDoubleSpinBox):
6
+ """A doubleSpinBox that uses minimum() and maximum() as np.nan"""
7
+
8
+ def __init__(self, *args, **kwargs):
9
+ super(DoubleSpinBoxNan, self).__init__(*args, **kwargs)
10
+ self._suffix = self.suffix() # remember initial suffix
11
+ self.validator = NanFloatValidator()
12
+
13
+ def validate(self, text, position):
14
+ return self.validator.validate(text, position, self.suffix())
15
+
16
+ def value(self):
17
+ value = super(DoubleSpinBoxNan, self).value()
18
+ if value == self.minimum() or value == self.maximum():
19
+ value = np.nan
20
+ return value
21
+
22
+ def valueFromText(self, text):
23
+ if text == "nan":
24
+ return np.nan
25
+ else:
26
+ return convert_string_to_nanfloat(text[:-len(self.suffix())])
27
+
28
+ def textFromValue(self, value):
29
+ if value == self.minimum() or value == self.maximum():
30
+ return "nan"
31
+ else:
32
+ return str(value)
33
+
34
+
35
+ class NanFloatValidator(QtGui.QValidator):
36
+ def validate(self, text, position, suffix):
37
+ string = text[:-len(suffix)]
38
+ if string in ["n", "na", "nan"]:
39
+ text = "nan"
40
+ if valid_nanfloat_string(string):
41
+ return self.State.Acceptable, text, position
42
+ elif string == "":
43
+ return self.State.Intermediate, text, position
44
+ return self.State.Invalid, text, position
45
+
46
+ def fixup(self, text):
47
+ try:
48
+ val = convert_string_to_nanfloat(text)
49
+ except ValueError:
50
+ val = ""
51
+ return str(val)
52
+
53
+
54
+ def valid_nanfloat_string(string):
55
+ try:
56
+ convert_string_to_nanfloat(string)
57
+ except ValueError:
58
+ valid = False
59
+ else:
60
+ valid = True
61
+ return valid
62
+
63
+
64
+ def convert_string_to_nanfloat(string):
65
+ try:
66
+ val = float(string)
67
+ except ValueError:
68
+ string = string.strip()
69
+ for iid in ["n", "na", "nan"]:
70
+ if string.startswith(iid):
71
+ val = np.nan
72
+ break
73
+ else:
74
+ raise ValueError("Not a valid nan-float!")
75
+ return val