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