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
dcscope/pipeline/core.py
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
import dclab
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ..idiom import SLOPING_FEATURES
|
|
8
|
+
|
|
9
|
+
from .dataslot import Dataslot
|
|
10
|
+
from .filter import Filter
|
|
11
|
+
from .filter_ray import FilterRay
|
|
12
|
+
from .plot import Plot
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EmptyDatasetWarning(UserWarning):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MissingFeatureWarning(UserWarning):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Pipeline(object):
|
|
24
|
+
def __init__(self, state=None):
|
|
25
|
+
#: Filters are instances of :class:`dcscope.pipeline.Filter`
|
|
26
|
+
self.filters = []
|
|
27
|
+
#: Plots are instances of :class:`dcscope.pipeline.Plot`
|
|
28
|
+
self.plots = []
|
|
29
|
+
#: Filter rays of the current pipeline
|
|
30
|
+
self.rays = {}
|
|
31
|
+
#: Slots are instances of :class:`dcscope.pipeline.Dataslot`
|
|
32
|
+
self.slots = []
|
|
33
|
+
#: individual element states
|
|
34
|
+
self.element_states = {}
|
|
35
|
+
|
|
36
|
+
self.reset()
|
|
37
|
+
#: previous state (see __setstate__)
|
|
38
|
+
self._old_state = {}
|
|
39
|
+
if state is not None:
|
|
40
|
+
self.__setstate__(state)
|
|
41
|
+
|
|
42
|
+
def __setstate__(self, state):
|
|
43
|
+
if self._old_state == state:
|
|
44
|
+
# Nothing changed
|
|
45
|
+
return
|
|
46
|
+
self._old_state = state
|
|
47
|
+
self.reset()
|
|
48
|
+
for filt_state in state["filters"]:
|
|
49
|
+
self.add_filter(filt_state)
|
|
50
|
+
for plot_state in state["plots"]:
|
|
51
|
+
self.add_plot(plot_state)
|
|
52
|
+
self.check_contour_spacing(plot_state["identifier"])
|
|
53
|
+
for slot_state in state["slots"]:
|
|
54
|
+
self.add_slot(slot=slot_state)
|
|
55
|
+
# set element states at the end
|
|
56
|
+
self.element_states = state["elements"]
|
|
57
|
+
|
|
58
|
+
# sanity checks
|
|
59
|
+
if set(self.filters_used) != set(state["filters used"]):
|
|
60
|
+
raise ValueError("Bad pipeline state ('filters used' don't match)")
|
|
61
|
+
if set(self.slots_used) != set(state["slots used"]):
|
|
62
|
+
raise ValueError("Bad pipeline state ('slots used' don't match)")
|
|
63
|
+
|
|
64
|
+
def __getstate__(self):
|
|
65
|
+
state = {"elements": copy.deepcopy(self.element_states),
|
|
66
|
+
"filters": [filt.__getstate__() for filt in self.filters],
|
|
67
|
+
"filters used": self.filters_used,
|
|
68
|
+
"plots": [plot.__getstate__() for plot in self.plots],
|
|
69
|
+
"slots": [slot.__getstate__() for slot in self.slots],
|
|
70
|
+
"slots used": self.slots_used}
|
|
71
|
+
return state
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def filter_ids(self):
|
|
75
|
+
return [filt.identifier for filt in self.filters]
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def filters_used(self):
|
|
79
|
+
return [filt.identifier for filt in self.filters if filt.filter_used]
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def plot_ids(self):
|
|
83
|
+
return [plot.identifier for plot in self.plots]
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def slot_ids(self):
|
|
87
|
+
return [slot.identifier for slot in self.slots]
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def slots_used(self):
|
|
91
|
+
return [slot.identifier for slot in self.slots if slot.slot_used]
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def num_filters(self):
|
|
95
|
+
return len(self.filters)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def num_plots(self):
|
|
99
|
+
return len(self.plots)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def num_slots(self):
|
|
103
|
+
return len(self.slots)
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def paths(self):
|
|
107
|
+
return [ds.path for ds in self.slots]
|
|
108
|
+
|
|
109
|
+
def add_filter(self, filt=None, index=None):
|
|
110
|
+
"""Add a filter to the pipeline
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
filt: dcscope.pipeline.Filter or dict
|
|
115
|
+
Filter instance or its state from Filter.__getstate__()
|
|
116
|
+
index: int
|
|
117
|
+
Position in the filter list, defaults to `len(self.filters)`
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
index: int
|
|
122
|
+
index of the filter in the pipeline;
|
|
123
|
+
indexing starts at "0".
|
|
124
|
+
"""
|
|
125
|
+
if index is None:
|
|
126
|
+
index = self.num_filters
|
|
127
|
+
if filt is None:
|
|
128
|
+
filt = Filter()
|
|
129
|
+
elif isinstance(filt, Filter):
|
|
130
|
+
pass
|
|
131
|
+
elif isinstance(filt, dict):
|
|
132
|
+
state = filt
|
|
133
|
+
if state["identifier"] in Filter._instances:
|
|
134
|
+
filt = Filter._instances[filt["identifier"]]
|
|
135
|
+
else:
|
|
136
|
+
filt = Filter()
|
|
137
|
+
filt.__setstate__(state)
|
|
138
|
+
self.filters.insert(index, filt)
|
|
139
|
+
filt_id = filt.identifier
|
|
140
|
+
for slot_id in self.slot_ids:
|
|
141
|
+
self.element_states[slot_id][filt_id] = False
|
|
142
|
+
return filt_id
|
|
143
|
+
|
|
144
|
+
def add_plot(self, plot=None, index=None):
|
|
145
|
+
"""Add a plot to the pipeline
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
plot: dcscope.pipeline.Plot or dict
|
|
150
|
+
Plot instance or its state from Plot.__getstate__()
|
|
151
|
+
index: int
|
|
152
|
+
Position in the plot list, defaults to `len(self.plots)`
|
|
153
|
+
|
|
154
|
+
Returns
|
|
155
|
+
-------
|
|
156
|
+
index: int
|
|
157
|
+
index of the plot in the pipeline;
|
|
158
|
+
indexing starts at "0".
|
|
159
|
+
"""
|
|
160
|
+
if index is None:
|
|
161
|
+
index = self.num_plots
|
|
162
|
+
if plot is None:
|
|
163
|
+
plot = Plot()
|
|
164
|
+
elif isinstance(plot, Plot):
|
|
165
|
+
pass
|
|
166
|
+
elif isinstance(plot, dict):
|
|
167
|
+
state = plot
|
|
168
|
+
if state["identifier"] in Plot._instances:
|
|
169
|
+
plot = Plot._instances[plot["identifier"]]
|
|
170
|
+
else:
|
|
171
|
+
plot = Plot()
|
|
172
|
+
plot.__setstate__(state)
|
|
173
|
+
|
|
174
|
+
self.plots.insert(index, plot)
|
|
175
|
+
plot_id = plot.identifier
|
|
176
|
+
for slot_id in self.slot_ids:
|
|
177
|
+
self.element_states[slot_id][plot_id] = False
|
|
178
|
+
|
|
179
|
+
return plot.identifier
|
|
180
|
+
|
|
181
|
+
def add_slot(self, slot=None, path=None, index=None):
|
|
182
|
+
"""Add a slot (experiment) to the pipeline
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
slot: dcscope.pipeline.Dataslot or dict
|
|
187
|
+
Dataslot representing an experimental dataset or its
|
|
188
|
+
state from Dataslot.__getstate__(); At least `slot`
|
|
189
|
+
or `path` need to be specified
|
|
190
|
+
path: str or pathlib.Path
|
|
191
|
+
Path to a measurement or DCOR URL
|
|
192
|
+
index: int
|
|
193
|
+
Position in the slot list, defaults to `len(self.slots)`
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
index: int
|
|
198
|
+
index of the slot in the pipeline;
|
|
199
|
+
indexing starts at "0".
|
|
200
|
+
identifier: str
|
|
201
|
+
identifier of the slot
|
|
202
|
+
"""
|
|
203
|
+
if index is None:
|
|
204
|
+
index = self.num_slots
|
|
205
|
+
if ((slot is None and path is None)
|
|
206
|
+
or (slot is not None and path is not None)):
|
|
207
|
+
raise ValueError("Please specify either `slot` or `path`.")
|
|
208
|
+
elif path is not None:
|
|
209
|
+
slot = Dataslot(path=path)
|
|
210
|
+
elif isinstance(slot, Dataslot):
|
|
211
|
+
pass
|
|
212
|
+
elif isinstance(slot, dict):
|
|
213
|
+
state = slot
|
|
214
|
+
if state["identifier"] in Dataslot._instances:
|
|
215
|
+
slot = Dataslot._instances[slot["identifier"]]
|
|
216
|
+
else:
|
|
217
|
+
slot = Dataslot()
|
|
218
|
+
slot.__setstate__(state)
|
|
219
|
+
|
|
220
|
+
self.slots.insert(index, slot)
|
|
221
|
+
slot_id = slot.identifier
|
|
222
|
+
self.element_states[slot_id] = {}
|
|
223
|
+
for filt_id in self.filter_ids:
|
|
224
|
+
self.element_states[slot_id][filt_id] = False
|
|
225
|
+
for plot_id in self.plot_ids:
|
|
226
|
+
self.element_states[slot_id][plot_id] = False
|
|
227
|
+
return slot.identifier
|
|
228
|
+
|
|
229
|
+
def apply_filter_ray(self, rtdc_ds, slot_id):
|
|
230
|
+
"""Convenience function for applying filters to other data
|
|
231
|
+
|
|
232
|
+
The filters that are currently set for a specific slot with
|
|
233
|
+
`slot_id` are applied to a dataset.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
rtdc_ds: dclab.rtdc_dataset.RTDCBase
|
|
238
|
+
Dataset
|
|
239
|
+
slot_id: str
|
|
240
|
+
Identifier of the slot from which the filters are taken
|
|
241
|
+
"""
|
|
242
|
+
# make sure the current ray is built correctly
|
|
243
|
+
self.get_dataset(self.slot_ids.index(slot_id), apply_filter=False)
|
|
244
|
+
# get the ray
|
|
245
|
+
ray = self.get_ray(slot_id)
|
|
246
|
+
ds = ray.get_final_child(rtdc_ds)
|
|
247
|
+
return ds
|
|
248
|
+
|
|
249
|
+
def check_contour_spacing(self, plot_id):
|
|
250
|
+
"""Check the contour spacing for a specific plot against the data
|
|
251
|
+
|
|
252
|
+
This method was implemented to avoid tiny contour spacings for
|
|
253
|
+
plotting, which could lead to OOM events.
|
|
254
|
+
"""
|
|
255
|
+
plot = self.plots[self.plot_ids.index(plot_id)]
|
|
256
|
+
plot_state = plot.__getstate__()
|
|
257
|
+
old_plot_state = copy.deepcopy(plot_state)
|
|
258
|
+
if plot_state["general"]["auto range"]:
|
|
259
|
+
for ax in ["x", "y"]:
|
|
260
|
+
feat = plot_state["general"][f"axis {ax}"]
|
|
261
|
+
spacing = plot_state["contour"][f"spacing {ax}"]
|
|
262
|
+
for ds, slot_state in zip(*self.get_plot_datasets(
|
|
263
|
+
plot_id, apply_filter=False)):
|
|
264
|
+
slot_id = slot_state["identifier"]
|
|
265
|
+
slot = self.get_slot(slot_id)
|
|
266
|
+
sp_min, sp_max = slot.get_sane_spacing_range(feat=feat)
|
|
267
|
+
if spacing < sp_min:
|
|
268
|
+
warnings.warn(f"Setting contour spacing for {slot_id} "
|
|
269
|
+
f"to minimum ({spacing}<{sp_min})")
|
|
270
|
+
spacing = sp_min
|
|
271
|
+
elif spacing > sp_max:
|
|
272
|
+
warnings.warn(f"Setting contour spacing for {slot_id} "
|
|
273
|
+
f"to maximum ({spacing}>{sp_max})")
|
|
274
|
+
spacing = sp_max
|
|
275
|
+
plot_state["contour"][f"spacing {ax}"] = spacing
|
|
276
|
+
if old_plot_state != plot_state:
|
|
277
|
+
plot.__setstate__(plot_state)
|
|
278
|
+
|
|
279
|
+
def get_dataset(self, slot_index, filt_index=-1, apply_filter=True):
|
|
280
|
+
"""Return dataset with all filters updated (optionally applied)
|
|
281
|
+
|
|
282
|
+
Parameters
|
|
283
|
+
----------
|
|
284
|
+
slot_index: int
|
|
285
|
+
index of measurement
|
|
286
|
+
filt_index: int or None
|
|
287
|
+
index of filter; if None, then the plain dataset is returned.
|
|
288
|
+
If negative (default), then the last dataset in the pipeline
|
|
289
|
+
is returned (all selected filters applied).
|
|
290
|
+
apply_filter: bool
|
|
291
|
+
whether to call `dataset.apply_filter` in the end;
|
|
292
|
+
if set to `False`, only the filtering configuration
|
|
293
|
+
of the dataset and its hierarchy parents are updated
|
|
294
|
+
"""
|
|
295
|
+
if not isinstance(slot_index, int):
|
|
296
|
+
raise ValueError(
|
|
297
|
+
f"`slot_index` must be an integer, got '{slot_index}'")
|
|
298
|
+
slot = self.slots[slot_index]
|
|
299
|
+
if filt_index is None or (filt_index == -1 and len(self.slots) == 0):
|
|
300
|
+
# return the unfiltered dataset
|
|
301
|
+
ds = slot.get_dataset()
|
|
302
|
+
else:
|
|
303
|
+
slot_id = slot.identifier
|
|
304
|
+
# the filters used
|
|
305
|
+
filters = self.get_filters_for_slot(slot_id=slot_id,
|
|
306
|
+
max_filter_index=filt_index)
|
|
307
|
+
# filter ray magic
|
|
308
|
+
ray = self.get_ray(slot.identifier)
|
|
309
|
+
ds = ray.get_dataset(filters, apply_filter=apply_filter)
|
|
310
|
+
return ds
|
|
311
|
+
|
|
312
|
+
def get_datasets(self, filt_index=-1, apply_filter=True):
|
|
313
|
+
"""Return all datasets with filters applied
|
|
314
|
+
|
|
315
|
+
The parameters are passed to :func:`Pipeline.get_dataset`.
|
|
316
|
+
|
|
317
|
+
Parameters
|
|
318
|
+
----------
|
|
319
|
+
filt_index: int or None
|
|
320
|
+
index of filter; if None, then the plain dataset is returned.
|
|
321
|
+
If negative (default), then the last dataset in the pipeline
|
|
322
|
+
is returned (all selected filters applied).
|
|
323
|
+
apply_filter: bool
|
|
324
|
+
whether to call `dataset.apply_filter` in the end;
|
|
325
|
+
if set to `False`, only the filtering configuration
|
|
326
|
+
of the dataset and its hierarchy parents are updated
|
|
327
|
+
"""
|
|
328
|
+
kw = {"filt_index": filt_index,
|
|
329
|
+
"apply_filter": apply_filter}
|
|
330
|
+
return [self.get_dataset(ii, **kw) for ii in range(len(self.slots))]
|
|
331
|
+
|
|
332
|
+
def get_features(self, scalar=False, label_sort=False, union=False,
|
|
333
|
+
plot_id=None, ret_labels=False):
|
|
334
|
+
"""Return a list of features in the pipeline
|
|
335
|
+
|
|
336
|
+
Parameters
|
|
337
|
+
----------
|
|
338
|
+
scalar: bool
|
|
339
|
+
If True, only return scalar features
|
|
340
|
+
label_sort: bool
|
|
341
|
+
If True, return the features sorted by label
|
|
342
|
+
instead of by feature name
|
|
343
|
+
union: bool
|
|
344
|
+
If True, return the union of features available in all
|
|
345
|
+
slots. If False (default), return only those features
|
|
346
|
+
that are shared by all slots.
|
|
347
|
+
plot_id: None or str
|
|
348
|
+
If set, only datasets that are part of the matching Plot
|
|
349
|
+
instance are used. If None, all datasets of the pipeline
|
|
350
|
+
are used.
|
|
351
|
+
ret_labels: bool
|
|
352
|
+
If True, return the labels as well
|
|
353
|
+
|
|
354
|
+
Notes
|
|
355
|
+
-----
|
|
356
|
+
This function returns an empty list if there are no features
|
|
357
|
+
available.
|
|
358
|
+
"""
|
|
359
|
+
if union:
|
|
360
|
+
features = set()
|
|
361
|
+
else:
|
|
362
|
+
features = None
|
|
363
|
+
for slot_index in range(self.num_slots):
|
|
364
|
+
slot_id = self.slot_ids[slot_index]
|
|
365
|
+
if (plot_id is None
|
|
366
|
+
or (self.element_states[slot_id][plot_id]
|
|
367
|
+
and slot_id in self.slots_used)):
|
|
368
|
+
ds = self.get_dataset(slot_index=slot_index, filt_index=None)
|
|
369
|
+
if scalar:
|
|
370
|
+
ds_features = set(ds.features_scalar)
|
|
371
|
+
else:
|
|
372
|
+
ds_features = set(ds.features)
|
|
373
|
+
if union:
|
|
374
|
+
features |= ds_features
|
|
375
|
+
else:
|
|
376
|
+
if features is None:
|
|
377
|
+
features = ds_features
|
|
378
|
+
else:
|
|
379
|
+
features &= ds_features
|
|
380
|
+
if features is None:
|
|
381
|
+
# This means that the pipeline is empty
|
|
382
|
+
features = []
|
|
383
|
+
labs = [dclab.dfn.get_feature_label(f) for f in features]
|
|
384
|
+
if label_sort:
|
|
385
|
+
lf = sorted(zip(labs, features))
|
|
386
|
+
features = [it[1] for it in lf]
|
|
387
|
+
labs = [it[0] for it in lf]
|
|
388
|
+
else:
|
|
389
|
+
fl = sorted(zip(features, labs))
|
|
390
|
+
features = [it[0] for it in fl]
|
|
391
|
+
labs = [it[1] for it in fl]
|
|
392
|
+
if ret_labels:
|
|
393
|
+
return features, labs
|
|
394
|
+
else:
|
|
395
|
+
return features
|
|
396
|
+
|
|
397
|
+
def get_filter(self, filt_id):
|
|
398
|
+
"""Return the Filter matching the identifier"""
|
|
399
|
+
if filt_id not in self.filter_ids:
|
|
400
|
+
raise ValueError(f"Filter '{filt_id}' not part of this pipeline!")
|
|
401
|
+
return self.filters[self.filter_ids.index(filt_id)]
|
|
402
|
+
|
|
403
|
+
def get_filters_for_slot(self, slot_id, max_filter_index=-1):
|
|
404
|
+
"""Return list of filters for a slot
|
|
405
|
+
|
|
406
|
+
Parameters
|
|
407
|
+
----------
|
|
408
|
+
slot_id: str
|
|
409
|
+
identifier of the slot
|
|
410
|
+
max_filter_index: int
|
|
411
|
+
maximum filter index to include in the list. Note that
|
|
412
|
+
some filters may not be applied to a slot, so the final
|
|
413
|
+
length of the returned list may be smaller than this
|
|
414
|
+
value. Set to a negative value (default) to include all
|
|
415
|
+
filters applied to a dataset.
|
|
416
|
+
"""
|
|
417
|
+
filters = []
|
|
418
|
+
if max_filter_index < 0:
|
|
419
|
+
# include all filters that are used for this slot
|
|
420
|
+
max_filter_index = len(self.filters) - 1
|
|
421
|
+
for filt_id in self.filter_ids[:max_filter_index + 1]:
|
|
422
|
+
if (self.is_element_active(slot_id, filt_id)
|
|
423
|
+
and filt_id in self.filters_used):
|
|
424
|
+
filters.append(self.get_filter(filt_id))
|
|
425
|
+
return filters
|
|
426
|
+
|
|
427
|
+
def get_min_max(self, feat, plot_id=None, margin=0.0):
|
|
428
|
+
"""Return minimum and maximum values for a feature
|
|
429
|
+
|
|
430
|
+
Parameters
|
|
431
|
+
----------
|
|
432
|
+
feat: str
|
|
433
|
+
Feature name
|
|
434
|
+
plot_id: str
|
|
435
|
+
Plot identifier
|
|
436
|
+
margin: float
|
|
437
|
+
Fraction by which the minimum and maximum are
|
|
438
|
+
extended. E.g. for plotting with a 5% margin
|
|
439
|
+
use `margin=0.05`.
|
|
440
|
+
|
|
441
|
+
Returns
|
|
442
|
+
-------
|
|
443
|
+
[fmin, fmax]: list of float
|
|
444
|
+
Minimum and maximum values of the feature. If the feature
|
|
445
|
+
is empty or only-nan, an :class:`EmptyDatasetWarning` is
|
|
446
|
+
issued and both return values are set to zero.
|
|
447
|
+
"""
|
|
448
|
+
if plot_id is not None:
|
|
449
|
+
dslist = self.get_plot_datasets(plot_id)[0]
|
|
450
|
+
else:
|
|
451
|
+
dslist = self.get_datasets(filt_index=None, apply_filter=False)
|
|
452
|
+
fmin = np.inf
|
|
453
|
+
fmax = -np.inf
|
|
454
|
+
for ds in dslist:
|
|
455
|
+
if np.any(ds.filter.all):
|
|
456
|
+
if feat in ds:
|
|
457
|
+
fdata = ds[feat][ds.filter.all]
|
|
458
|
+
invalid = np.isinf(fdata)
|
|
459
|
+
if np.any(invalid):
|
|
460
|
+
vdata = fdata[~invalid]
|
|
461
|
+
else:
|
|
462
|
+
vdata = fdata
|
|
463
|
+
if feat in SLOPING_FEATURES:
|
|
464
|
+
# We are a little faster here.
|
|
465
|
+
vmin = min(np.nanmin(vdata[:1000]),
|
|
466
|
+
np.nanmin(vdata[-1000:]))
|
|
467
|
+
vmax = max(np.nanmax(vdata[:1000]),
|
|
468
|
+
np.nanmax(vdata[-1000:]))
|
|
469
|
+
else:
|
|
470
|
+
vmin = np.nanmin(vdata)
|
|
471
|
+
vmax = np.nanmax(vdata)
|
|
472
|
+
fmin = min(fmin, vmin)
|
|
473
|
+
fmax = max(fmax, vmax)
|
|
474
|
+
else:
|
|
475
|
+
warnings.warn(f"Dataset {ds.identifier} does not "
|
|
476
|
+
f"contain the feature '{feat}'!",
|
|
477
|
+
MissingFeatureWarning)
|
|
478
|
+
else:
|
|
479
|
+
warnings.warn(f"Dataset {ds.identifier} does not "
|
|
480
|
+
f"contain any events when filtered!",
|
|
481
|
+
EmptyDatasetWarning)
|
|
482
|
+
if margin:
|
|
483
|
+
diff = fmax - fmin
|
|
484
|
+
fmin -= margin*diff
|
|
485
|
+
fmax += margin*diff
|
|
486
|
+
|
|
487
|
+
if np.any(np.isinf([fmin, fmax])):
|
|
488
|
+
# Set values to 0 if no
|
|
489
|
+
fmin = fmax = 0
|
|
490
|
+
return [fmin, fmax]
|
|
491
|
+
|
|
492
|
+
def get_plot(self, plot_id):
|
|
493
|
+
if plot_id not in self.plot_ids:
|
|
494
|
+
raise ValueError(f"Plot '{plot_id}' not part of this pipeline!")
|
|
495
|
+
self.check_contour_spacing(plot_id)
|
|
496
|
+
return self.plots[self.plot_ids.index(plot_id)]
|
|
497
|
+
|
|
498
|
+
def get_plot_datasets(self, plot_id, apply_filter=True):
|
|
499
|
+
"""Return a list of datasets with slot states that belong to a plot"""
|
|
500
|
+
datasets = []
|
|
501
|
+
states = []
|
|
502
|
+
# keep the same order as in self.slots
|
|
503
|
+
for slot_index in range(len(self.slots)):
|
|
504
|
+
slot = self.slots[slot_index]
|
|
505
|
+
slot_id = slot.identifier
|
|
506
|
+
if (self.element_states[slot_id][plot_id]
|
|
507
|
+
and slot_id in self.slots_used):
|
|
508
|
+
ds = self.get_dataset(slot_index=slot_index,
|
|
509
|
+
apply_filter=apply_filter)
|
|
510
|
+
datasets.append(ds)
|
|
511
|
+
states.append(slot.__getstate__())
|
|
512
|
+
return datasets, states
|
|
513
|
+
|
|
514
|
+
def get_plot_col_row_count(self, plot_id, pipeline_state=None):
|
|
515
|
+
"""Compute how many rows a plot layout requires
|
|
516
|
+
|
|
517
|
+
Parameters
|
|
518
|
+
----------
|
|
519
|
+
plot_id: str
|
|
520
|
+
identifier of a plot in this pipeline
|
|
521
|
+
pipeline_state: dict
|
|
522
|
+
pipeline state to use; defaults to the current pipeline
|
|
523
|
+
state
|
|
524
|
+
"""
|
|
525
|
+
if pipeline_state is None:
|
|
526
|
+
pipeline_state = self.__getstate__()
|
|
527
|
+
|
|
528
|
+
# plot state
|
|
529
|
+
for pstate in pipeline_state["plots"]:
|
|
530
|
+
if plot_id == pstate["identifier"]:
|
|
531
|
+
break
|
|
532
|
+
else:
|
|
533
|
+
raise KeyError(f"Plot '{plot_id}' not given in pipeline state!")
|
|
534
|
+
|
|
535
|
+
# number of datasets in that plot
|
|
536
|
+
num_scat = 0
|
|
537
|
+
for slot_id in pipeline_state["elements"]:
|
|
538
|
+
num_scat += pipeline_state["elements"][slot_id][plot_id]
|
|
539
|
+
|
|
540
|
+
# additional plots
|
|
541
|
+
div = pstate["layout"]["division"]
|
|
542
|
+
if div == "each":
|
|
543
|
+
num_plots = max(1, num_scat)
|
|
544
|
+
elif div == "merge":
|
|
545
|
+
num_plots = 1
|
|
546
|
+
elif div == "multiscatter+contour":
|
|
547
|
+
num_plots = num_scat + 1
|
|
548
|
+
else:
|
|
549
|
+
raise ValueError(f"Unrecognized division: '{div}'")
|
|
550
|
+
|
|
551
|
+
# column count
|
|
552
|
+
col_count = min(pstate["layout"]["column count"], num_plots)
|
|
553
|
+
|
|
554
|
+
# row count
|
|
555
|
+
row_count = int(np.ceil(num_plots/col_count))
|
|
556
|
+
return col_count, row_count
|
|
557
|
+
|
|
558
|
+
def get_ray(self, slot_id):
|
|
559
|
+
"""Convenience function that creates and returns a filter ray"""
|
|
560
|
+
# cleanup (just in case)
|
|
561
|
+
for key in list(self.rays.keys()):
|
|
562
|
+
if key not in self.slot_ids:
|
|
563
|
+
self.rays.pop(key)
|
|
564
|
+
if slot_id not in self.rays:
|
|
565
|
+
# create filter ray if it does not exist
|
|
566
|
+
self.rays[slot_id] = FilterRay(self.get_slot(slot_id))
|
|
567
|
+
return self.rays[slot_id]
|
|
568
|
+
|
|
569
|
+
def get_slot(self, slot_id):
|
|
570
|
+
"""Return the Dataslot matching the RTDCBase identifier"""
|
|
571
|
+
slot_id = slot_id.split("-")[0] # this is how FilterRay names children
|
|
572
|
+
if slot_id in self.slot_ids:
|
|
573
|
+
slot = self.slots[self.slot_ids.index(slot_id)]
|
|
574
|
+
else:
|
|
575
|
+
raise ValueError(f"Unknown dataset identifier: `{slot_id}`")
|
|
576
|
+
return slot
|
|
577
|
+
|
|
578
|
+
def is_element_active(self, slot_id, filt_plot_id):
|
|
579
|
+
return self.element_states[slot_id][filt_plot_id]
|
|
580
|
+
|
|
581
|
+
def remove_filter(self, filt_id):
|
|
582
|
+
"""Remove a filter by filter identifier"""
|
|
583
|
+
index = self.filter_ids.index(filt_id)
|
|
584
|
+
self.filters.pop(index)
|
|
585
|
+
for slot_id in self.element_states:
|
|
586
|
+
if filt_id in self.element_states[slot_id]:
|
|
587
|
+
self.element_states[slot_id].pop(filt_id)
|
|
588
|
+
|
|
589
|
+
def remove_plot(self, plot_id):
|
|
590
|
+
"""Remove a filter by plot identifier"""
|
|
591
|
+
index = self.plot_ids.index(plot_id)
|
|
592
|
+
self.plots.pop(index)
|
|
593
|
+
for slot_id in self.element_states:
|
|
594
|
+
if plot_id in self.element_states[slot_id]:
|
|
595
|
+
self.element_states[slot_id].pop(plot_id)
|
|
596
|
+
|
|
597
|
+
def remove_slot(self, slot_id):
|
|
598
|
+
"""Remove a slot by slot identifier"""
|
|
599
|
+
index = self.slot_ids.index(slot_id)
|
|
600
|
+
self.slots.pop(index)
|
|
601
|
+
if slot_id in self.element_states:
|
|
602
|
+
self.element_states.pop(slot_id)
|
|
603
|
+
|
|
604
|
+
def reorder_slots(self, indices):
|
|
605
|
+
"""Change the order of data slots
|
|
606
|
+
|
|
607
|
+
Parameters
|
|
608
|
+
----------
|
|
609
|
+
indices: list of ints
|
|
610
|
+
New sequence of slots, i.e. the new slots
|
|
611
|
+
will be `self.slots[indices]`.
|
|
612
|
+
"""
|
|
613
|
+
# sanity checks
|
|
614
|
+
if sorted(indices) != list(range(len(self.slots))):
|
|
615
|
+
raise ValueError(f"Cannot reorder slots with inconclusive "
|
|
616
|
+
f"ordering sequence '{indices}'!")
|
|
617
|
+
new_slots = []
|
|
618
|
+
for idx in indices:
|
|
619
|
+
new_slots.append(self.slots[idx])
|
|
620
|
+
self.slots = new_slots
|
|
621
|
+
|
|
622
|
+
def reset(self):
|
|
623
|
+
"""Reset the pipeline"""
|
|
624
|
+
self.filters.clear()
|
|
625
|
+
self.plots.clear()
|
|
626
|
+
self.rays.clear()
|
|
627
|
+
self.slots.clear()
|
|
628
|
+
self.element_states.clear()
|
|
629
|
+
|
|
630
|
+
def set_element_active(self, slot_id, filt_plot_id, active=True):
|
|
631
|
+
"""Activate an element in the block matrix"""
|
|
632
|
+
self.element_states[slot_id][filt_plot_id] = active
|