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,638 @@
1
+ import copy
2
+ import importlib.resources
3
+
4
+ import dclab
5
+ import dclab.kde.methods
6
+ import numpy as np
7
+ from PyQt6 import uic, QtCore, QtWidgets
8
+
9
+ from ...pipeline import Plot
10
+ from ...pipeline.plot import STATE_OPTIONS
11
+
12
+ from ..pipeline_plot import (
13
+ compute_contours, compute_contour_opening_angles, compute_contour_reliable)
14
+
15
+ from ..widgets import show_wait_cursor
16
+
17
+ COLORMAPS = STATE_OPTIONS["scatter"]["colormap"]
18
+
19
+
20
+ class PlotPanel(QtWidgets.QWidget):
21
+ #: Emitted when a dcscope.pipeline.Plot is to be changed
22
+ plot_changed = QtCore.pyqtSignal(dict)
23
+ #: Emitted when the pipeline is to be changed
24
+ pipeline_changed = QtCore.pyqtSignal(dict)
25
+
26
+ def __init__(self, *args, **kwargs):
27
+ super(PlotPanel, self).__init__(*args, **kwargs)
28
+ ref = importlib.resources.files(
29
+ "dcscope.gui.analysis") / "ana_plot.ui"
30
+ with importlib.resources.as_file(ref) as path_ui:
31
+ uic.loadUi(path_ui, self)
32
+
33
+ # current DCscope pipeline
34
+ self._pipeline = None
35
+ self._init_controls()
36
+ self.update_content()
37
+
38
+ # options for division
39
+ self.comboBox_division.clear()
40
+ self.comboBox_division.addItem("Merge all plots", "merge")
41
+ self.comboBox_division.addItem("One plot per dataset", "each")
42
+ self.comboBox_division.addItem("Scatter plots and joint contour plot",
43
+ "multiscatter+contour")
44
+ self.comboBox_division.setCurrentIndex(2)
45
+
46
+ # signals
47
+ self.toolButton_duplicate.clicked.connect(self.on_plot_duplicated)
48
+ self.toolButton_remove.clicked.connect(self.on_plot_removed)
49
+ self.pushButton_reset.clicked.connect(self.update_content)
50
+ self.pushButton_apply.clicked.connect(self.write_plot)
51
+ self.comboBox_plots.currentIndexChanged.connect(self.update_content)
52
+ self.comboBox_marker_hue.currentIndexChanged.connect(
53
+ self.on_hue_selected)
54
+ self.comboBox_marker_feature.currentIndexChanged.connect(
55
+ self.on_hue_selected)
56
+ self.comboBox_axis_x.currentIndexChanged.connect(self.on_axis_changed)
57
+ self.comboBox_axis_y.currentIndexChanged.connect(self.on_axis_changed)
58
+ self.comboBox_scale_x.currentIndexChanged.connect(self.on_axis_changed)
59
+ self.comboBox_scale_y.currentIndexChanged.connect(self.on_axis_changed)
60
+ self.spinBox_column_count.valueChanged.connect(
61
+ self.on_column_num_changed)
62
+ self.widget_range_x.range_changed.connect(self.on_range_changed)
63
+ self.widget_range_y.range_changed.connect(self.on_range_changed)
64
+ # automatically set spacing
65
+ self.toolButton_spacing_auto.clicked.connect(self.on_spacing_auto)
66
+
67
+ def read_pipeline_state(self):
68
+ rx = self.widget_range_x.read_pipeline_state()
69
+ ry = self.widget_range_y.read_pipeline_state()
70
+
71
+ # hue min/max
72
+ marker_hue = self.comboBox_marker_hue.currentData()
73
+ if marker_hue == "kde":
74
+ hmin = 0
75
+ hmax = 1
76
+ elif marker_hue == "feature":
77
+ rstate = self.widget_range_feat.read_pipeline_state()
78
+ hmin = rstate["start"]
79
+ hmax = rstate["end"]
80
+ else:
81
+ hmin = hmax = np.nan
82
+
83
+ state = {
84
+ "identifier": self.current_plot.identifier,
85
+ "layout": {
86
+ "column count": self.spinBox_column_count.value(),
87
+ "division": self.comboBox_division.currentData(),
88
+ "label plots": self.checkBox_label_plots.isChecked(),
89
+ "name": self.lineEdit.text(),
90
+ "size x": self.spinBox_size_x.value(),
91
+ "size y": self.spinBox_size_y.value(),
92
+ },
93
+ "general": {
94
+ "auto range": self.checkBox_auto_range.isChecked(),
95
+ "axis x": self.comboBox_axis_x.currentData(),
96
+ "axis y": self.comboBox_axis_y.currentData(),
97
+ "isoelastics": self.checkBox_isoelastics.isChecked(),
98
+ "lut": self.comboBox_lut.currentData(),
99
+ "kde": self.comboBox_kde.currentData(),
100
+ "range x": [rx["start"], rx["end"]],
101
+ "range y": [ry["start"], ry["end"]],
102
+ "scale x": self.comboBox_scale_x.currentData(),
103
+ "scale y": self.comboBox_scale_y.currentData(),
104
+ },
105
+ "scatter": {
106
+ "colormap": self.comboBox_colormap.currentData(),
107
+ "downsample": self.checkBox_downsample.isChecked(),
108
+ "downsampling value": self.spinBox_downsample.value(),
109
+ "enabled": self.groupBox_scatter.isChecked(),
110
+ "hue feature": self.comboBox_marker_feature.currentData(),
111
+ "hue max": hmax,
112
+ "hue min": hmin,
113
+ "marker alpha": self.spinBox_alpha.value() / 100,
114
+ "marker hue": marker_hue,
115
+ "marker size": self.doubleSpinBox_marker_size.value(),
116
+ "show event count": self.checkBox_event_count.isChecked(),
117
+ },
118
+ "contour": {
119
+ "enabled": self.groupBox_contour.isChecked(),
120
+ "legend": self.checkBox_legend.isChecked(),
121
+ "line widths": [self.doubleSpinBox_lw_1.value(),
122
+ self.doubleSpinBox_lw_2.value(),
123
+ ],
124
+ "line styles": [self.comboBox_ls_1.currentData(),
125
+ self.comboBox_ls_2.currentData(),
126
+ ],
127
+ "percentiles": [self.doubleSpinBox_perc_1.value(),
128
+ self.doubleSpinBox_perc_2.value(),
129
+ ],
130
+ "spacing x": self.doubleSpinBox_spacing_x.value(),
131
+ "spacing y": self.doubleSpinBox_spacing_y.value(),
132
+ }
133
+ }
134
+ return state
135
+
136
+ def write_pipeline_state(self, state):
137
+ if self.current_plot.identifier != state["identifier"]:
138
+ raise ValueError("Plot identifier mismatch!")
139
+ toblock = [
140
+ self.comboBox_axis_x,
141
+ self.comboBox_axis_y,
142
+ self.widget_range_x,
143
+ self.widget_range_y,
144
+ ]
145
+
146
+ for b in toblock:
147
+ b.blockSignals(True)
148
+
149
+ # Layout
150
+ lay = state["layout"]
151
+ self.spinBox_column_count.setValue(lay["column count"])
152
+ idx = self.comboBox_division.findData(lay["division"])
153
+ self.comboBox_division.setCurrentIndex(idx)
154
+ self.checkBox_label_plots.setChecked(lay["label plots"])
155
+ self.lineEdit.setText(lay["name"])
156
+ self.spinBox_size_x.setValue(lay["size x"])
157
+ self.spinBox_size_y.setValue(lay["size y"])
158
+ # General
159
+ gen = state["general"]
160
+ self.checkBox_auto_range.setChecked(gen["auto range"])
161
+ self.comboBox_axis_x.setCurrentIndex(
162
+ self.comboBox_axis_x.findData(gen["axis x"]))
163
+ self.comboBox_axis_y.setCurrentIndex(
164
+ self.comboBox_axis_y.findData(gen["axis y"]))
165
+ self.checkBox_isoelastics.setChecked(gen["isoelastics"])
166
+ lut_index = self.comboBox_lut.findData(gen.get("lut", "LE-2D-FEM-19"))
167
+ self.comboBox_lut.setCurrentIndex(lut_index)
168
+ kde_index = self.comboBox_kde.findData(gen["kde"])
169
+ self.comboBox_kde.setCurrentIndex(kde_index)
170
+ scx_index = self.comboBox_scale_x.findData(gen["scale x"])
171
+ self.comboBox_scale_x.setCurrentIndex(scx_index)
172
+ scy_index = self.comboBox_scale_y.findData(gen["scale y"])
173
+ self.comboBox_scale_y.setCurrentIndex(scy_index)
174
+ self._set_range_xy_state(axis_x=gen["axis x"],
175
+ axis_y=gen["axis y"],
176
+ range_x=gen["range x"],
177
+ range_y=gen["range y"],
178
+ )
179
+
180
+ # Scatter
181
+ sca = state["scatter"]
182
+ self.checkBox_downsample.setChecked(sca["downsample"])
183
+ self.spinBox_downsample.setValue(sca["downsampling value"])
184
+ self.groupBox_scatter.setChecked(sca["enabled"])
185
+ hue_index = self.comboBox_marker_hue.findData(sca["marker hue"])
186
+ self.comboBox_marker_hue.setCurrentIndex(hue_index)
187
+ self.doubleSpinBox_marker_size.setValue(sca["marker size"])
188
+ feat_index = self.comboBox_marker_feature.findData(sca["hue feature"])
189
+ feat_index = feat_index or 0
190
+ self.comboBox_marker_feature.setCurrentIndex(feat_index)
191
+ color_index = COLORMAPS.index(sca["colormap"])
192
+ self.comboBox_colormap.setCurrentIndex(color_index)
193
+ self.checkBox_event_count.setChecked(sca["show event count"])
194
+ self.spinBox_alpha.setValue(int(sca["marker alpha"]*100))
195
+ if sca["marker hue"] == "feature":
196
+ self._set_range_feat_state(sca["hue feature"], sca["hue min"],
197
+ sca["hue max"])
198
+
199
+ # Contour
200
+ con = state["contour"]
201
+ self.groupBox_contour.setChecked(con["enabled"])
202
+ self.checkBox_legend.setChecked(con["legend"])
203
+ self.doubleSpinBox_perc_1.setValue(con["percentiles"][0])
204
+ self.doubleSpinBox_perc_2.setValue(con["percentiles"][1])
205
+ self.doubleSpinBox_lw_1.setValue(con["line widths"][0])
206
+ self.doubleSpinBox_lw_2.setValue(con["line widths"][1])
207
+ ls1_index = self.comboBox_ls_1.findData(con["line styles"][0])
208
+ self.comboBox_ls_1.setCurrentIndex(ls1_index)
209
+ ls2_index = self.comboBox_ls_2.findData(con["line styles"][1])
210
+ self.comboBox_ls_2.setCurrentIndex(ls2_index)
211
+ self._set_contour_spacing(spacing_x=con["spacing x"],
212
+ spacing_y=con["spacing y"])
213
+ for b in toblock:
214
+ b.blockSignals(False)
215
+
216
+ def _init_controls(self):
217
+ """All controls that are not subject to change"""
218
+ # LUT
219
+ self.comboBox_lut.clear()
220
+ lut_dict = dclab.features.emodulus.load.get_internal_lut_names_dict()
221
+ for lut_id in lut_dict.keys():
222
+ self.comboBox_lut.addItem(lut_id, lut_id)
223
+ # KDE
224
+ kde_names = STATE_OPTIONS["general"]["kde"]
225
+ self.comboBox_kde.clear()
226
+ for kn in kde_names:
227
+ self.comboBox_kde.addItem(kn.capitalize(), kn)
228
+ # Scales
229
+ scales = STATE_OPTIONS["general"]["scale x"]
230
+ self.comboBox_scale_x.clear()
231
+ self.comboBox_scale_y.clear()
232
+ for sc in scales:
233
+ if sc == "log":
234
+ vc = "logarithmic"
235
+ else:
236
+ vc = sc
237
+ self.comboBox_scale_x.addItem(vc, sc)
238
+ self.comboBox_scale_y.addItem(vc, sc)
239
+ # Marker hue
240
+ hues = STATE_OPTIONS["scatter"]["marker hue"]
241
+ self.comboBox_marker_hue.clear()
242
+ for hue in hues:
243
+ if hue == "kde":
244
+ huev = "KDE"
245
+ else:
246
+ huev = hue.capitalize()
247
+ self.comboBox_marker_hue.addItem(huev, hue)
248
+ self.comboBox_colormap.clear()
249
+ for c in COLORMAPS:
250
+ self.comboBox_colormap.addItem(c, c)
251
+ # Contour line styles
252
+ lstyles = STATE_OPTIONS["contour"]["line styles"][0]
253
+ self.comboBox_ls_1.clear()
254
+ self.comboBox_ls_2.clear()
255
+ for ls in lstyles:
256
+ self.comboBox_ls_1.addItem(ls, ls)
257
+ self.comboBox_ls_2.addItem(ls, ls)
258
+ # range controls
259
+ for rc in [self.widget_range_x, self.widget_range_y,
260
+ self.widget_range_feat]:
261
+ rc.setLabel("")
262
+ rc.setCheckable(False)
263
+ # hide feature label range selection
264
+ self.widget_range_feat.hide()
265
+
266
+ def _set_range_feat_state(self, feat, fmin=None, fmax=None):
267
+ """Set a proper state for the feature hue range control"""
268
+ if len(self.pipeline.slots) == 0:
269
+ self.setEnabled(False)
270
+ # do nothing
271
+ return
272
+ else:
273
+ self.setEnabled(True)
274
+ if feat is not None:
275
+ lim = self.pipeline.get_min_max(
276
+ feat=feat, plot_id=self.current_plot.identifier)
277
+ if not (np.isinf(lim[0]) or np.isinf(lim[1])):
278
+ self.widget_range_feat.setLimits(vmin=lim[0], vmax=lim[1])
279
+ if fmin is None:
280
+ fmin = lim[0]
281
+ if fmax is None:
282
+ fmax = lim[1]
283
+ self.widget_range_feat.write_pipeline_state({"active": True,
284
+ "start": fmin,
285
+ "end": fmax,
286
+ })
287
+
288
+ def _set_range_xy_state(self, axis_x=None, range_x=None,
289
+ axis_y=None, range_y=None):
290
+ """Set a proper state for the x/y range controls"""
291
+ if len(self.pipeline.slots) == 0:
292
+ self.setEnabled(False)
293
+ # do nothing
294
+ return
295
+ else:
296
+ self.setEnabled(True)
297
+
298
+ plot_id = self.current_plot.identifier
299
+
300
+ for axis, rang, rc in zip([axis_x, axis_y],
301
+ [range_x, range_y],
302
+ [self.widget_range_x, self.widget_range_y],
303
+ ):
304
+ if axis is not None:
305
+ lim = self.pipeline.get_min_max(feat=axis, plot_id=plot_id)
306
+ if not (np.isinf(lim[0]) or np.isinf(lim[1])):
307
+ rc.setLimits(vmin=lim[0],
308
+ vmax=lim[1])
309
+ if rang is None or rang[0] == rang[1]:
310
+ # default range is limits + 5% margin
311
+ rang = self.pipeline.get_min_max(feat=axis,
312
+ plot_id=plot_id,
313
+ margin=0.05)
314
+ rc.write_pipeline_state({"active": True,
315
+ "start": rang[0],
316
+ "end": rang[1],
317
+ })
318
+
319
+ def _set_contour_spacing(self, spacing_x=None, spacing_y=None):
320
+ """Set the contour spacing in the spin boxes
321
+
322
+ - sets spinbox limits first
323
+ - sets number of digits
324
+ - sets step
325
+ - sets value in the end
326
+ """
327
+ for spacing, spinBox in zip([spacing_x, spacing_y],
328
+ [self.doubleSpinBox_spacing_x,
329
+ self.doubleSpinBox_spacing_y]):
330
+ if spacing is None or np.isnan(spacing) or spacing == 0:
331
+ continue
332
+ else:
333
+ if spacing >= 1:
334
+ dec = 2
335
+ else:
336
+ dec = -int(np.log10(spacing)) + 3
337
+ spinBox.setDecimals(dec)
338
+ spinBox.setMinimum(10**-dec)
339
+ spinBox.setMaximum(max(10*spacing, 10))
340
+ spinBox.setSingleStep(10**(-dec + 1))
341
+ spinBox.setValue(spacing)
342
+
343
+ def _set_contour_spacing_auto(self, axis_x=None, axis_y=None):
344
+ """automatically set the contour spacing
345
+
346
+ - uses :func:`dclab.kde.methods.bin_width_percentile`
347
+ - uses _set_contour_spacing
348
+
349
+ Not to be confused with `on_spacing_auto`!
350
+ """
351
+ if len(self.pipeline.slots) == 0:
352
+ self.setEnabled(False)
353
+ # do nothing
354
+ return
355
+ else:
356
+ self.setEnabled(True)
357
+ dslist, _ = self.pipeline.get_plot_datasets(
358
+ self.current_plot.identifier)
359
+ if dslist:
360
+ spacings_xy = []
361
+ for axis, scaleCombo in zip([axis_x, axis_y],
362
+ [self.comboBox_scale_x,
363
+ self.comboBox_scale_y]):
364
+ if axis is None:
365
+ # nothing to do
366
+ spacings_xy.append(None)
367
+ else:
368
+ # determine good approximation
369
+ spacings = []
370
+ for ds in dslist:
371
+ spa = ds.get_kde_spacing(
372
+ a=ds[axis],
373
+ feat=axis,
374
+ scale=scaleCombo.currentData(),
375
+ method=dclab.kde.methods.bin_width_percentile,
376
+ )
377
+ spacings.append(spa)
378
+ spacings_xy.append(np.min(spacings))
379
+ spacing_x, spacing_y = spacings_xy
380
+ # sets the limits before setting the value
381
+ self._set_contour_spacing(spacing_x=spacing_x,
382
+ spacing_y=spacing_y)
383
+
384
+ @property
385
+ def current_plot(self):
386
+ if self.plot_ids:
387
+ plot_index = self.comboBox_plots.currentIndex()
388
+ plot_id = self.plot_ids[plot_index]
389
+ plot = Plot.get_instances()[plot_id]
390
+ else:
391
+ plot = None
392
+ return plot
393
+
394
+ @property
395
+ def pipeline(self):
396
+ return self._pipeline
397
+
398
+ @property
399
+ def plot_ids(self):
400
+ """List of plot identifiers"""
401
+ if self.pipeline is not None:
402
+ ids = [plot.identifier for plot in self.pipeline.plots]
403
+ else:
404
+ ids = []
405
+ return ids
406
+
407
+ @property
408
+ def plot_names(self):
409
+ """List of plot names"""
410
+ if self.pipeline is not None:
411
+ ids = [plot.name for plot in self.pipeline.plots]
412
+ else:
413
+ ids = []
414
+ return ids
415
+
416
+ def get_features(self):
417
+ """Wrapper around pipeline with default features if empty"""
418
+ feats_srt = self.pipeline.get_features(
419
+ scalar=True, label_sort=True, plot_id=self.current_plot.identifier)
420
+ if len(feats_srt) == 0:
421
+ # fallback (nothing in the pipeline)
422
+ features = dclab.dfn.scalar_feature_names
423
+ labs = [dclab.dfn.get_feature_label(f) for f in features]
424
+ lf = sorted(zip(labs, features))
425
+ feats_srt = [it[1] for it in lf]
426
+ return feats_srt
427
+
428
+ @QtCore.pyqtSlot()
429
+ def on_axis_changed(self):
430
+ gen = self.read_pipeline_state()["general"]
431
+ if self.sender() == self.comboBox_axis_x:
432
+ self._set_range_xy_state(axis_x=gen["axis x"])
433
+ self._set_contour_spacing_auto(axis_x=gen["axis x"])
434
+ elif self.sender() == self.comboBox_axis_y:
435
+ self._set_range_xy_state(axis_y=gen["axis y"])
436
+ self._set_contour_spacing_auto(axis_y=gen["axis y"])
437
+ elif self.sender() == self.comboBox_scale_x:
438
+ self._set_contour_spacing_auto(axis_x=gen["axis x"])
439
+ elif self.sender() == self.comboBox_scale_y:
440
+ self._set_contour_spacing_auto(axis_y=gen["axis y"])
441
+
442
+ @QtCore.pyqtSlot()
443
+ def on_column_num_changed(self):
444
+ """The user changed the number of columns
445
+
446
+ - increase/decrease self.spinBox_size_x by 150pt
447
+ - increase/decrease self.spinBox_size_y by 150pt if
448
+ the row count changes as well
449
+ """
450
+ # old parameters
451
+ state = self.current_plot.__getstate__()
452
+ plot_id = state["identifier"]
453
+ plot_index = self.pipeline.plot_ids.index(plot_id)
454
+ old_size_x = state["layout"]["size x"]
455
+ old_size_y = state["layout"]["size y"]
456
+ old_ncol, old_nrow = self.pipeline.get_plot_col_row_count(plot_id)
457
+ # new parameters
458
+ new_pipeline_state = self.pipeline.__getstate__()
459
+ new_pipeline_state["plots"][plot_index] = self.read_pipeline_state()
460
+ new_ncol, new_nrow = self.pipeline.get_plot_col_row_count(
461
+ plot_id, new_pipeline_state)
462
+ # size x (minimum of 400)
463
+ new_size_x = max(400, old_size_x + 200*(new_ncol - old_ncol))
464
+ self.spinBox_size_x.setValue(new_size_x)
465
+ # size y
466
+ new_size_y = max(400, old_size_y + 200*(new_nrow - old_nrow))
467
+ self.spinBox_size_y.setValue(new_size_y)
468
+
469
+ @QtCore.pyqtSlot()
470
+ def on_hue_selected(self):
471
+ """Show/hide options for feature-based hue selection"""
472
+ selection = self.comboBox_marker_hue.currentData()
473
+ # hide everything
474
+ self.comboBox_marker_feature.hide()
475
+ self.widget_dataset_alpha.hide()
476
+ self.comboBox_colormap.hide()
477
+ self.label_colormap.hide()
478
+ self.widget_range_feat.hide()
479
+ # Only show feature selection if needed
480
+ if selection == "feature":
481
+ self.comboBox_marker_feature.show()
482
+ self.comboBox_colormap.show()
483
+ self.label_colormap.show()
484
+ self.widget_range_feat.show()
485
+ # set the range
486
+ self._set_range_feat_state(
487
+ feat=self.comboBox_marker_feature.currentData())
488
+ elif selection == "kde":
489
+ self.comboBox_colormap.show()
490
+ self.label_colormap.show()
491
+ elif selection in ["dataset", "none"]:
492
+ self.widget_dataset_alpha.show()
493
+ else:
494
+ raise ValueError("Unknown selection: '{}'".format(selection))
495
+
496
+ @QtCore.pyqtSlot()
497
+ def on_plot_duplicated(self):
498
+ # determine the new filter state
499
+ plot_state = self.read_pipeline_state()
500
+ new_state = copy.deepcopy(plot_state)
501
+ new_plot = Plot()
502
+ new_state["identifier"] = new_plot.identifier
503
+ new_state["layout"]["name"] = new_plot.name
504
+ new_plot.write_pipeline_state(new_state)
505
+ # determine the filter position
506
+ pos = self.pipeline.plot_ids.index(plot_state["identifier"])
507
+ self.pipeline.add_plot(new_plot, index=pos+1)
508
+ state = self.pipeline.__getstate__()
509
+ self.pipeline_changed.emit(state)
510
+
511
+ @QtCore.pyqtSlot()
512
+ def on_plot_removed(self):
513
+ plot_state = self.read_pipeline_state()
514
+ self.pipeline.remove_plot(plot_state["identifier"])
515
+ state = self.pipeline.__getstate__()
516
+ self.pipeline_changed.emit(state)
517
+
518
+ @QtCore.pyqtSlot()
519
+ @show_wait_cursor
520
+ def on_spacing_auto(self):
521
+ """Iteratively find a good spacing for smooth contours (#110)"""
522
+ # https://github.com/DC-analysis/DCscope/issues/110
523
+ plot_id = self.current_plot.identifier
524
+ # Get all datasets belonging to this plot.
525
+ datasets, _ = self.pipeline.get_plot_datasets(plot_id)
526
+ state = self.read_pipeline_state()
527
+ gen = state["general"]
528
+ # initial guess
529
+ # sensible start parameters
530
+ self._set_contour_spacing_auto(axis_x=gen["axis x"],
531
+ axis_y=gen["axis y"])
532
+
533
+ # retrieve state with updated spacings
534
+ state = self.read_pipeline_state()
535
+ phi_conv = np.deg2rad(23)
536
+
537
+ for ii in range(15): # hard-limit is 15 iterations
538
+ # maximum difference of opening angle from 180° [rad]
539
+ max_dphi = 0
540
+ for ds in datasets:
541
+ # Compute the contour for the highest percentile of the plot.
542
+ state["contour"]["percentiles"] = \
543
+ [np.max(state["contour"]["percentiles"])]
544
+ cc = compute_contours(plot_state=state, rtdc_ds=ds)[0][0]
545
+ if not compute_contour_reliable(
546
+ plot_state=state, contour=cc, thresh_ang=phi_conv):
547
+ # Compute the opening angle for each point of the cnotour
548
+ # and take the point with the largest opening angle.
549
+ angles = compute_contour_opening_angles(
550
+ plot_state=state, contour=cc)
551
+ dphi = np.max(np.abs(angles))
552
+ max_dphi = max(max_dphi, np.abs(dphi))
553
+ if max_dphi <= phi_conv:
554
+ # Normal stopping criterion (opening angle <= 23°)
555
+ break
556
+ else:
557
+ # If the absolute opening angle is too large,
558
+ # we assume that we have to reduce the spacing.
559
+ state["contour"]["spacing x"] /= 2
560
+ state["contour"]["spacing y"] /= 2
561
+ else:
562
+ raise ValueError(
563
+ "Could not automatically determine contour spacing")
564
+
565
+ # set the final spacing
566
+ new_state = self.read_pipeline_state()
567
+ new_state["contour"]["spacing x"] = state["contour"]["spacing x"]
568
+ new_state["contour"]["spacing y"] = state["contour"]["spacing y"]
569
+ self.write_pipeline_state(new_state)
570
+
571
+ @QtCore.pyqtSlot()
572
+ def on_range_changed(self):
573
+ """User changed x/y range -> disable auto range checkbox"""
574
+ self.checkBox_auto_range.setChecked(False)
575
+
576
+ def show_plot(self, plot_id):
577
+ self.update_content(plot_index=self.plot_ids.index(plot_id))
578
+
579
+ def set_pipeline(self, pipeline):
580
+ self._pipeline = pipeline
581
+
582
+ def update_content(self, plot_index=None, **kwargs):
583
+ if self.plot_ids:
584
+ # remember the previous plot index and make sure it is sane
585
+ prev_index = self.comboBox_plots.currentIndex()
586
+ if prev_index is None or prev_index < 0:
587
+ prev_index = len(self.plot_ids) - 1
588
+
589
+ self.setEnabled(True)
590
+ # update combobox
591
+ self.comboBox_plots.blockSignals(True)
592
+ # this also updates the combobox
593
+ if plot_index is None or plot_index < 0:
594
+ plot_index = prev_index
595
+ plot_index = min(plot_index, len(self.plot_ids) - 1)
596
+
597
+ self.comboBox_plots.clear()
598
+ self.comboBox_plots.addItems(self.plot_names)
599
+ self.comboBox_plots.setCurrentIndex(plot_index)
600
+ self.comboBox_plots.blockSignals(False)
601
+ # set choices for all comboboxes that deal with features
602
+ for cb in [self.comboBox_axis_x,
603
+ self.comboBox_axis_y,
604
+ self.comboBox_marker_feature]:
605
+ # get the features currently available
606
+ feats_srt = self.get_features()
607
+ cb.blockSignals(True)
608
+ # remember previous selection if possible
609
+ if cb.count:
610
+ # remember current selection
611
+ curfeat = cb.currentData()
612
+ if curfeat not in feats_srt:
613
+ curfeat = None
614
+ else:
615
+ curfeat = None
616
+ # repopulate
617
+ cb.clear()
618
+ for feat in feats_srt:
619
+ cb.addItem(dclab.dfn.get_feature_label(feat), feat)
620
+ if curfeat is not None:
621
+ # write back current selection
622
+ curidx = cb.findData(curfeat)
623
+ cb.setCurrentIndex(curidx)
624
+ cb.blockSignals(False)
625
+ # populate content
626
+ plot = Plot.get_plot(identifier=self.plot_ids[plot_index])
627
+ state = plot.__getstate__()
628
+ self.write_pipeline_state(state)
629
+ else:
630
+ self.setEnabled(False)
631
+
632
+ def write_plot(self):
633
+ """Update the dcscope.pipeline.Plot instance"""
634
+ # get current index
635
+ plot_state = self.read_pipeline_state()
636
+ # this signal will update the main pipeline which will trigger
637
+ # a call to `set_pipeline` and `update_content`.
638
+ self.plot_changed.emit(plot_state)