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,341 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import importlib.resources
|
|
3
|
+
|
|
4
|
+
from PyQt6 import uic, QtCore, QtWidgets
|
|
5
|
+
|
|
6
|
+
import dclab
|
|
7
|
+
|
|
8
|
+
from ...pipeline import Filter
|
|
9
|
+
|
|
10
|
+
from ..widgets import RangeControl
|
|
11
|
+
from ... import idiom
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FilterPanel(QtWidgets.QWidget):
|
|
15
|
+
"""Filter panel widget
|
|
16
|
+
|
|
17
|
+
The filtering panel visualizes the properties of a
|
|
18
|
+
:class:`dcscope.pipeline.filter.Filter` instance,
|
|
19
|
+
i.e. box filters, list of polygon filters, filter
|
|
20
|
+
name, etc. Their `__getstate__` and `__setstate__`
|
|
21
|
+
functions are compatible.
|
|
22
|
+
"""
|
|
23
|
+
#: Emitted when a dcscope.pipeline.Filter is to be changed
|
|
24
|
+
filter_changed = QtCore.pyqtSignal(dict)
|
|
25
|
+
#: Emitted when the pipeline is to be changed
|
|
26
|
+
pipeline_changed = QtCore.pyqtSignal(dict)
|
|
27
|
+
#: Emitted when the user wants to create a new polygon filter
|
|
28
|
+
request_new_polygon_filter = QtCore.pyqtSignal()
|
|
29
|
+
|
|
30
|
+
def __init__(self, *args, **kwargs):
|
|
31
|
+
super(FilterPanel, self).__init__(*args, **kwargs)
|
|
32
|
+
ref = importlib.resources.files(
|
|
33
|
+
"dcscope.gui.analysis") / "ana_filter.ui"
|
|
34
|
+
with importlib.resources.as_file(ref) as path_ui:
|
|
35
|
+
uic.loadUi(path_ui, self)
|
|
36
|
+
# current DCscope pipeline
|
|
37
|
+
self._pipeline = None
|
|
38
|
+
self.setUpdatesEnabled(False)
|
|
39
|
+
#: contains the range widgets for the box filters
|
|
40
|
+
self._box_range_controls = {}
|
|
41
|
+
self._populate_box_filters()
|
|
42
|
+
self._polygon_checkboxes = {}
|
|
43
|
+
self.update_polygon_filters()
|
|
44
|
+
self.toolButton_duplicate.clicked.connect(self.on_duplicate_filter)
|
|
45
|
+
self.toolButton_remove.clicked.connect(self.on_remove_filter)
|
|
46
|
+
self.pushButton_apply.clicked.connect(self.write_filter)
|
|
47
|
+
self.pushButton_reset.clicked.connect(self.update_content)
|
|
48
|
+
|
|
49
|
+
self.comboBox_filters.currentIndexChanged.connect(self.update_content)
|
|
50
|
+
self.toolButton_moreless.clicked.connect(self.on_moreless)
|
|
51
|
+
self.label_box_edit.setVisible(False)
|
|
52
|
+
self._box_edit_view = False
|
|
53
|
+
self.update_content()
|
|
54
|
+
self.setUpdatesEnabled(True)
|
|
55
|
+
|
|
56
|
+
def read_pipeline_state(self):
|
|
57
|
+
state = {
|
|
58
|
+
"filter used": self.checkBox_enable.isChecked(),
|
|
59
|
+
"identifier": self.current_filter.identifier,
|
|
60
|
+
"limit events bool": self.checkBox_limit.isChecked(),
|
|
61
|
+
"limit events num": self.spinBox_limit.value(),
|
|
62
|
+
"name": self.lineEdit_name.text(),
|
|
63
|
+
"remove invalid events": self.checkBox_invalid.isChecked(),
|
|
64
|
+
}
|
|
65
|
+
# box filters
|
|
66
|
+
box = {}
|
|
67
|
+
for feat in self.active_box_features:
|
|
68
|
+
rc = self._box_range_controls[feat]
|
|
69
|
+
box[feat] = rc.read_pipeline_state()
|
|
70
|
+
state["box filters"] = box
|
|
71
|
+
# polygon filters
|
|
72
|
+
pflist = []
|
|
73
|
+
for key in self._polygon_checkboxes:
|
|
74
|
+
if self._polygon_checkboxes[key].isChecked():
|
|
75
|
+
pflist.append(key)
|
|
76
|
+
state["polygon filters"] = pflist
|
|
77
|
+
return state
|
|
78
|
+
|
|
79
|
+
def write_pipeline_state(self, state):
|
|
80
|
+
if self.current_filter.identifier != state["identifier"]:
|
|
81
|
+
raise ValueError("Filter identifier mismatch!")
|
|
82
|
+
self.checkBox_enable.setChecked(state["filter used"])
|
|
83
|
+
self.lineEdit_name.setText(state["name"])
|
|
84
|
+
self.checkBox_limit.setChecked(state["limit events bool"])
|
|
85
|
+
self.spinBox_limit.setValue(state["limit events num"])
|
|
86
|
+
self.checkBox_invalid.setChecked(state["remove invalid events"])
|
|
87
|
+
# box filters
|
|
88
|
+
box = state["box filters"]
|
|
89
|
+
for feat in self._box_range_controls:
|
|
90
|
+
rc = self._box_range_controls[feat]
|
|
91
|
+
if feat in box:
|
|
92
|
+
rc.show()
|
|
93
|
+
rc.write_pipeline_state(box[feat])
|
|
94
|
+
else:
|
|
95
|
+
rc.setActive(False) # uncheck range control (#67)
|
|
96
|
+
rc.hide()
|
|
97
|
+
rc.reset_range()
|
|
98
|
+
|
|
99
|
+
# polygon filters
|
|
100
|
+
pflist = state["polygon filters"]
|
|
101
|
+
for key in self._polygon_checkboxes:
|
|
102
|
+
if key in pflist:
|
|
103
|
+
self._polygon_checkboxes[key].setChecked(True)
|
|
104
|
+
else:
|
|
105
|
+
self._polygon_checkboxes[key].setChecked(False)
|
|
106
|
+
|
|
107
|
+
def _populate_box_filters(self):
|
|
108
|
+
"""Dynamically update available pipeline box filters
|
|
109
|
+
|
|
110
|
+
This method can be called multiple times. If called multiple
|
|
111
|
+
times, additional features that were not there before
|
|
112
|
+
(e.g. `ml_score_???`) are added.
|
|
113
|
+
"""
|
|
114
|
+
feats, labs = self.get_features_labels()
|
|
115
|
+
|
|
116
|
+
self.verticalLayout_box.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
|
|
117
|
+
|
|
118
|
+
for lab, feat in sorted(zip(labs, feats)):
|
|
119
|
+
integer = True if feat in idiom.INTEGER_FEATURES else False
|
|
120
|
+
if feat not in self._box_range_controls:
|
|
121
|
+
# Create the control
|
|
122
|
+
rc = RangeControl(
|
|
123
|
+
self,
|
|
124
|
+
checkbox=False, # checkbox is used in on_moreless
|
|
125
|
+
integer=integer,
|
|
126
|
+
label=lab,
|
|
127
|
+
data=feat)
|
|
128
|
+
rc.setActive(False)
|
|
129
|
+
rc.setVisible(False)
|
|
130
|
+
# Insert the control at the correct position (label-sorted)
|
|
131
|
+
rcf = list(self._box_range_controls.keys())
|
|
132
|
+
rcl = [dclab.dfn.get_feature_label(ft) for ft in rcf]
|
|
133
|
+
index = sorted(rcl + [lab]).index(lab)
|
|
134
|
+
self.verticalLayout_box.insertWidget(index, rc)
|
|
135
|
+
self._box_range_controls[feat] = rc
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def active_box_features(self):
|
|
139
|
+
"""List of box-filtered features that are active"""
|
|
140
|
+
act = []
|
|
141
|
+
for feat, item in self._box_range_controls.items():
|
|
142
|
+
if item.is_active():
|
|
143
|
+
act.append(feat)
|
|
144
|
+
return act
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def current_filter(self):
|
|
148
|
+
if self.filter_ids:
|
|
149
|
+
filt_index = self.comboBox_filters.currentIndex()
|
|
150
|
+
filt_id = self.filter_ids[filt_index]
|
|
151
|
+
filt = Filter.get_instances()[filt_id]
|
|
152
|
+
else:
|
|
153
|
+
filt = None
|
|
154
|
+
return filt
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def filter_ids(self):
|
|
158
|
+
"""List of filter identifiers"""
|
|
159
|
+
if self.pipeline is not None:
|
|
160
|
+
ids = [filt.identifier for filt in self.pipeline.filters]
|
|
161
|
+
else:
|
|
162
|
+
ids = []
|
|
163
|
+
return ids
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def filter_names(self):
|
|
167
|
+
"""List of filter names"""
|
|
168
|
+
if self.pipeline is not None:
|
|
169
|
+
nms = [filt.name for filt in self.pipeline.filters]
|
|
170
|
+
else:
|
|
171
|
+
nms = []
|
|
172
|
+
return nms
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def pipeline(self):
|
|
176
|
+
return self._pipeline
|
|
177
|
+
|
|
178
|
+
def get_features_labels(self):
|
|
179
|
+
"""Wrapper around pipeline with default features if empty"""
|
|
180
|
+
if self.pipeline is not None and self.pipeline.num_slots != 0:
|
|
181
|
+
feats, labs = self.pipeline.get_features(scalar=True,
|
|
182
|
+
label_sort=True,
|
|
183
|
+
ret_labels=True,
|
|
184
|
+
union=True)
|
|
185
|
+
else:
|
|
186
|
+
# fallback (nothing in the pipeline or no pipeline)
|
|
187
|
+
features = dclab.dfn.scalar_feature_names
|
|
188
|
+
labs = [dclab.dfn.get_feature_label(f) for f in features]
|
|
189
|
+
lf = sorted(zip(labs, features))
|
|
190
|
+
feats = [it[1] for it in lf]
|
|
191
|
+
labs = [it[0] for it in lf]
|
|
192
|
+
return feats, labs
|
|
193
|
+
|
|
194
|
+
def on_duplicate_filter(self):
|
|
195
|
+
# determine the new filter state
|
|
196
|
+
filt_state = self.read_pipeline_state()
|
|
197
|
+
new_state = copy.deepcopy(filt_state)
|
|
198
|
+
new_filt = Filter()
|
|
199
|
+
new_state["identifier"] = new_filt.identifier
|
|
200
|
+
new_state["name"] = new_filt.name
|
|
201
|
+
new_filt.__setstate__(new_state)
|
|
202
|
+
# determine the filter position
|
|
203
|
+
pos = self.pipeline.filter_ids.index(filt_state["identifier"])
|
|
204
|
+
self.pipeline.add_filter(new_filt, index=pos+1)
|
|
205
|
+
state = self.pipeline.__getstate__()
|
|
206
|
+
self.pipeline_changed.emit(state)
|
|
207
|
+
|
|
208
|
+
def on_remove_filter(self):
|
|
209
|
+
filt_state = self.read_pipeline_state()
|
|
210
|
+
self.pipeline.remove_filter(filt_state["identifier"])
|
|
211
|
+
state = self.pipeline.__getstate__()
|
|
212
|
+
self.pipeline_changed.emit(state)
|
|
213
|
+
|
|
214
|
+
def on_moreless(self):
|
|
215
|
+
"""User wants to choose box filters"""
|
|
216
|
+
if not self._box_edit_view:
|
|
217
|
+
# get available features to show
|
|
218
|
+
features, _ = self.get_features_labels()
|
|
219
|
+
# create missing range controls if applicable (e.g. ml_score_???)
|
|
220
|
+
self._populate_box_filters()
|
|
221
|
+
# Show all filters shared by all datasets to the user
|
|
222
|
+
for feat, rc in self._box_range_controls.items():
|
|
223
|
+
if feat in features:
|
|
224
|
+
rc.setVisible(True)
|
|
225
|
+
rc.checkBox.setVisible(True)
|
|
226
|
+
rc.doubleSpinBox_min.setEnabled(False)
|
|
227
|
+
rc.doubleSpinBox_max.setEnabled(False)
|
|
228
|
+
rc.range_slider.setEnabled(False)
|
|
229
|
+
self.toolButton_moreless.setText("...Finish editing")
|
|
230
|
+
self.label_box_edit.setVisible(True)
|
|
231
|
+
self._box_edit_view = True
|
|
232
|
+
else:
|
|
233
|
+
# Hide all filters that are not active
|
|
234
|
+
for _, rc in self._box_range_controls.items():
|
|
235
|
+
if not rc.is_active():
|
|
236
|
+
rc.setVisible(False)
|
|
237
|
+
rc.checkBox.setVisible(False)
|
|
238
|
+
rc.doubleSpinBox_min.setEnabled(True)
|
|
239
|
+
rc.doubleSpinBox_max.setEnabled(True)
|
|
240
|
+
rc.range_slider.setEnabled(True)
|
|
241
|
+
self.toolButton_moreless.setText("Choose filters...")
|
|
242
|
+
self.label_box_edit.setVisible(False)
|
|
243
|
+
self._box_edit_view = False
|
|
244
|
+
# Update box filter ranges
|
|
245
|
+
self.update_box_ranges()
|
|
246
|
+
|
|
247
|
+
def set_pipeline(self, pipeline):
|
|
248
|
+
self._pipeline = pipeline
|
|
249
|
+
|
|
250
|
+
def show_filter(self, filt_id):
|
|
251
|
+
self.update_content(filt_index=self.filter_ids.index(filt_id))
|
|
252
|
+
|
|
253
|
+
def update_content(self, filt_index=None, **kwargs):
|
|
254
|
+
if self.filter_ids:
|
|
255
|
+
# remember the previous filter index and make sure it is sane
|
|
256
|
+
prev_index = self.comboBox_filters.currentIndex()
|
|
257
|
+
if prev_index is None or prev_index < 0:
|
|
258
|
+
prev_index = len(self.filter_ids) - 1
|
|
259
|
+
|
|
260
|
+
self.setEnabled(True)
|
|
261
|
+
self.update_polygon_filters(update_state=False)
|
|
262
|
+
# update combobox
|
|
263
|
+
self.comboBox_filters.blockSignals(True)
|
|
264
|
+
if filt_index is None or filt_index < 0:
|
|
265
|
+
# fallback to previous filter index
|
|
266
|
+
filt_index = prev_index
|
|
267
|
+
filt_index = min(filt_index, len(self.filter_ids) - 1)
|
|
268
|
+
|
|
269
|
+
self.comboBox_filters.clear()
|
|
270
|
+
self.comboBox_filters.addItems(self.filter_names)
|
|
271
|
+
self.comboBox_filters.setCurrentIndex(filt_index)
|
|
272
|
+
self.comboBox_filters.blockSignals(False)
|
|
273
|
+
# populate content
|
|
274
|
+
filt = Filter.get_filter(identifier=self.filter_ids[filt_index])
|
|
275
|
+
state = filt.__getstate__()
|
|
276
|
+
self.write_pipeline_state(state)
|
|
277
|
+
self.update_box_ranges()
|
|
278
|
+
else:
|
|
279
|
+
self.setEnabled(False)
|
|
280
|
+
|
|
281
|
+
def update_box_ranges(self):
|
|
282
|
+
"""Update the box plot filter ranges
|
|
283
|
+
|
|
284
|
+
Feature information is taken from the current pipeline.
|
|
285
|
+
"""
|
|
286
|
+
if self.pipeline is not None and self.pipeline.num_slots:
|
|
287
|
+
# compute min/max values
|
|
288
|
+
mmdict = {}
|
|
289
|
+
for feat in self.active_box_features:
|
|
290
|
+
mmdict[feat] = self.pipeline.get_min_max(feat=feat)
|
|
291
|
+
# update used features
|
|
292
|
+
for feat in self._box_range_controls:
|
|
293
|
+
rc = self._box_range_controls[feat]
|
|
294
|
+
if feat in mmdict:
|
|
295
|
+
rc.setLimits(*mmdict[feat])
|
|
296
|
+
if self.current_filter is not None:
|
|
297
|
+
state = self.current_filter.__getstate__()
|
|
298
|
+
if feat not in state["box filters"]:
|
|
299
|
+
# reset range to limits
|
|
300
|
+
rc.reset_range()
|
|
301
|
+
|
|
302
|
+
def update_polygon_filters(self, update_state=True):
|
|
303
|
+
"""Update the layout containing the polygon filters"""
|
|
304
|
+
self.verticalLayout_poly.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
|
|
305
|
+
# clear layout
|
|
306
|
+
for ii in reversed(range(self.verticalLayout_poly.count())):
|
|
307
|
+
item = self.verticalLayout_poly.itemAt(ii).widget()
|
|
308
|
+
if item is not None:
|
|
309
|
+
item.hide()
|
|
310
|
+
item.deleteLater()
|
|
311
|
+
self._polygon_checkboxes = {} # must come after getting the state
|
|
312
|
+
if dclab.PolygonFilter.instances:
|
|
313
|
+
for pf in dclab.PolygonFilter.instances:
|
|
314
|
+
widget = QtWidgets.QWidget()
|
|
315
|
+
hbox = QtWidgets.QHBoxLayout()
|
|
316
|
+
hbox.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft)
|
|
317
|
+
hbox.setContentsMargins(0, 0, 0, 0)
|
|
318
|
+
chb = QtWidgets.QCheckBox()
|
|
319
|
+
hbox.addWidget(chb)
|
|
320
|
+
hbox.addWidget(QtWidgets.QLabel(pf.name))
|
|
321
|
+
widget.setLayout(hbox)
|
|
322
|
+
self.verticalLayout_poly.addWidget(widget)
|
|
323
|
+
self._polygon_checkboxes[pf.unique_id] = chb
|
|
324
|
+
else:
|
|
325
|
+
label = QtWidgets.QLabel("No polygon filters have been created "
|
|
326
|
+
+ "yet.")
|
|
327
|
+
button = QtWidgets.QPushButton("Create polygon filter")
|
|
328
|
+
button.clicked.connect(self.request_new_polygon_filter)
|
|
329
|
+
self.verticalLayout_poly.addWidget(label)
|
|
330
|
+
self.verticalLayout_poly.addWidget(button)
|
|
331
|
+
# update current filters
|
|
332
|
+
if update_state and self.current_filter is not None:
|
|
333
|
+
self.write_pipeline_state(self.current_filter.__getstate__())
|
|
334
|
+
|
|
335
|
+
def write_filter(self):
|
|
336
|
+
"""Update the dcscope.pipeline.Filter instance"""
|
|
337
|
+
# get current index
|
|
338
|
+
filter_state = self.read_pipeline_state()
|
|
339
|
+
# this signal will update the main pipeline which will trigger
|
|
340
|
+
# a call to `set_pipeline` and `update_content`.
|
|
341
|
+
self.filter_changed.emit(filter_state)
|