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.
- dcscope/__init__.py +17 -0
- dcscope/__main__.py +44 -0
- dcscope/_version.py +21 -0
- dcscope/extensions.py +250 -0
- dcscope/gui/__init__.py +2 -0
- dcscope/gui/analysis/__init__.py +10 -0
- dcscope/gui/analysis/ana_basins.py +110 -0
- dcscope/gui/analysis/ana_basins.ui +143 -0
- dcscope/gui/analysis/ana_filter.py +341 -0
- dcscope/gui/analysis/ana_filter.ui +364 -0
- dcscope/gui/analysis/ana_log.py +122 -0
- dcscope/gui/analysis/ana_log.ui +100 -0
- dcscope/gui/analysis/ana_meta.py +207 -0
- dcscope/gui/analysis/ana_meta.ui +141 -0
- dcscope/gui/analysis/ana_plot.py +638 -0
- dcscope/gui/analysis/ana_plot.ui +1060 -0
- dcscope/gui/analysis/ana_slot.py +504 -0
- dcscope/gui/analysis/ana_slot.ui +684 -0
- dcscope/gui/analysis/ana_tables.py +227 -0
- dcscope/gui/analysis/ana_tables.ui +195 -0
- dcscope/gui/analysis/ana_view.py +69 -0
- dcscope/gui/analysis/ana_view.ui +269 -0
- dcscope/gui/analysis/dlg_slot_reorder.py +55 -0
- dcscope/gui/analysis/dlg_slot_reorder.ui +138 -0
- dcscope/gui/bulk/__init__.py +2 -0
- dcscope/gui/bulk/bulk_emodulus.py +200 -0
- dcscope/gui/bulk/bulk_emodulus.ui +245 -0
- dcscope/gui/compute/__init__.py +3 -0
- dcscope/gui/compute/comp_lme4.py +115 -0
- dcscope/gui/compute/comp_lme4.ui +194 -0
- dcscope/gui/compute/comp_lme4_dataset.py +51 -0
- dcscope/gui/compute/comp_lme4_dataset.ui +92 -0
- dcscope/gui/compute/comp_lme4_results.py +120 -0
- dcscope/gui/compute/comp_lme4_results.ui +268 -0
- dcscope/gui/compute/comp_stats.py +223 -0
- dcscope/gui/compute/comp_stats.ui +187 -0
- dcscope/gui/dcor/__init__.py +304 -0
- dcscope/gui/dcor/dcor.ui +118 -0
- dcscope/gui/export/__init__.py +3 -0
- dcscope/gui/export/e2data.py +394 -0
- dcscope/gui/export/e2data.ui +367 -0
- dcscope/gui/export/e2filter.py +76 -0
- dcscope/gui/export/e2filter.ui +111 -0
- dcscope/gui/export/e2plot.py +94 -0
- dcscope/gui/export/e2plot.ui +175 -0
- dcscope/gui/main.py +1089 -0
- dcscope/gui/main.ui +579 -0
- dcscope/gui/matrix/__init__.py +4 -0
- dcscope/gui/matrix/block_matrix.py +141 -0
- dcscope/gui/matrix/block_matrix.ui +207 -0
- dcscope/gui/matrix/data_matrix.py +574 -0
- dcscope/gui/matrix/dm_dataset.py +116 -0
- dcscope/gui/matrix/dm_dataset.ui +348 -0
- dcscope/gui/matrix/dm_element.py +111 -0
- dcscope/gui/matrix/dm_element.ui +169 -0
- dcscope/gui/matrix/dm_filter.py +115 -0
- dcscope/gui/matrix/dm_filter.ui +287 -0
- dcscope/gui/matrix/plot_matrix.py +316 -0
- dcscope/gui/matrix/pm_element.py +39 -0
- dcscope/gui/matrix/pm_plot.py +86 -0
- dcscope/gui/matrix/pm_plot.ui +249 -0
- dcscope/gui/pipeline_plot.py +797 -0
- dcscope/gui/pipeline_plot.ui +66 -0
- dcscope/gui/preferences.py +380 -0
- dcscope/gui/preferences.ui +554 -0
- dcscope/gui/quick_view/__init__.py +1 -0
- dcscope/gui/quick_view/qv_main.py +1072 -0
- dcscope/gui/quick_view/qv_main.ui +1297 -0
- dcscope/gui/quick_view/qv_scatter.py +284 -0
- dcscope/gui/quick_view/qv_style.css +10 -0
- dcscope/gui/update.py +90 -0
- dcscope/gui/widgets/__init__.py +15 -0
- dcscope/gui/widgets/bg_thread.py +29 -0
- dcscope/gui/widgets/bulk_list.py +79 -0
- dcscope/gui/widgets/bulk_list.ui +95 -0
- dcscope/gui/widgets/double_spin_box_nan.py +75 -0
- dcscope/gui/widgets/feature_combobox.py +140 -0
- dcscope/gui/widgets/get_path.py +42 -0
- dcscope/gui/widgets/key_value_table_widget.css +12 -0
- dcscope/gui/widgets/key_value_table_widget.py +75 -0
- dcscope/gui/widgets/mdi_subwindow_wo_close.py +12 -0
- dcscope/gui/widgets/qrangeslider.py +262 -0
- dcscope/gui/widgets/rangecontrol.py +308 -0
- dcscope/gui/widgets/rangecontrol.ui +136 -0
- dcscope/gui/widgets/simple_image_view.py +55 -0
- dcscope/gui/widgets/simple_plot_widget.py +113 -0
- dcscope/gui/widgets/so_colorbaritem.py +29 -0
- dcscope/gui/widgets/wait_cursor.py +33 -0
- dcscope/idiom.py +26 -0
- dcscope/img/__init__.py +2 -0
- dcscope/img/icon-theme/breeze/COPYING-ICONS +209 -0
- dcscope/img/icon-theme/breeze/COPYING.LIB +510 -0
- dcscope/img/icon-theme/breeze/README +5 -0
- dcscope/img/icon-theme/breeze/actions/16/application-exit.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/16/code-context.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-cancel.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-close.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-messages.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-ok-apply.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-ok.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/document-open-folder.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/document-open.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/document-save.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/documentinfo.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/16/draw-watercolor.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/edit-clear-all.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/edit-clear.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/edit-paste.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/globe.svg +16 -0
- dcscope/img/icon-theme/breeze/actions/16/gtk-preferences.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/list-add.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/messagebox_warning.svg +20 -0
- dcscope/img/icon-theme/breeze/actions/16/object-columns.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/object-order-lower.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/object-rows.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/office-chart-line-stacked.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/office-chart-ring.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/office-chart-scatter.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/path-mode-polyline.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/preferences-activities.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/remove.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/16/search.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/show-grid.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/special_paste.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/tools-wizard.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-calendar-list.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-filter.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-list-tree.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-statistics.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/visibility.svg +21 -0
- dcscope/img/icon-theme/breeze/actions/22/application-exit.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/22/code-context.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-cancel.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-close.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-messages.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-ok-apply.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-ok.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/document-open-folder.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/document-open.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/document-save.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/documentinfo.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/draw-watercolor.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/edit-clear-all.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/edit-clear.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/edit-paste.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/globe.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/22/gtk-preferences.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/22/list-add.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/messagebox_warning.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/object-columns.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/object-order-lower.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/object-rows.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/office-chart-line-stacked.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/office-chart-ring.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/office-chart-scatter.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/path-mode-polyline.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/preferences-activities.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/remove.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/22/special_paste.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/tools-wizard.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-calendar-list.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-filter.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-list-tree.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-statistics.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/visibility.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/application-exit.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/code-context.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-cancel.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-close.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-messages.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-ok-apply.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-ok.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/document-open-folder.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/document-open.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/document-save.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/documentinfo.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/draw-watercolor.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/edit-clear-all.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/edit-clear.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/edit-paste.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/globe.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/gtk-preferences.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/24/list-add.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/messagebox_warning.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/24/object-columns.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/object-order-lower.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/object-rows.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/office-chart-line-stacked.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/office-chart-ring.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/office-chart-scatter.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/path-mode-polyline.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/preferences-activities.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/24/remove.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/24/special_paste.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/tools-wizard.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-calendar-list.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-filter.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-list-tree.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-statistics.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/visibility.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/32/application-exit.svg +8 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-cancel.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-messages.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-ok-apply.svg +1 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-ok.svg +1 -0
- dcscope/img/icon-theme/breeze/actions/32/document-open-folder.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/document-open.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/document-save.svg +18 -0
- dcscope/img/icon-theme/breeze/actions/32/gtk-preferences.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/32/object-order-lower.svg +18 -0
- dcscope/img/icon-theme/breeze/actions/32/view-filter.svg +18 -0
- dcscope/img/icon-theme/breeze/actions/32/view-list-tree.svg +18 -0
- dcscope/img/icon-theme/breeze/places/16/folder-cloud.svg +13 -0
- dcscope/img/icon-theme/breeze/places/16/folder.svg +13 -0
- dcscope/img/icon-theme/breeze/places/22/folder-cloud.svg +13 -0
- dcscope/img/icon-theme/breeze/places/22/folder.svg +13 -0
- dcscope/img/icon-theme/breeze/places/24/folder-cloud.svg +12 -0
- dcscope/img/icon-theme/breeze/places/24/folder.svg +12 -0
- dcscope/img/icon-theme/breeze/places/32/folder-cloud.svg +35 -0
- dcscope/img/icon-theme/breeze/places/32/folder.svg +30 -0
- dcscope/img/icon-theme/breeze/places/64/folder-cloud.svg +35 -0
- dcscope/img/icon-theme/breeze/places/64/folder.svg +30 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-error.svg +9 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-information.svg +9 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-question.svg +7 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-warning.svg +9 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-error.svg +9 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-information.svg +9 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-question.svg +7 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-warning.svg +9 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-error.svg +13 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-information.svg +13 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-question.svg +9 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-warning.svg +1 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-error.svg +25 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-information.svg +25 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-question.svg +25 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-warning.svg +25 -0
- dcscope/img/icon-theme/collect_icons.py +124 -0
- dcscope/img/icon-theme/dcscope/dcor.png +0 -0
- dcscope/img/icon-theme/dcscope/edit-copy-anew.svg +13 -0
- dcscope/img/icon-theme/dcscope/emodulus.svg +69 -0
- dcscope/img/icon-theme/dcscope/filter_ray.svg +54 -0
- dcscope/img/icon-theme/dcscope/region_channel.svg +86 -0
- dcscope/img/icon-theme/dcscope/region_reservoir.svg +89 -0
- dcscope/img/icon-theme/dcscope/rlang.svg +108 -0
- dcscope/img/icon-theme/dcscope/statistical_significance.svg +106 -0
- dcscope/img/icon-theme/index.theme +81 -0
- dcscope/img/icon.png +0 -0
- dcscope/img/icon.svg +73 -0
- dcscope/img/splash.png +0 -0
- dcscope/meta_tool.py +143 -0
- dcscope/pipeline/__init__.py +5 -0
- dcscope/pipeline/core.py +632 -0
- dcscope/pipeline/dataslot.py +270 -0
- dcscope/pipeline/filter.py +161 -0
- dcscope/pipeline/filter_ray.py +170 -0
- dcscope/pipeline/plot.py +187 -0
- dcscope/plot_cache.py +79 -0
- dcscope/session.py +379 -0
- dcscope/util.py +34 -0
- dcscope-2.22.1.dist-info/METADATA +95 -0
- dcscope-2.22.1.dist-info/RECORD +267 -0
- dcscope-2.22.1.dist-info/WHEEL +5 -0
- dcscope-2.22.1.dist-info/entry_points.txt +2 -0
- dcscope-2.22.1.dist-info/licenses/LICENSE +621 -0
- dcscope-2.22.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from PyQt6 import QtCore, QtWidgets
|
|
5
|
+
|
|
6
|
+
from ... import pipeline
|
|
7
|
+
|
|
8
|
+
from .dm_dataset import MatrixDataset
|
|
9
|
+
from .dm_filter import MatrixFilter
|
|
10
|
+
from .dm_element import MatrixElement
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DataMatrix(QtWidgets.QWidget):
|
|
14
|
+
quickviewed = QtCore.pyqtSignal(int, int)
|
|
15
|
+
matrix_changed = QtCore.pyqtSignal()
|
|
16
|
+
filter_modify_clicked = QtCore.pyqtSignal(str)
|
|
17
|
+
slot_modify_clicked = QtCore.pyqtSignal(str)
|
|
18
|
+
|
|
19
|
+
def __init__(self, *args, **kwargs):
|
|
20
|
+
super(DataMatrix, self).__init__(*args, **kwargs)
|
|
21
|
+
|
|
22
|
+
self.glo = None
|
|
23
|
+
self._reset_layout()
|
|
24
|
+
|
|
25
|
+
self.setAcceptDrops(True)
|
|
26
|
+
|
|
27
|
+
# used for toggling between all active, all inactive and semi state
|
|
28
|
+
self.semi_states_dataset = {}
|
|
29
|
+
self.semi_states_filter = {}
|
|
30
|
+
|
|
31
|
+
# used for remembering quickview element
|
|
32
|
+
self._old_quickview_instance = None
|
|
33
|
+
|
|
34
|
+
def read_pipeline_state(self):
|
|
35
|
+
"""State of the current data matrix"""
|
|
36
|
+
# slots
|
|
37
|
+
slot_states = []
|
|
38
|
+
slots_used = []
|
|
39
|
+
for dw in self.dataset_widgets:
|
|
40
|
+
dw_state = dw.read_pipeline_state()
|
|
41
|
+
slot = pipeline.Dataslot.get_slot(dw_state["identifier"])
|
|
42
|
+
slot.slot_used = dw_state["enabled"]
|
|
43
|
+
slot_states.append(slot.__getstate__())
|
|
44
|
+
if dw_state["enabled"]:
|
|
45
|
+
slots_used.append(dw_state["identifier"])
|
|
46
|
+
|
|
47
|
+
# filters
|
|
48
|
+
filter_states = []
|
|
49
|
+
filters_used = []
|
|
50
|
+
for fw in self.filter_widgets:
|
|
51
|
+
fw_state = fw.read_pipeline_state()
|
|
52
|
+
filt = pipeline.Filter.get_filter(fw_state["identifier"])
|
|
53
|
+
filter_states.append(filt.__getstate__())
|
|
54
|
+
if fw_state["enabled"]:
|
|
55
|
+
filters_used.append(fw_state["identifier"])
|
|
56
|
+
# elements
|
|
57
|
+
mestates = {}
|
|
58
|
+
for dw in self.dataset_widgets:
|
|
59
|
+
idict = {}
|
|
60
|
+
for fw in self.filter_widgets:
|
|
61
|
+
me = self.get_matrix_element(dw.identifier, fw.identifier)
|
|
62
|
+
# We only store the information about whether the user
|
|
63
|
+
# clicked this element. The state about "enabled" is stored
|
|
64
|
+
# in `slots_used` and `filters_used`.
|
|
65
|
+
idict[fw.identifier] = me.read_pipeline_state()["active"]
|
|
66
|
+
mestates[dw.identifier] = idict
|
|
67
|
+
state = {"elements": mestates,
|
|
68
|
+
"filters": filter_states,
|
|
69
|
+
"filters used": filters_used,
|
|
70
|
+
"slots": slot_states,
|
|
71
|
+
"slots used": slots_used,
|
|
72
|
+
}
|
|
73
|
+
return state
|
|
74
|
+
|
|
75
|
+
def write_pipeline_state(self, state):
|
|
76
|
+
# remember current QuickView identifiers
|
|
77
|
+
qv_slot_id, qv_filt_id = self.get_quickview_ids()
|
|
78
|
+
self.blockSignals(True)
|
|
79
|
+
self.clear()
|
|
80
|
+
# dataset states
|
|
81
|
+
for ii in range(len(state["slots"])):
|
|
82
|
+
slot_id = state["slots"][ii]["identifier"]
|
|
83
|
+
dw_state = {"path": state["slots"][ii]["path"],
|
|
84
|
+
"identifier": slot_id,
|
|
85
|
+
"enabled": slot_id in state["slots used"],
|
|
86
|
+
}
|
|
87
|
+
self.add_dataset(state=dw_state)
|
|
88
|
+
# filter states
|
|
89
|
+
for jj in range(len(state["filters"])):
|
|
90
|
+
filt_id = state["filters"][jj]["identifier"]
|
|
91
|
+
fw_state = {"identifier": filt_id,
|
|
92
|
+
"enabled": filt_id in state["filters used"],
|
|
93
|
+
"name": state["filters"][jj]["name"]
|
|
94
|
+
}
|
|
95
|
+
self.add_filter(state=fw_state)
|
|
96
|
+
# make sure elements exist
|
|
97
|
+
# (this also sets enabled/disabled state)
|
|
98
|
+
self.fill_elements()
|
|
99
|
+
# element states
|
|
100
|
+
MatrixElement._quick_view_instance = None
|
|
101
|
+
for slot_id in state["elements"]:
|
|
102
|
+
ds_state = state["elements"][slot_id]
|
|
103
|
+
for filt_id in ds_state:
|
|
104
|
+
me = self.get_matrix_element(slot_id, filt_id)
|
|
105
|
+
me_state = me.read_pipeline_state()
|
|
106
|
+
me_state["active"] = ds_state[filt_id]
|
|
107
|
+
me.write_pipeline_state(me_state)
|
|
108
|
+
# re-apply current quickview ids
|
|
109
|
+
try:
|
|
110
|
+
meqv = self.get_matrix_element(qv_slot_id, qv_filt_id)
|
|
111
|
+
except KeyError:
|
|
112
|
+
pass
|
|
113
|
+
else:
|
|
114
|
+
MatrixElement._quick_view_instance = meqv
|
|
115
|
+
self.update_content()
|
|
116
|
+
self.blockSignals(False)
|
|
117
|
+
|
|
118
|
+
def _reset_layout(self):
|
|
119
|
+
if self.glo is not None:
|
|
120
|
+
# send old layout to Nirvana eventually
|
|
121
|
+
layout = self.glo
|
|
122
|
+
self.glo = None
|
|
123
|
+
self.old_layout = QtWidgets.QWidget()
|
|
124
|
+
self.old_layout.setLayout(layout)
|
|
125
|
+
self.old_layout.hide()
|
|
126
|
+
self.old_layout.deleteLater()
|
|
127
|
+
# add new layout
|
|
128
|
+
self.glo = QtWidgets.QGridLayout()
|
|
129
|
+
self.glo.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
|
|
130
|
+
self.glo.setSpacing(2)
|
|
131
|
+
self.glo.setContentsMargins(0, 0, 0, 0)
|
|
132
|
+
# add dummy corner element
|
|
133
|
+
cl = QtWidgets.QLabel("Block\nMatrix")
|
|
134
|
+
cl.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
|
135
|
+
self.glo.addWidget(cl, 0, 0)
|
|
136
|
+
self.setLayout(self.glo)
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def dataset_widgets(self):
|
|
140
|
+
datasets = []
|
|
141
|
+
for ii in range(self.glo.rowCount()):
|
|
142
|
+
item = self.glo.itemAtPosition(ii+1, 0)
|
|
143
|
+
if item is not None:
|
|
144
|
+
ds = item.widget()
|
|
145
|
+
datasets.append(ds)
|
|
146
|
+
return datasets
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def element_width(self):
|
|
150
|
+
"""Data matrix element width (without 2px spacing)"""
|
|
151
|
+
for jj in range(1, self.glo.columnCount()-1):
|
|
152
|
+
item = self.glo.itemAtPosition(0, jj)
|
|
153
|
+
if item is not None:
|
|
154
|
+
width = item.geometry().width()
|
|
155
|
+
break
|
|
156
|
+
else:
|
|
157
|
+
width = 67
|
|
158
|
+
return width
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def element_widget_dict(self):
|
|
162
|
+
els = {}
|
|
163
|
+
for ii, ws in enumerate(self.dataset_widgets):
|
|
164
|
+
elsd = {}
|
|
165
|
+
for jj, wf in enumerate(self.filter_widgets):
|
|
166
|
+
it = self.glo.itemAtPosition(ii+1, jj+1)
|
|
167
|
+
elsd[wf.identifier] = it.widget()
|
|
168
|
+
els[ws.identifier] = elsd
|
|
169
|
+
return els
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def filter_widgets(self):
|
|
173
|
+
filters = []
|
|
174
|
+
for jj in range(self.glo.columnCount()):
|
|
175
|
+
item = self.glo.itemAtPosition(0, jj+1)
|
|
176
|
+
if item is not None:
|
|
177
|
+
fs = item.widget()
|
|
178
|
+
filters.append(fs)
|
|
179
|
+
return filters
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def num_datasets(self):
|
|
183
|
+
count = 0
|
|
184
|
+
for ii in range(1, self.glo.rowCount()):
|
|
185
|
+
if self.glo.itemAtPosition(ii, 0) is not None:
|
|
186
|
+
count += 1
|
|
187
|
+
return count
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def num_filters(self):
|
|
191
|
+
count = 0
|
|
192
|
+
for jj in range(1, self.glo.columnCount()):
|
|
193
|
+
if self.glo.itemAtPosition(0, jj) is not None:
|
|
194
|
+
count += 1
|
|
195
|
+
return count
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def plot_matrix(self):
|
|
199
|
+
for ch in self.parent().children():
|
|
200
|
+
if ch.__class__.__name__ == "PlotMatrix":
|
|
201
|
+
break
|
|
202
|
+
else:
|
|
203
|
+
raise KeyError("PlotMatrix not found!")
|
|
204
|
+
return ch
|
|
205
|
+
|
|
206
|
+
def add_dataset(self, slot_id=None, state=None):
|
|
207
|
+
"""Add a dataset to the DataMatrix"""
|
|
208
|
+
md = MatrixDataset(identifier=slot_id, state=state)
|
|
209
|
+
self.glo.addWidget(md, self.num_datasets+1, 0)
|
|
210
|
+
md.active_toggled.connect(self.toggle_dataset_active)
|
|
211
|
+
md.enabled_toggled.connect(self.toggle_dataset_enable)
|
|
212
|
+
md.enabled_toggled.connect(self.plot_matrix.toggle_dataset_enable)
|
|
213
|
+
md.option_action.connect(self.on_option_dataset)
|
|
214
|
+
md.modify_clicked.connect(self.slot_modify_clicked.emit)
|
|
215
|
+
self.fill_elements()
|
|
216
|
+
self.plot_matrix.fill_elements()
|
|
217
|
+
self.adjust_size()
|
|
218
|
+
self.plot_matrix.adjust_size() # important when opt/removing slots
|
|
219
|
+
self.publish_matrix()
|
|
220
|
+
return md
|
|
221
|
+
|
|
222
|
+
def add_filter(self, identifier=None, state=None):
|
|
223
|
+
mf = MatrixFilter(identifier=identifier, state=state)
|
|
224
|
+
mf.active_toggled.connect(self.toggle_filter_active)
|
|
225
|
+
mf.enabled_toggled.connect(self.toggle_filter_enable)
|
|
226
|
+
mf.option_action.connect(self.on_option_filter)
|
|
227
|
+
mf.modify_clicked.connect(self.filter_modify_clicked.emit)
|
|
228
|
+
self.glo.addWidget(mf, 0, self.num_filters+1)
|
|
229
|
+
self.fill_elements()
|
|
230
|
+
self.adjust_size()
|
|
231
|
+
self.plot_matrix.adjust_size() # important when opt/removing filters
|
|
232
|
+
self.publish_matrix()
|
|
233
|
+
return mf
|
|
234
|
+
|
|
235
|
+
def adjust_size(self):
|
|
236
|
+
QtWidgets.QApplication.processEvents(
|
|
237
|
+
QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 300)
|
|
238
|
+
self.setMinimumSize(self.sizeHint())
|
|
239
|
+
self.setFixedSize(self.sizeHint())
|
|
240
|
+
QtWidgets.QApplication.processEvents(
|
|
241
|
+
QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 300)
|
|
242
|
+
self.setMinimumSize(self.sizeHint())
|
|
243
|
+
self.setFixedSize(self.sizeHint())
|
|
244
|
+
|
|
245
|
+
def changed_element(self):
|
|
246
|
+
self.publish_matrix()
|
|
247
|
+
|
|
248
|
+
def changed_quickview(self):
|
|
249
|
+
slot_index_qv, filt_index_qv = self.get_quickview_indices()
|
|
250
|
+
# events must be integer, use -1 to indicate None
|
|
251
|
+
if slot_index_qv is None:
|
|
252
|
+
slot_index_qv = -1
|
|
253
|
+
if filt_index_qv is None:
|
|
254
|
+
filt_index_qv = -1
|
|
255
|
+
self.quickviewed.emit(slot_index_qv, filt_index_qv)
|
|
256
|
+
|
|
257
|
+
def enable_quickview(self, b=True):
|
|
258
|
+
if b:
|
|
259
|
+
MatrixElement._quick_view_instance = self._old_quickview_instance
|
|
260
|
+
else:
|
|
261
|
+
self._old_quickview_instance = MatrixElement._quick_view_instance
|
|
262
|
+
MatrixElement._quick_view_instance = None
|
|
263
|
+
self.update_content()
|
|
264
|
+
|
|
265
|
+
def clear(self):
|
|
266
|
+
"""Reset layout"""
|
|
267
|
+
self._reset_layout()
|
|
268
|
+
|
|
269
|
+
def dragEnterEvent(self, event):
|
|
270
|
+
# drag enter event on data matrix
|
|
271
|
+
event.ignore()
|
|
272
|
+
|
|
273
|
+
def dropEvent(self, event):
|
|
274
|
+
# drag drop event on data matrix
|
|
275
|
+
event.ignore()
|
|
276
|
+
|
|
277
|
+
def fill_elements(self):
|
|
278
|
+
# add widgets
|
|
279
|
+
for ii in range(self.num_datasets):
|
|
280
|
+
for jj in range(self.num_filters):
|
|
281
|
+
if self.glo.itemAtPosition(ii+1, jj+1) is None:
|
|
282
|
+
me = MatrixElement()
|
|
283
|
+
me.quickview_selected.connect(self.changed_quickview)
|
|
284
|
+
me.element_changed.connect(self.changed_element)
|
|
285
|
+
self.glo.addWidget(me, ii+1, jj+1)
|
|
286
|
+
# make sure enabled/disabled is honored
|
|
287
|
+
state = self.read_pipeline_state()
|
|
288
|
+
for slot_sate in state["slots"]:
|
|
289
|
+
slot_id = slot_sate["identifier"]
|
|
290
|
+
for filt_state in state["filters"]:
|
|
291
|
+
filt_id = filt_state["identifier"]
|
|
292
|
+
if not (slot_id in state["slots used"]
|
|
293
|
+
and filt_id in state["filters used"]):
|
|
294
|
+
me = self.get_matrix_element(slot_id, filt_id)
|
|
295
|
+
mstate = me.read_pipeline_state()
|
|
296
|
+
mstate["enabled"] = False
|
|
297
|
+
me.write_pipeline_state(mstate)
|
|
298
|
+
|
|
299
|
+
def get_filter_index(self, filter_id):
|
|
300
|
+
for ii, fs in enumerate(self.filter_widgets):
|
|
301
|
+
if fs.identifier == filter_id:
|
|
302
|
+
break
|
|
303
|
+
else:
|
|
304
|
+
raise KeyError("Filter '{}' not found!".format(filter_id))
|
|
305
|
+
return ii
|
|
306
|
+
|
|
307
|
+
def get_filter_widget_state(self, filter_id):
|
|
308
|
+
ii = self.get_filter_index(filter_id)
|
|
309
|
+
fw = self.filter_widgets[ii]
|
|
310
|
+
return fw.read_pipeline_state()
|
|
311
|
+
|
|
312
|
+
def get_slot_index(self, slot_id):
|
|
313
|
+
for ii, dw in enumerate(self.dataset_widgets):
|
|
314
|
+
if dw.identifier == slot_id:
|
|
315
|
+
break
|
|
316
|
+
else:
|
|
317
|
+
raise KeyError("Dataset '{}' not found!".format(slot_id))
|
|
318
|
+
return ii
|
|
319
|
+
|
|
320
|
+
def get_slot_widget_state(self, slot_id, ret_index=False):
|
|
321
|
+
ii = self.get_slot_index(slot_id)
|
|
322
|
+
dw = self.dataset_widgets[ii]
|
|
323
|
+
if ret_index:
|
|
324
|
+
return dw.read_pipeline_state(), ii
|
|
325
|
+
else:
|
|
326
|
+
return dw.read_pipeline_state()
|
|
327
|
+
|
|
328
|
+
def get_matrix_element(self, slot_id, filt_id):
|
|
329
|
+
"""Return matrix element matching dataset and filter identifiers"""
|
|
330
|
+
ii, jj = self.get_matrix_indices(slot_id, filt_id)
|
|
331
|
+
return self.glo.itemAtPosition(ii, jj).widget()
|
|
332
|
+
|
|
333
|
+
def get_matrix_indices(self, slot_id, filt_id):
|
|
334
|
+
ncols = self.glo.columnCount()
|
|
335
|
+
nrows = self.glo.rowCount()
|
|
336
|
+
for ii in range(1, nrows):
|
|
337
|
+
ds = self.glo.itemAtPosition(ii, 0).widget()
|
|
338
|
+
if ds.identifier == slot_id:
|
|
339
|
+
for jj in range(1, ncols):
|
|
340
|
+
f = self.glo.itemAtPosition(0, jj).widget()
|
|
341
|
+
if f.identifier == filt_id:
|
|
342
|
+
break
|
|
343
|
+
else:
|
|
344
|
+
raise KeyError("Filter '{}' not found!".format(filt_id))
|
|
345
|
+
break
|
|
346
|
+
else:
|
|
347
|
+
raise KeyError("Dataset '{}' not found!".format(slot_id))
|
|
348
|
+
return ii, jj
|
|
349
|
+
|
|
350
|
+
def get_quickview_ids(self):
|
|
351
|
+
current = MatrixElement._quick_view_instance
|
|
352
|
+
if current is not None:
|
|
353
|
+
try:
|
|
354
|
+
state = self.read_pipeline_state()
|
|
355
|
+
except KeyError:
|
|
356
|
+
# the state is not valid (issue #25)
|
|
357
|
+
return None, None
|
|
358
|
+
for slot_id in state["elements"]:
|
|
359
|
+
ds_state = state["elements"][slot_id]
|
|
360
|
+
for filt_id in ds_state:
|
|
361
|
+
me = self.get_matrix_element(slot_id, filt_id)
|
|
362
|
+
if current == me:
|
|
363
|
+
return slot_id, filt_id
|
|
364
|
+
else:
|
|
365
|
+
# no valid QuickView selection (issue #38)
|
|
366
|
+
return None, None
|
|
367
|
+
else:
|
|
368
|
+
return None, None
|
|
369
|
+
|
|
370
|
+
def get_quickview_indices(self):
|
|
371
|
+
slot_id, filt_id = self.get_quickview_ids()
|
|
372
|
+
if slot_id is not None:
|
|
373
|
+
ii, jj = self.get_matrix_indices(slot_id, filt_id)
|
|
374
|
+
return ii - 1, jj - 1
|
|
375
|
+
else:
|
|
376
|
+
return None, None
|
|
377
|
+
|
|
378
|
+
@QtCore.pyqtSlot(str)
|
|
379
|
+
def on_option_dataset(self, option):
|
|
380
|
+
"""Dataset option logic (remove, insert_anew, duplicate)"""
|
|
381
|
+
dw_state = self.sender().read_pipeline_state()
|
|
382
|
+
slot_id = dw_state["identifier"]
|
|
383
|
+
slot_index = self.get_slot_index(slot_id)
|
|
384
|
+
state = self.read_pipeline_state()
|
|
385
|
+
pstate = self.plot_matrix.read_pipeline_state()
|
|
386
|
+
if option == "remove":
|
|
387
|
+
state["slots"].pop(slot_index)
|
|
388
|
+
if slot_id in state["slots used"]:
|
|
389
|
+
state["slots used"].remove(slot_id)
|
|
390
|
+
state["elements"].pop(slot_id)
|
|
391
|
+
pstate["elements"].pop(slot_id)
|
|
392
|
+
else:
|
|
393
|
+
# create a new slot
|
|
394
|
+
slot = pipeline.Dataslot(path=dw_state["path"])
|
|
395
|
+
new_id = slot.identifier
|
|
396
|
+
if option == "duplicate":
|
|
397
|
+
# use original state
|
|
398
|
+
new_state = copy.deepcopy(state["slots"][slot_index])
|
|
399
|
+
# only set the new identifier (issue #96)
|
|
400
|
+
new_state["identifier"] = new_id
|
|
401
|
+
else: # insert_anew
|
|
402
|
+
new_state = slot.__getstate__()
|
|
403
|
+
slot.__setstate__(new_state)
|
|
404
|
+
state["slots"].insert(slot_index+1, new_state)
|
|
405
|
+
state["slots used"].append(new_id)
|
|
406
|
+
# this also takes care of filling up matrix elements
|
|
407
|
+
self.write_pipeline_state(state)
|
|
408
|
+
# this correctly assigns elements in plot matrix
|
|
409
|
+
# (also when option is not remove)
|
|
410
|
+
self.plot_matrix.write_pipeline_state(pstate)
|
|
411
|
+
self.plot_matrix.fill_elements()
|
|
412
|
+
self.publish_matrix()
|
|
413
|
+
|
|
414
|
+
@QtCore.pyqtSlot(str)
|
|
415
|
+
def on_option_filter(self, option):
|
|
416
|
+
"""Filter option logic (remove, duplicate)"""
|
|
417
|
+
fw_state = self.sender().read_pipeline_state()
|
|
418
|
+
filt_id = fw_state["identifier"]
|
|
419
|
+
filt_index = self.get_filter_index(filt_id)
|
|
420
|
+
state = self.read_pipeline_state()
|
|
421
|
+
if option == "remove":
|
|
422
|
+
state["filters"].pop(filt_index)
|
|
423
|
+
# remove matrix elements
|
|
424
|
+
for ds_key in state["elements"]:
|
|
425
|
+
state["elements"][ds_key].pop(filt_id)
|
|
426
|
+
else: # duplicate
|
|
427
|
+
filt = pipeline.Filter()
|
|
428
|
+
new_state = copy.deepcopy(state["filters"][filt_index])
|
|
429
|
+
new_state["identifier"] = filt.identifier
|
|
430
|
+
new_state["name"] = filt.name
|
|
431
|
+
state["filters"].insert(filt_index+1, new_state)
|
|
432
|
+
state["filters used"].append(filt.identifier)
|
|
433
|
+
filt.__setstate__(new_state)
|
|
434
|
+
self.write_pipeline_state(state)
|
|
435
|
+
self.publish_matrix()
|
|
436
|
+
|
|
437
|
+
def publish_matrix(self):
|
|
438
|
+
"""Publish state via self.matrix_changed signal for Pipeline"""
|
|
439
|
+
if not self.signalsBlocked():
|
|
440
|
+
self.matrix_changed.emit()
|
|
441
|
+
self.changed_quickview()
|
|
442
|
+
|
|
443
|
+
@QtCore.pyqtSlot()
|
|
444
|
+
def toggle_dataset_active(self):
|
|
445
|
+
"""Switch between all active, all inactive, previous state
|
|
446
|
+
|
|
447
|
+
Modifies the matrix elements for a dataset/row,
|
|
448
|
+
which is defined by the signal sender :class:`MatrixDataset`.
|
|
449
|
+
Cyclic toggling order: semi -> all -> none
|
|
450
|
+
"""
|
|
451
|
+
self.semi_states_filter = {} # sic
|
|
452
|
+
sender = self.sender()
|
|
453
|
+
slot_id = sender.identifier
|
|
454
|
+
state = self.read_pipeline_state()["elements"][slot_id]
|
|
455
|
+
num_actives = sum([s for s in state.values()])
|
|
456
|
+
|
|
457
|
+
# update state according to the scheme in the docstring
|
|
458
|
+
if num_actives == 0:
|
|
459
|
+
if slot_id in self.semi_states_dataset:
|
|
460
|
+
# use semi state
|
|
461
|
+
oldstate = self.semi_states_dataset[slot_id]
|
|
462
|
+
for filt_id in oldstate:
|
|
463
|
+
if filt_id in state:
|
|
464
|
+
state[filt_id] = oldstate[filt_id]
|
|
465
|
+
else:
|
|
466
|
+
# toggle all to active
|
|
467
|
+
for filt_id in state:
|
|
468
|
+
state[filt_id] = True
|
|
469
|
+
elif num_actives == len(state):
|
|
470
|
+
# toggle all to inactive
|
|
471
|
+
for filt_id in state:
|
|
472
|
+
state[filt_id] = False
|
|
473
|
+
else:
|
|
474
|
+
# save semi state
|
|
475
|
+
self.semi_states_dataset[slot_id] = copy.deepcopy(state)
|
|
476
|
+
# toggle all to active
|
|
477
|
+
for filt_id in state:
|
|
478
|
+
state[filt_id] = True
|
|
479
|
+
|
|
480
|
+
for filt_id in state:
|
|
481
|
+
me = self.get_matrix_element(slot_id, filt_id)
|
|
482
|
+
me.set_active(state[filt_id])
|
|
483
|
+
self.publish_matrix()
|
|
484
|
+
|
|
485
|
+
@QtCore.pyqtSlot(bool)
|
|
486
|
+
def toggle_dataset_enable(self, enabled):
|
|
487
|
+
sender = self.sender()
|
|
488
|
+
slot_id = sender.identifier
|
|
489
|
+
state = self.read_pipeline_state()
|
|
490
|
+
for filt_id in state["elements"][slot_id]:
|
|
491
|
+
# make sure that disabled filters are honored
|
|
492
|
+
fstate = self.get_filter_widget_state(filt_id)
|
|
493
|
+
fenabled = fstate["enabled"]
|
|
494
|
+
# update element widget
|
|
495
|
+
me = self.get_matrix_element(slot_id, filt_id)
|
|
496
|
+
mstate = me.read_pipeline_state()
|
|
497
|
+
mstate["enabled"] = np.logical_and(enabled, fenabled)
|
|
498
|
+
me.write_pipeline_state(mstate)
|
|
499
|
+
self.publish_matrix()
|
|
500
|
+
|
|
501
|
+
@QtCore.pyqtSlot()
|
|
502
|
+
def toggle_filter_active(self):
|
|
503
|
+
"""Switch between all active, all inactive, previous state
|
|
504
|
+
|
|
505
|
+
Modifies the matrix elements for a filter/column,
|
|
506
|
+
which is defined by the signal sender :class:`MatrixFilter`.
|
|
507
|
+
Cyclic toggling order: semi -> all -> none
|
|
508
|
+
"""
|
|
509
|
+
self.semi_states_dataset = {} # sic
|
|
510
|
+
sender = self.sender()
|
|
511
|
+
filt_id = sender.identifier
|
|
512
|
+
|
|
513
|
+
states = self.read_pipeline_state()["elements"]
|
|
514
|
+
state = {}
|
|
515
|
+
for slot_id in states:
|
|
516
|
+
state[slot_id] = states[slot_id][filt_id]
|
|
517
|
+
|
|
518
|
+
num_actives = sum(list(state.values()))
|
|
519
|
+
|
|
520
|
+
# update state according to the scheme in the docstring
|
|
521
|
+
if num_actives == 0:
|
|
522
|
+
if filt_id in self.semi_states_filter:
|
|
523
|
+
# use semi state
|
|
524
|
+
oldstate = self.semi_states_filter[filt_id]
|
|
525
|
+
for slot_id in oldstate:
|
|
526
|
+
if slot_id in state:
|
|
527
|
+
state[slot_id] = oldstate[slot_id]
|
|
528
|
+
else:
|
|
529
|
+
# toggle all to active
|
|
530
|
+
for slot_id in state:
|
|
531
|
+
state[slot_id] = True
|
|
532
|
+
elif num_actives == len(state):
|
|
533
|
+
# toggle all to inactive
|
|
534
|
+
for slot_id in state:
|
|
535
|
+
state[slot_id] = False
|
|
536
|
+
else:
|
|
537
|
+
# save semi state
|
|
538
|
+
self.semi_states_filter[filt_id] = copy.deepcopy(state)
|
|
539
|
+
# toggle all to active
|
|
540
|
+
for slot_id in state:
|
|
541
|
+
state[slot_id] = True
|
|
542
|
+
|
|
543
|
+
for slot_id in state:
|
|
544
|
+
me = self.get_matrix_element(slot_id, filt_id)
|
|
545
|
+
me.set_active(state[slot_id])
|
|
546
|
+
self.publish_matrix()
|
|
547
|
+
|
|
548
|
+
@QtCore.pyqtSlot(bool)
|
|
549
|
+
def toggle_filter_enable(self, enabled):
|
|
550
|
+
sender = self.sender()
|
|
551
|
+
sid = sender.identifier
|
|
552
|
+
state = self.read_pipeline_state()
|
|
553
|
+
for slot_id in state["elements"]:
|
|
554
|
+
# make sure that disabled filters are honored
|
|
555
|
+
dstate = self.get_slot_widget_state(slot_id)
|
|
556
|
+
denabled = dstate["enabled"]
|
|
557
|
+
# update element widget
|
|
558
|
+
me = self.get_matrix_element(slot_id, sid)
|
|
559
|
+
mstate = me.read_pipeline_state()
|
|
560
|
+
mstate["enabled"] = np.logical_and(enabled, denabled)
|
|
561
|
+
me.write_pipeline_state(mstate)
|
|
562
|
+
self.publish_matrix()
|
|
563
|
+
|
|
564
|
+
def update_content(self):
|
|
565
|
+
ncols = self.glo.columnCount()
|
|
566
|
+
nrows = self.glo.rowCount()
|
|
567
|
+
for ii in range(nrows):
|
|
568
|
+
for jj in range(ncols):
|
|
569
|
+
if ii == 0 and jj == 0:
|
|
570
|
+
# block matrix label
|
|
571
|
+
continue
|
|
572
|
+
item = self.glo.itemAtPosition(ii, jj)
|
|
573
|
+
if item is not None:
|
|
574
|
+
item.widget().update_content()
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import importlib.resources
|
|
2
|
+
|
|
3
|
+
from PyQt6 import uic, QtWidgets, QtCore, QtGui
|
|
4
|
+
|
|
5
|
+
from ... import meta_tool
|
|
6
|
+
from ... import pipeline
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MatrixDataset(QtWidgets.QWidget):
|
|
10
|
+
active_toggled = QtCore.pyqtSignal()
|
|
11
|
+
enabled_toggled = QtCore.pyqtSignal(bool)
|
|
12
|
+
option_action = QtCore.pyqtSignal(str)
|
|
13
|
+
modify_clicked = QtCore.pyqtSignal(str)
|
|
14
|
+
|
|
15
|
+
def __init__(self, identifier=None, state=None, *args, **kwargs):
|
|
16
|
+
"""Create a new dataset matrix element
|
|
17
|
+
|
|
18
|
+
Specify either an existing Dataslot identifier or a
|
|
19
|
+
Dataslot state
|
|
20
|
+
"""
|
|
21
|
+
super(MatrixDataset, self).__init__(*args, **kwargs)
|
|
22
|
+
ref = importlib.resources.files(
|
|
23
|
+
"dcscope.gui.matrix") / "dm_dataset.ui"
|
|
24
|
+
with importlib.resources.as_file(ref) as path_ui:
|
|
25
|
+
uic.loadUi(path_ui, self)
|
|
26
|
+
|
|
27
|
+
# options button
|
|
28
|
+
menu = QtWidgets.QMenu()
|
|
29
|
+
menu.addAction('insert anew', self.action_insert_anew)
|
|
30
|
+
menu.addAction('duplicate', self.action_duplicate)
|
|
31
|
+
menu.addAction('remove', self.action_remove)
|
|
32
|
+
self.toolButton_opt.setMenu(menu)
|
|
33
|
+
|
|
34
|
+
# toggle all active, all inactive, semi state
|
|
35
|
+
self.toolButton_toggle.clicked.connect(self.active_toggled.emit)
|
|
36
|
+
|
|
37
|
+
# toggle enabled/disabled state
|
|
38
|
+
self.checkBox.clicked.connect(self.enabled_toggled.emit)
|
|
39
|
+
|
|
40
|
+
# modify slot button
|
|
41
|
+
self.toolButton_modify.clicked.connect(self.on_modify)
|
|
42
|
+
|
|
43
|
+
if state is None:
|
|
44
|
+
slot = pipeline.Dataslot._instances[identifier]
|
|
45
|
+
self.identifier = identifier
|
|
46
|
+
self.path = slot.path
|
|
47
|
+
# set tooltip/label
|
|
48
|
+
self.update_content()
|
|
49
|
+
else:
|
|
50
|
+
self.write_pipeline_state(state)
|
|
51
|
+
|
|
52
|
+
def read_pipeline_state(self):
|
|
53
|
+
state = {"path": self.path,
|
|
54
|
+
"identifier": self.identifier,
|
|
55
|
+
"enabled": self.checkBox.isChecked(),
|
|
56
|
+
}
|
|
57
|
+
return state
|
|
58
|
+
|
|
59
|
+
def write_pipeline_state(self, state):
|
|
60
|
+
self.identifier = state["identifier"]
|
|
61
|
+
self.path = state["path"]
|
|
62
|
+
self.checkBox.setChecked(state["enabled"])
|
|
63
|
+
self.update_content()
|
|
64
|
+
|
|
65
|
+
def action_duplicate(self):
|
|
66
|
+
self.option_action.emit("duplicate")
|
|
67
|
+
|
|
68
|
+
def action_insert_anew(self):
|
|
69
|
+
self.option_action.emit("insert_anew")
|
|
70
|
+
|
|
71
|
+
def action_remove(self):
|
|
72
|
+
self.option_action.emit("remove")
|
|
73
|
+
|
|
74
|
+
def on_modify(self):
|
|
75
|
+
self.modify_clicked.emit(self.identifier)
|
|
76
|
+
|
|
77
|
+
def set_label_string(self, string):
|
|
78
|
+
if self.label.fontMetrics().boundingRect(string).width() < 65:
|
|
79
|
+
nstring = string
|
|
80
|
+
else:
|
|
81
|
+
nstring = string + "..."
|
|
82
|
+
while True:
|
|
83
|
+
width = self.label.fontMetrics().boundingRect(nstring).width()
|
|
84
|
+
if width > 65:
|
|
85
|
+
nstring = nstring[:-4] + "..."
|
|
86
|
+
else:
|
|
87
|
+
break
|
|
88
|
+
self.label.setText(nstring)
|
|
89
|
+
|
|
90
|
+
def update_content(self):
|
|
91
|
+
"""Reset tool tips and title"""
|
|
92
|
+
if self.path is not None:
|
|
93
|
+
tip = meta_tool.get_repr(self.path, append_path=True)
|
|
94
|
+
self.setToolTip(tip)
|
|
95
|
+
self.label.setToolTip(tip)
|
|
96
|
+
slot = pipeline.Dataslot._instances[self.identifier]
|
|
97
|
+
name = slot.name
|
|
98
|
+
self.set_label_string(name)
|
|
99
|
+
# Set region image
|
|
100
|
+
region = meta_tool.get_info(self.path,
|
|
101
|
+
section="setup",
|
|
102
|
+
key="chip region")
|
|
103
|
+
icon = QtGui.QIcon.fromTheme("region_{}".format(region))
|
|
104
|
+
pixmap = icon.pixmap(16)
|
|
105
|
+
self.label_region.setPixmap(pixmap)
|
|
106
|
+
self.label_region.setToolTip(region)
|
|
107
|
+
if region == "channel":
|
|
108
|
+
# Set flow rate
|
|
109
|
+
flow_rate = meta_tool.get_info(self.path,
|
|
110
|
+
section="setup",
|
|
111
|
+
key="flow rate")
|
|
112
|
+
self.label_flowrate.setText("{:.4g}".format(flow_rate))
|
|
113
|
+
self.label_flowrate.setToolTip("{:.4g} µL/s".format(flow_rate))
|
|
114
|
+
else:
|
|
115
|
+
self.label_flowrate.setText(region[:3])
|
|
116
|
+
self.label_flowrate.setToolTip(region)
|