qplotter 1.6.0b3__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.
- qplot/__init__.py +46 -0
- qplot/__main__.py +232 -0
- qplot/_auxiliary_paths.py +63 -0
- qplot/_metadata.py +12 -0
- qplot/_repair.py +14 -0
- qplot/_shutdown_supervisor.py +4049 -0
- qplot/_version.py +12 -0
- qplot/_windows_shutdown_job.py +1166 -0
- qplot/configuration/__init__.py +3 -0
- qplot/configuration/config.py +573 -0
- qplot/configuration/config_schema.json +319 -0
- qplot/configuration/scripts.py +255 -0
- qplot/configuration/themes/__init__.py +13 -0
- qplot/configuration/themes/_base.py +579 -0
- qplot/configuration/themes/blank.py +17 -0
- qplot/configuration/themes/dark.py +54 -0
- qplot/configuration/themes/light.py +54 -0
- qplot/datahandling/LoadFromDB.py +224 -0
- qplot/datahandling/__init__.py +47 -0
- qplot/datahandling/_trusted_live_helper.py +812 -0
- qplot/datahandling/_trusted_live_protocol.py +1745 -0
- qplot/datahandling/database.py +2330 -0
- qplot/datahandling/dimensions.py +43 -0
- qplot/datahandling/file_identity.py +461 -0
- qplot/datahandling/parameter_data.py +149 -0
- qplot/datahandling/plot_progress.py +17 -0
- qplot/datahandling/qcodes_cache.py +277 -0
- qplot/datahandling/qcodes_compat.py +14 -0
- qplot/datahandling/readSQL.py +2442 -0
- qplot/datahandling/readonly.py +2561 -0
- qplot/datahandling/source_activity.py +21 -0
- qplot/datahandling/trusted_array_preview.py +127 -0
- qplot/datahandling/trusted_derived_cache.py +1605 -0
- qplot/datahandling/trusted_derived_rendering.py +868 -0
- qplot/datahandling/trusted_heatmap.py +241 -0
- qplot/datahandling/trusted_live.py +2808 -0
- qplot/datahandling/trusted_live_queries.py +5907 -0
- qplot/datahandling/trusted_live_service.py +1894 -0
- qplot/datahandling/trusted_live_supervisor.py +2161 -0
- qplot/datahandling/trusted_plot.py +283 -0
- qplot/datahandling/trusted_presentation.py +1065 -0
- qplot/datahandling/trusted_snapshot.py +1132 -0
- qplot/datahandling/trusted_work_coordinator.py +2157 -0
- qplot/datahandling/trusted_work_scheduler.py +1204 -0
- qplot/diagnostics.py +241 -0
- qplot/resources/testdata/qplot_test_db_01_10mb.csv +11 -0
- qplot/resources/testdata/qplot_test_db_02_25mb.csv +14 -0
- qplot/resources/testdata/qplot_test_db_03_50mb.csv +17 -0
- qplot/resources/testdata/qplot_test_db_04_100mb.csv +20 -0
- qplot/resources/testdata/qplot_test_db_05_250mb.csv +23 -0
- qplot/resources/testdata/qplot_test_db_06_500mb.csv +26 -0
- qplot/resources/testdata/qplot_test_db_07_1gb.csv +29 -0
- qplot/resources/testdata/qplot_test_db_08_5gb.csv +32 -0
- qplot/resources/testdata/qplot_test_db_09_10gb.csv +35 -0
- qplot/resources/testdata/qplot_test_db_10_30gb.csv +38 -0
- qplot/testdata.py +1733 -0
- qplot/tools/__init__.py +13 -0
- qplot/tools/finite_means.py +114 -0
- qplot/tools/general.py +134 -0
- qplot/tools/heatmap_geometry.py +381 -0
- qplot/tools/operation_registry.py +179 -0
- qplot/tools/plot_tools.py +625 -0
- qplot/tools/sample_statistics.py +56 -0
- qplot/tools/worker.py +2787 -0
- qplot/windows/__init__.py +9 -0
- qplot/windows/_colorbar.py +422 -0
- qplot/windows/_commands.py +523 -0
- qplot/windows/_config_persistence.py +123 -0
- qplot/windows/_database_actions.py +4904 -0
- qplot/windows/_dataset_handle.py +221 -0
- qplot/windows/_dragdrop.py +71 -0
- qplot/windows/_export_paths.py +1167 -0
- qplot/windows/_help.py +169 -0
- qplot/windows/_native_averaging.py +173 -0
- qplot/windows/_native_transforms.py +389 -0
- qplot/windows/_plot1d_snap.py +608 -0
- qplot/windows/_plot1d_traces.py +2183 -0
- qplot/windows/_plot2d_colorbar.py +1126 -0
- qplot/windows/_plot2d_colorbar_dialog.py +786 -0
- qplot/windows/_plot2d_layers.py +2197 -0
- qplot/windows/_plot2d_sweeps.py +712 -0
- qplot/windows/_plotWin.py +1993 -0
- qplot/windows/_plot_actions.py +2695 -0
- qplot/windows/_plot_appearance.py +276 -0
- qplot/windows/_plot_axis_scaling.py +1485 -0
- qplot/windows/_plot_export.py +1445 -0
- qplot/windows/_plot_feedback.py +110 -0
- qplot/windows/_plot_marquee.py +656 -0
- qplot/windows/_plot_refresh.py +942 -0
- qplot/windows/_plot_state.py +239 -0
- qplot/windows/_plot_transform_labels.py +60 -0
- qplot/windows/_preferences.py +635 -0
- qplot/windows/_refresh_interval.py +70 -0
- qplot/windows/_run_controls.py +828 -0
- qplot/windows/_shortcuts.py +47 -0
- qplot/windows/_subplots/__init__.py +8 -0
- qplot/windows/_subplots/subplot1d.py +531 -0
- qplot/windows/_subplots/subplot2d.py +918 -0
- qplot/windows/_svg_export.py +209 -0
- qplot/windows/_trusted_derived_qt.py +1759 -0
- qplot/windows/_widgets/__init__.py +23 -0
- qplot/windows/_widgets/_run_formatting.py +387 -0
- qplot/windows/_widgets/details_tables.py +1119 -0
- qplot/windows/_widgets/dropbox.py +290 -0
- qplot/windows/_widgets/operations.py +460 -0
- qplot/windows/_widgets/preview.py +2997 -0
- qplot/windows/_widgets/run_list_items.py +488 -0
- qplot/windows/_widgets/toolbar.py +111 -0
- qplot/windows/_widgets/treeWidgets.py +2572 -0
- qplot/windows/_window_controls.py +413 -0
- qplot/windows/main.py +1635 -0
- qplot/windows/plot1d.py +311 -0
- qplot/windows/plot2d.py +1901 -0
- qplotter-1.6.0b3.dist-info/METADATA +318 -0
- qplotter-1.6.0b3.dist-info/RECORD +119 -0
- qplotter-1.6.0b3.dist-info/WHEEL +5 -0
- qplotter-1.6.0b3.dist-info/entry_points.txt +4 -0
- qplotter-1.6.0b3.dist-info/licenses/LICENSE +21 -0
- qplotter-1.6.0b3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from PyQt6 import QtCore, QtGui
|
|
6
|
+
from PyQt6 import QtWidgets as qtw
|
|
7
|
+
|
|
8
|
+
from ._colorbar import (
|
|
9
|
+
_CET_COLORBAR_SUBTYPES,
|
|
10
|
+
_COLORBAR_COLORMAP_LABELS,
|
|
11
|
+
_COLORBAR_TABLE_SORT_ROLE,
|
|
12
|
+
_MATPLOTLIB_COLORBAR_SUBTYPES,
|
|
13
|
+
_colorbar_colormap_preview,
|
|
14
|
+
_colorbar_colormap_type_label,
|
|
15
|
+
_colorbar_subtype_config_key,
|
|
16
|
+
_ColorbarColormapTableItem,
|
|
17
|
+
_config_value,
|
|
18
|
+
)
|
|
19
|
+
from ._config_persistence import persist_config_value
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
class _ColorbarScaleDialogBase:
|
|
23
|
+
_colorbar_colormap_name: str
|
|
24
|
+
_colorbar_manual_levels: tuple[float, float] | None
|
|
25
|
+
bar: Any
|
|
26
|
+
colorbar_auto_radio: qtw.QRadioButton
|
|
27
|
+
colorbar_button_group: qtw.QButtonGroup
|
|
28
|
+
colorbar_cet_subtype_checks: dict[str, qtw.QCheckBox]
|
|
29
|
+
colorbar_colormap_table: qtw.QTableWidget
|
|
30
|
+
colorbar_include_cet_check: qtw.QCheckBox
|
|
31
|
+
colorbar_include_custom_check: qtw.QCheckBox
|
|
32
|
+
colorbar_include_local_check: qtw.QCheckBox
|
|
33
|
+
colorbar_include_matplotlib_check: qtw.QCheckBox
|
|
34
|
+
colorbar_manual_radio: qtw.QRadioButton
|
|
35
|
+
colorbar_matplotlib_subtype_checks: dict[str, qtw.QCheckBox]
|
|
36
|
+
colorbar_max_label: qtw.QLabel
|
|
37
|
+
colorbar_max_text: qtw.QLineEdit
|
|
38
|
+
colorbar_min_label: qtw.QLabel
|
|
39
|
+
colorbar_min_text: qtw.QLineEdit
|
|
40
|
+
colorbar_copy_auto_limits_button: qtw.QToolButton
|
|
41
|
+
colorbar_scale_action: QtGui.QAction
|
|
42
|
+
colorbar_scale_controls: qtw.QWidget
|
|
43
|
+
colorbar_scale_dialog: qtw.QDialog
|
|
44
|
+
relevel_refresh: qtw.QCheckBox
|
|
45
|
+
|
|
46
|
+
def _available_colorbar_colormaps(self) -> tuple[str, ...]: ...
|
|
47
|
+
def _colorbar_colormap(self, name: str | None = None) -> Any: ...
|
|
48
|
+
def _current_colorbar_colormap_name(self) -> str: ...
|
|
49
|
+
def _current_colorbar_levels(self) -> tuple[float, float] | None: ...
|
|
50
|
+
def _data_colorbar_levels(self) -> tuple[float, float] | None: ...
|
|
51
|
+
def _set_colorbar_levels(self, vmin: float, vmax: float) -> None: ...
|
|
52
|
+
def scaleColorbar(self, event: Any = None) -> None: ...
|
|
53
|
+
def show_status(self, message: str, timeout: int = 5000) -> None: ...
|
|
54
|
+
def refreshWindow(self, force: bool = False) -> None: ...
|
|
55
|
+
else:
|
|
56
|
+
class _ColorbarScaleDialogBase:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class _ColorbarAutoLimitsButton(qtw.QToolButton):
|
|
61
|
+
"""Refresh its prospective-limit tooltip immediately before display."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, refresh_tooltip: Callable[[], None], parent: qtw.QWidget):
|
|
64
|
+
super().__init__(parent)
|
|
65
|
+
self._refresh_tooltip = refresh_tooltip
|
|
66
|
+
|
|
67
|
+
def event(self, event: QtCore.QEvent | None) -> bool:
|
|
68
|
+
if event is not None and event.type() == QtCore.QEvent.Type.ToolTip:
|
|
69
|
+
self._refresh_tooltip()
|
|
70
|
+
return super().event(event)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class _CenteredIconDelegate(qtw.QStyledItemDelegate):
|
|
74
|
+
"""
|
|
75
|
+
Paint icon-only table cells with the icon centered in the cell.
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def paint(self, painter, option, index):
|
|
80
|
+
icon = index.data(QtCore.Qt.ItemDataRole.DecorationRole)
|
|
81
|
+
if not isinstance(icon, QtGui.QIcon) or icon.isNull():
|
|
82
|
+
super().paint(painter, option, index)
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
opt = qtw.QStyleOptionViewItem(option)
|
|
86
|
+
self.initStyleOption(opt, index)
|
|
87
|
+
opt.text = ""
|
|
88
|
+
opt.icon = QtGui.QIcon()
|
|
89
|
+
|
|
90
|
+
widget = opt.widget
|
|
91
|
+
style = widget.style() if widget else qtw.QApplication.style()
|
|
92
|
+
if style is None:
|
|
93
|
+
super().paint(painter, option, index)
|
|
94
|
+
return
|
|
95
|
+
style.drawControl(qtw.QStyle.ControlElement.CE_ItemViewItem, opt, painter, widget)
|
|
96
|
+
|
|
97
|
+
icon_size = opt.decorationSize
|
|
98
|
+
if not icon_size.isValid() or icon_size.isEmpty():
|
|
99
|
+
icon_size = icon.actualSize(opt.rect.size())
|
|
100
|
+
icon_size = icon_size.boundedTo(opt.rect.size())
|
|
101
|
+
icon_rect = QtCore.QRect(QtCore.QPoint(0, 0), icon_size)
|
|
102
|
+
icon_rect.moveCenter(opt.rect.center())
|
|
103
|
+
|
|
104
|
+
mode = QtGui.QIcon.Mode.Normal
|
|
105
|
+
if not (opt.state & qtw.QStyle.StateFlag.State_Enabled):
|
|
106
|
+
mode = QtGui.QIcon.Mode.Disabled
|
|
107
|
+
elif opt.state & qtw.QStyle.StateFlag.State_Selected:
|
|
108
|
+
mode = QtGui.QIcon.Mode.Selected
|
|
109
|
+
|
|
110
|
+
icon.paint(painter, icon_rect, QtCore.Qt.AlignmentFlag.AlignCenter, mode)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class ColorbarScaleDialogMixin(_ColorbarScaleDialogBase):
|
|
114
|
+
"""
|
|
115
|
+
Dialog and table controls for heatmap color-scale configuration.
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def _init_colorbar_scale_controls(self):
|
|
120
|
+
"""
|
|
121
|
+
Build manual/auto color scale controls for the dialog.
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
controls = qtw.QWidget()
|
|
125
|
+
layout = qtw.QVBoxLayout(controls)
|
|
126
|
+
layout.setContentsMargins(6, 4, 6, 4)
|
|
127
|
+
layout.setSpacing(8)
|
|
128
|
+
|
|
129
|
+
self.colorbar_manual_radio = qtw.QRadioButton("Manual")
|
|
130
|
+
self.colorbar_auto_radio = qtw.QRadioButton("Auto")
|
|
131
|
+
self.colorbar_min_label = qtw.QLabel("Minimum")
|
|
132
|
+
self.colorbar_max_label = qtw.QLabel("Maximum")
|
|
133
|
+
self.colorbar_min_text = qtw.QLineEdit()
|
|
134
|
+
self.colorbar_max_text = qtw.QLineEdit()
|
|
135
|
+
self.colorbar_copy_auto_limits_button = _ColorbarAutoLimitsButton(
|
|
136
|
+
self._update_colorbar_auto_limits_tooltip,
|
|
137
|
+
controls,
|
|
138
|
+
)
|
|
139
|
+
self.colorbar_copy_auto_limits_button.setObjectName(
|
|
140
|
+
"colorbarCopyAutoLimitsButton"
|
|
141
|
+
)
|
|
142
|
+
self.colorbar_copy_auto_limits_button.setAccessibleName(
|
|
143
|
+
"Use auto color scale limits as manual limits"
|
|
144
|
+
)
|
|
145
|
+
self.colorbar_copy_auto_limits_button.setFixedSize(26, 24)
|
|
146
|
+
style = qtw.QApplication.style()
|
|
147
|
+
if style is not None:
|
|
148
|
+
self.colorbar_copy_auto_limits_button.setIcon(
|
|
149
|
+
style.standardIcon(qtw.QStyle.StandardPixmap.SP_BrowserReload)
|
|
150
|
+
)
|
|
151
|
+
self.colorbar_colormap_table = qtw.QTableWidget()
|
|
152
|
+
self.colorbar_include_cet_check = qtw.QCheckBox("CET")
|
|
153
|
+
self.colorbar_include_matplotlib_check = qtw.QCheckBox("Matplotlib")
|
|
154
|
+
self.colorbar_include_local_check = qtw.QCheckBox("Local")
|
|
155
|
+
self.colorbar_include_custom_check = qtw.QCheckBox("Custom")
|
|
156
|
+
self.colorbar_cet_subtype_checks = {}
|
|
157
|
+
self.colorbar_matplotlib_subtype_checks = {}
|
|
158
|
+
for subtype, label in _CET_COLORBAR_SUBTYPES:
|
|
159
|
+
self.colorbar_cet_subtype_checks[subtype] = qtw.QCheckBox(label)
|
|
160
|
+
for subtype, label in _MATPLOTLIB_COLORBAR_SUBTYPES:
|
|
161
|
+
self.colorbar_matplotlib_subtype_checks[subtype] = qtw.QCheckBox(label)
|
|
162
|
+
self._init_colorbar_colormap_table()
|
|
163
|
+
|
|
164
|
+
validator = QtGui.QDoubleValidator(cast(QtCore.QObject, self))
|
|
165
|
+
# Match Python's dot-decimal parsing/formatting regardless of Qt's
|
|
166
|
+
# default locale. Grouping must never change an input's meaning.
|
|
167
|
+
numeric_locale = QtCore.QLocale.c()
|
|
168
|
+
numeric_locale.setNumberOptions(
|
|
169
|
+
numeric_locale.numberOptions()
|
|
170
|
+
| QtCore.QLocale.NumberOption.RejectGroupSeparator
|
|
171
|
+
)
|
|
172
|
+
validator.setLocale(numeric_locale)
|
|
173
|
+
validator.setNotation(QtGui.QDoubleValidator.Notation.ScientificNotation)
|
|
174
|
+
self.colorbar_min_text.setValidator(validator)
|
|
175
|
+
self.colorbar_max_text.setValidator(validator)
|
|
176
|
+
self.colorbar_min_label.setBuddy(self.colorbar_min_text)
|
|
177
|
+
self.colorbar_max_label.setBuddy(self.colorbar_max_text)
|
|
178
|
+
self.colorbar_min_text.setAccessibleName("Color scale minimum")
|
|
179
|
+
self.colorbar_max_text.setAccessibleName("Color scale maximum")
|
|
180
|
+
for line_edit in (self.colorbar_min_text, self.colorbar_max_text):
|
|
181
|
+
line_edit.setMinimumWidth(80)
|
|
182
|
+
line_edit.setToolTip(
|
|
183
|
+
"Use a decimal point (e.g. 1.5 or 1.5e-3), without grouping separators."
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
self.colorbar_button_group = qtw.QButtonGroup(cast(QtCore.QObject, self))
|
|
187
|
+
self.colorbar_button_group.addButton(self.colorbar_manual_radio)
|
|
188
|
+
self.colorbar_button_group.addButton(self.colorbar_auto_radio)
|
|
189
|
+
self.colorbar_button_group.setExclusive(True)
|
|
190
|
+
|
|
191
|
+
range_controls = qtw.QWidget()
|
|
192
|
+
range_layout = qtw.QGridLayout(range_controls)
|
|
193
|
+
range_layout.setContentsMargins(0, 0, 0, 0)
|
|
194
|
+
range_layout.setHorizontalSpacing(4)
|
|
195
|
+
range_layout.setVerticalSpacing(4)
|
|
196
|
+
align_vcenter = QtCore.Qt.AlignmentFlag.AlignVCenter
|
|
197
|
+
range_layout.addWidget(self.colorbar_manual_radio, 0, 0, align_vcenter)
|
|
198
|
+
range_layout.setColumnMinimumWidth(1, 36)
|
|
199
|
+
range_layout.addWidget(self.colorbar_min_label, 0, 2, align_vcenter)
|
|
200
|
+
range_layout.addWidget(self.colorbar_min_text, 0, 3, align_vcenter)
|
|
201
|
+
range_layout.addWidget(self.colorbar_max_label, 0, 4, align_vcenter)
|
|
202
|
+
range_layout.addWidget(self.colorbar_max_text, 0, 5, align_vcenter)
|
|
203
|
+
range_layout.addWidget(
|
|
204
|
+
self.colorbar_copy_auto_limits_button,
|
|
205
|
+
0,
|
|
206
|
+
6,
|
|
207
|
+
align_vcenter,
|
|
208
|
+
)
|
|
209
|
+
range_layout.addWidget(self.colorbar_auto_radio, 1, 0)
|
|
210
|
+
|
|
211
|
+
filter_controls = self._init_colorbar_filter_controls()
|
|
212
|
+
|
|
213
|
+
layout.addWidget(qtw.QLabel("Colors"))
|
|
214
|
+
layout.addWidget(filter_controls)
|
|
215
|
+
layout.addWidget(self.colorbar_colormap_table, 1)
|
|
216
|
+
layout.addWidget(range_controls)
|
|
217
|
+
|
|
218
|
+
self.colorbar_scale_controls = controls
|
|
219
|
+
|
|
220
|
+
menu = getattr(self, "vbMenu", None)
|
|
221
|
+
if menu is not None:
|
|
222
|
+
self.colorbar_scale_action = QtGui.QAction("&Color Scale...", cast(QtCore.QObject, self))
|
|
223
|
+
self.colorbar_scale_action.triggered.connect(self.open_colorbar_scale_dialog)
|
|
224
|
+
before = getattr(self, "autoscaleSep", None)
|
|
225
|
+
menu.insertAction(before, self.colorbar_scale_action)
|
|
226
|
+
|
|
227
|
+
self.colorbar_colormap_table.itemSelectionChanged.connect(
|
|
228
|
+
self._colorbar_colormap_selection_changed
|
|
229
|
+
)
|
|
230
|
+
self.colorbar_include_cet_check.toggled.connect(
|
|
231
|
+
self._colorbar_include_cet_changed
|
|
232
|
+
)
|
|
233
|
+
self.colorbar_include_matplotlib_check.toggled.connect(
|
|
234
|
+
self._colorbar_include_matplotlib_changed
|
|
235
|
+
)
|
|
236
|
+
self.colorbar_include_local_check.toggled.connect(
|
|
237
|
+
self._colorbar_include_local_changed
|
|
238
|
+
)
|
|
239
|
+
self.colorbar_include_custom_check.toggled.connect(
|
|
240
|
+
self._colorbar_include_custom_changed
|
|
241
|
+
)
|
|
242
|
+
for subtype, widget in self.colorbar_cet_subtype_checks.items():
|
|
243
|
+
widget.toggled.connect(
|
|
244
|
+
lambda enabled, subtype=subtype: self._colorbar_include_subtype_changed(
|
|
245
|
+
"cet",
|
|
246
|
+
subtype,
|
|
247
|
+
enabled,
|
|
248
|
+
)
|
|
249
|
+
)
|
|
250
|
+
for subtype, widget in self.colorbar_matplotlib_subtype_checks.items():
|
|
251
|
+
widget.toggled.connect(
|
|
252
|
+
lambda enabled, subtype=subtype: self._colorbar_include_subtype_changed(
|
|
253
|
+
"matplotlib",
|
|
254
|
+
subtype,
|
|
255
|
+
enabled,
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
self.colorbar_manual_radio.clicked.connect(self._apply_colorbar_manual_fields)
|
|
259
|
+
self.colorbar_min_text.editingFinished.connect(self._apply_colorbar_manual_fields)
|
|
260
|
+
self.colorbar_max_text.editingFinished.connect(self._apply_colorbar_manual_fields)
|
|
261
|
+
self.colorbar_auto_radio.clicked.connect(self.setColorbarAuto)
|
|
262
|
+
self.colorbar_copy_auto_limits_button.clicked.connect(
|
|
263
|
+
self._copy_colorbar_auto_limits
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
self._sync_colorbar_scale_controls()
|
|
267
|
+
|
|
268
|
+
def _init_colorbar_filter_controls(self):
|
|
269
|
+
"""
|
|
270
|
+
Build broad and subtype color-map filter controls.
|
|
271
|
+
|
|
272
|
+
"""
|
|
273
|
+
controls = qtw.QWidget()
|
|
274
|
+
layout = qtw.QGridLayout(controls)
|
|
275
|
+
layout.setContentsMargins(0, 0, 0, 0)
|
|
276
|
+
layout.setHorizontalSpacing(8)
|
|
277
|
+
layout.setVerticalSpacing(2)
|
|
278
|
+
|
|
279
|
+
layout.addWidget(qtw.QLabel("Show"), 0, 0)
|
|
280
|
+
layout.addWidget(self.colorbar_include_cet_check, 0, 1)
|
|
281
|
+
layout.addWidget(self.colorbar_include_matplotlib_check, 0, 2)
|
|
282
|
+
layout.addWidget(self.colorbar_include_local_check, 0, 3)
|
|
283
|
+
layout.addWidget(self.colorbar_include_custom_check, 0, 4)
|
|
284
|
+
|
|
285
|
+
layout.addWidget(qtw.QLabel("CET"), 1, 0)
|
|
286
|
+
for column, (_subtype, widget) in enumerate(
|
|
287
|
+
self.colorbar_cet_subtype_checks.items(),
|
|
288
|
+
1,
|
|
289
|
+
):
|
|
290
|
+
layout.addWidget(widget, 1, column)
|
|
291
|
+
|
|
292
|
+
layout.addWidget(qtw.QLabel("Matplotlib"), 2, 0)
|
|
293
|
+
for column, (_subtype, widget) in enumerate(
|
|
294
|
+
self.colorbar_matplotlib_subtype_checks.items(),
|
|
295
|
+
1,
|
|
296
|
+
):
|
|
297
|
+
layout.addWidget(widget, 2, column)
|
|
298
|
+
|
|
299
|
+
layout.setColumnStretch(7, 1)
|
|
300
|
+
return controls
|
|
301
|
+
|
|
302
|
+
def _init_colorbar_colormap_table(self):
|
|
303
|
+
"""
|
|
304
|
+
Build the scrollable color-map chooser with rendered previews.
|
|
305
|
+
|
|
306
|
+
"""
|
|
307
|
+
table = self.colorbar_colormap_table
|
|
308
|
+
table.setColumnCount(3)
|
|
309
|
+
table.setHorizontalHeaderLabels(("Color map", "Preview", "Type"))
|
|
310
|
+
vertical_header = table.verticalHeader()
|
|
311
|
+
if vertical_header is not None:
|
|
312
|
+
vertical_header.hide()
|
|
313
|
+
table.setShowGrid(False)
|
|
314
|
+
table.setAlternatingRowColors(True)
|
|
315
|
+
table.setSelectionBehavior(qtw.QAbstractItemView.SelectionBehavior.SelectRows)
|
|
316
|
+
table.setSelectionMode(qtw.QAbstractItemView.SelectionMode.SingleSelection)
|
|
317
|
+
table.setEditTriggers(qtw.QAbstractItemView.EditTrigger.NoEditTriggers)
|
|
318
|
+
table.setSortingEnabled(True)
|
|
319
|
+
table.setMinimumSize(560, 360)
|
|
320
|
+
table.setIconSize(QtCore.QSize(220, 14))
|
|
321
|
+
table.setItemDelegateForColumn(1, _CenteredIconDelegate(table))
|
|
322
|
+
|
|
323
|
+
header = table.horizontalHeader()
|
|
324
|
+
if header is None:
|
|
325
|
+
return
|
|
326
|
+
header.setSectionResizeMode(0, qtw.QHeaderView.ResizeMode.ResizeToContents)
|
|
327
|
+
header.setSectionResizeMode(1, qtw.QHeaderView.ResizeMode.Stretch)
|
|
328
|
+
header.setSectionResizeMode(2, qtw.QHeaderView.ResizeMode.ResizeToContents)
|
|
329
|
+
|
|
330
|
+
self._populate_colorbar_colormap_table()
|
|
331
|
+
|
|
332
|
+
def _populate_colorbar_colormap_table(self):
|
|
333
|
+
"""
|
|
334
|
+
Fill the color-map table using the current filter settings.
|
|
335
|
+
|
|
336
|
+
"""
|
|
337
|
+
table = self.colorbar_colormap_table
|
|
338
|
+
table.blockSignals(True)
|
|
339
|
+
sorting_enabled = table.isSortingEnabled()
|
|
340
|
+
table.setSortingEnabled(False)
|
|
341
|
+
table.setRowCount(0)
|
|
342
|
+
|
|
343
|
+
colormaps = self._available_colorbar_colormaps()
|
|
344
|
+
table.setRowCount(len(colormaps))
|
|
345
|
+
for row, name in enumerate(colormaps):
|
|
346
|
+
label = _COLORBAR_COLORMAP_LABELS.get(name, name)
|
|
347
|
+
type_label = _colorbar_colormap_type_label(name)
|
|
348
|
+
name_item = _ColorbarColormapTableItem(label)
|
|
349
|
+
name_item.setData(QtCore.Qt.ItemDataRole.UserRole, name)
|
|
350
|
+
name_item.setData(_COLORBAR_TABLE_SORT_ROLE, label)
|
|
351
|
+
type_item = _ColorbarColormapTableItem(type_label)
|
|
352
|
+
type_item.setData(QtCore.Qt.ItemDataRole.UserRole, name)
|
|
353
|
+
type_item.setData(_COLORBAR_TABLE_SORT_ROLE, type_label)
|
|
354
|
+
preview_item = _ColorbarColormapTableItem()
|
|
355
|
+
preview_item.setData(QtCore.Qt.ItemDataRole.UserRole, name)
|
|
356
|
+
preview_item.setData(_COLORBAR_TABLE_SORT_ROLE, label)
|
|
357
|
+
preview_item.setIcon(QtGui.QIcon(_colorbar_colormap_preview(name)))
|
|
358
|
+
|
|
359
|
+
table.setItem(row, 0, name_item)
|
|
360
|
+
table.setItem(row, 1, preview_item)
|
|
361
|
+
table.setItem(row, 2, type_item)
|
|
362
|
+
table.setRowHeight(row, 20)
|
|
363
|
+
|
|
364
|
+
table.resizeColumnToContents(0)
|
|
365
|
+
table.resizeColumnToContents(2)
|
|
366
|
+
table.setSortingEnabled(sorting_enabled)
|
|
367
|
+
table.blockSignals(False)
|
|
368
|
+
|
|
369
|
+
def _sync_colorbar_filter_controls(self):
|
|
370
|
+
"""
|
|
371
|
+
Mirror persisted broad color-map filters into the dialog controls.
|
|
372
|
+
|
|
373
|
+
"""
|
|
374
|
+
config_obj = self.__dict__.get("config")
|
|
375
|
+
for widget, key in (
|
|
376
|
+
(
|
|
377
|
+
self.colorbar_include_cet_check,
|
|
378
|
+
"user_preference.bar_colour_include_cet",
|
|
379
|
+
),
|
|
380
|
+
(
|
|
381
|
+
self.colorbar_include_matplotlib_check,
|
|
382
|
+
"user_preference.bar_colour_include_matplotlib",
|
|
383
|
+
),
|
|
384
|
+
(
|
|
385
|
+
self.colorbar_include_local_check,
|
|
386
|
+
"user_preference.bar_colour_include_local",
|
|
387
|
+
),
|
|
388
|
+
(
|
|
389
|
+
self.colorbar_include_custom_check,
|
|
390
|
+
"user_preference.bar_colour_include_custom",
|
|
391
|
+
),
|
|
392
|
+
):
|
|
393
|
+
widget.blockSignals(True)
|
|
394
|
+
widget.setChecked(_config_value(config_obj, key, True))
|
|
395
|
+
widget.blockSignals(False)
|
|
396
|
+
|
|
397
|
+
include_cet = self.colorbar_include_cet_check.isChecked()
|
|
398
|
+
include_matplotlib = self.colorbar_include_matplotlib_check.isChecked()
|
|
399
|
+
for subtype, widget in self.colorbar_cet_subtype_checks.items():
|
|
400
|
+
key = _colorbar_subtype_config_key("cet", subtype)
|
|
401
|
+
widget.blockSignals(True)
|
|
402
|
+
widget.setChecked(_config_value(config_obj, key, True))
|
|
403
|
+
widget.setEnabled(include_cet)
|
|
404
|
+
widget.blockSignals(False)
|
|
405
|
+
|
|
406
|
+
for subtype, widget in self.colorbar_matplotlib_subtype_checks.items():
|
|
407
|
+
key = _colorbar_subtype_config_key("matplotlib", subtype)
|
|
408
|
+
widget.blockSignals(True)
|
|
409
|
+
widget.setChecked(_config_value(config_obj, key, True))
|
|
410
|
+
widget.setEnabled(include_matplotlib)
|
|
411
|
+
widget.blockSignals(False)
|
|
412
|
+
|
|
413
|
+
def _set_colorbar_filter_setting(self, key, enabled):
|
|
414
|
+
"""
|
|
415
|
+
Persist a broad color-map filter and rebuild the chooser.
|
|
416
|
+
|
|
417
|
+
"""
|
|
418
|
+
config_obj = self.__dict__.get("config")
|
|
419
|
+
if config_obj is not None:
|
|
420
|
+
if not persist_config_value(
|
|
421
|
+
self,
|
|
422
|
+
config_obj,
|
|
423
|
+
key,
|
|
424
|
+
bool(enabled),
|
|
425
|
+
"the color-map filter",
|
|
426
|
+
self._sync_colorbar_filter_controls,
|
|
427
|
+
):
|
|
428
|
+
return False
|
|
429
|
+
|
|
430
|
+
self._populate_colorbar_colormap_table()
|
|
431
|
+
self._sync_colorbar_scale_controls()
|
|
432
|
+
return True
|
|
433
|
+
|
|
434
|
+
def _set_colorbar_subtype_filter_setting(self, group, subtype, enabled):
|
|
435
|
+
"""
|
|
436
|
+
Persist a color-map subtype filter and rebuild the chooser.
|
|
437
|
+
|
|
438
|
+
"""
|
|
439
|
+
self._set_colorbar_filter_setting(
|
|
440
|
+
_colorbar_subtype_config_key(group, subtype),
|
|
441
|
+
enabled,
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
@QtCore.pyqtSlot(bool)
|
|
445
|
+
def _colorbar_include_cet_changed(self, enabled):
|
|
446
|
+
"""
|
|
447
|
+
Include or exclude CET color maps in the chooser.
|
|
448
|
+
|
|
449
|
+
"""
|
|
450
|
+
self._set_colorbar_filter_setting(
|
|
451
|
+
"user_preference.bar_colour_include_cet",
|
|
452
|
+
enabled,
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
@QtCore.pyqtSlot(bool)
|
|
456
|
+
def _colorbar_include_matplotlib_changed(self, enabled):
|
|
457
|
+
"""
|
|
458
|
+
Include or exclude matplotlib color maps in the chooser.
|
|
459
|
+
|
|
460
|
+
"""
|
|
461
|
+
self._set_colorbar_filter_setting(
|
|
462
|
+
"user_preference.bar_colour_include_matplotlib",
|
|
463
|
+
enabled,
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
@QtCore.pyqtSlot(bool)
|
|
467
|
+
def _colorbar_include_local_changed(self, enabled):
|
|
468
|
+
"""
|
|
469
|
+
Include or exclude pyqtgraph local color maps in the chooser.
|
|
470
|
+
|
|
471
|
+
"""
|
|
472
|
+
self._set_colorbar_filter_setting(
|
|
473
|
+
"user_preference.bar_colour_include_local",
|
|
474
|
+
enabled,
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
@QtCore.pyqtSlot(bool)
|
|
478
|
+
def _colorbar_include_custom_changed(self, enabled):
|
|
479
|
+
"""
|
|
480
|
+
Include or exclude app-provided custom color maps in the chooser.
|
|
481
|
+
|
|
482
|
+
"""
|
|
483
|
+
self._set_colorbar_filter_setting(
|
|
484
|
+
"user_preference.bar_colour_include_custom",
|
|
485
|
+
enabled,
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
def _colorbar_include_subtype_changed(self, group, subtype, enabled):
|
|
489
|
+
"""
|
|
490
|
+
Include or exclude a color-map subtype in the chooser.
|
|
491
|
+
|
|
492
|
+
"""
|
|
493
|
+
self._set_colorbar_subtype_filter_setting(group, subtype, enabled)
|
|
494
|
+
|
|
495
|
+
def _sync_colorbar_scale_controls(self):
|
|
496
|
+
"""
|
|
497
|
+
Update color scale controls from the current colorbar state.
|
|
498
|
+
|
|
499
|
+
"""
|
|
500
|
+
levels = self._current_colorbar_levels()
|
|
501
|
+
if levels is not None:
|
|
502
|
+
self._sync_colorbar_level_fields(*levels)
|
|
503
|
+
|
|
504
|
+
table = getattr(self, "colorbar_colormap_table", None)
|
|
505
|
+
if table is not None:
|
|
506
|
+
self._sync_colorbar_filter_controls()
|
|
507
|
+
self._select_colorbar_colormap(self._current_colorbar_colormap_name())
|
|
508
|
+
|
|
509
|
+
manual = getattr(self, "_colorbar_manual_levels", None) is not None
|
|
510
|
+
for widget in (self.colorbar_manual_radio, self.colorbar_auto_radio):
|
|
511
|
+
widget.blockSignals(True)
|
|
512
|
+
|
|
513
|
+
self.colorbar_manual_radio.setChecked(manual)
|
|
514
|
+
self.colorbar_auto_radio.setChecked(not manual)
|
|
515
|
+
self._update_colorbar_auto_limits_tooltip()
|
|
516
|
+
|
|
517
|
+
for widget in (self.colorbar_manual_radio, self.colorbar_auto_radio):
|
|
518
|
+
widget.blockSignals(False)
|
|
519
|
+
|
|
520
|
+
def _colorbar_auto_limits(self):
|
|
521
|
+
"""Return validated prospective automatic color-scale limits."""
|
|
522
|
+
|
|
523
|
+
levels = self._data_colorbar_levels()
|
|
524
|
+
if levels is None:
|
|
525
|
+
return None
|
|
526
|
+
try:
|
|
527
|
+
vmin, vmax = (float(value) for value in levels)
|
|
528
|
+
except (TypeError, ValueError):
|
|
529
|
+
return None
|
|
530
|
+
if not np.isfinite(vmin) or not np.isfinite(vmax) or vmin >= vmax:
|
|
531
|
+
return None
|
|
532
|
+
return vmin, vmax
|
|
533
|
+
|
|
534
|
+
def _update_colorbar_auto_limits_tooltip(self):
|
|
535
|
+
"""Describe the range that the copy-auto button would apply."""
|
|
536
|
+
|
|
537
|
+
button = self.colorbar_copy_auto_limits_button
|
|
538
|
+
levels = self._colorbar_auto_limits()
|
|
539
|
+
button.setEnabled(levels is not None)
|
|
540
|
+
if levels is None:
|
|
541
|
+
button.setToolTip("Auto limits are unavailable for the color scale.")
|
|
542
|
+
return
|
|
543
|
+
button.setToolTip(
|
|
544
|
+
f"Set manual limits to {levels[0]:.6g} and {levels[1]:.6g}."
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
@QtCore.pyqtSlot()
|
|
548
|
+
def _copy_colorbar_auto_limits(self):
|
|
549
|
+
"""Freeze the prospective automatic color range as a manual range."""
|
|
550
|
+
|
|
551
|
+
levels = self._colorbar_auto_limits()
|
|
552
|
+
if levels is None:
|
|
553
|
+
self._update_colorbar_auto_limits_tooltip()
|
|
554
|
+
return
|
|
555
|
+
if self.setColorbarManualRange(*levels):
|
|
556
|
+
self._sync_colorbar_level_fields(*levels)
|
|
557
|
+
self._update_colorbar_auto_limits_tooltip()
|
|
558
|
+
|
|
559
|
+
def _sync_colorbar_level_fields(self, vmin, vmax):
|
|
560
|
+
"""
|
|
561
|
+
Mirror colorbar levels into the dialog text fields.
|
|
562
|
+
|
|
563
|
+
"""
|
|
564
|
+
if "colorbar_min_text" not in self.__dict__:
|
|
565
|
+
return
|
|
566
|
+
|
|
567
|
+
for widget, value in (
|
|
568
|
+
(self.colorbar_min_text, vmin),
|
|
569
|
+
(self.colorbar_max_text, vmax),
|
|
570
|
+
):
|
|
571
|
+
widget.blockSignals(True)
|
|
572
|
+
widget.setText(repr(float(value)))
|
|
573
|
+
widget.blockSignals(False)
|
|
574
|
+
|
|
575
|
+
def _colorbar_colormap_row(self, name):
|
|
576
|
+
"""
|
|
577
|
+
Return the table row for a color map name.
|
|
578
|
+
|
|
579
|
+
"""
|
|
580
|
+
table = getattr(self, "colorbar_colormap_table", None)
|
|
581
|
+
if table is None:
|
|
582
|
+
return -1
|
|
583
|
+
|
|
584
|
+
for row in range(table.rowCount()):
|
|
585
|
+
item = table.item(row, 0)
|
|
586
|
+
if item is not None and item.data(QtCore.Qt.ItemDataRole.UserRole) == name:
|
|
587
|
+
return row
|
|
588
|
+
|
|
589
|
+
return -1
|
|
590
|
+
|
|
591
|
+
def _select_colorbar_colormap(self, name):
|
|
592
|
+
"""
|
|
593
|
+
Select the current color map row without applying it again.
|
|
594
|
+
|
|
595
|
+
"""
|
|
596
|
+
table = getattr(self, "colorbar_colormap_table", None)
|
|
597
|
+
if table is None:
|
|
598
|
+
return
|
|
599
|
+
|
|
600
|
+
row = self._colorbar_colormap_row(name)
|
|
601
|
+
if row < 0:
|
|
602
|
+
row = self._colorbar_colormap_row("viridis")
|
|
603
|
+
if row < 0:
|
|
604
|
+
return
|
|
605
|
+
|
|
606
|
+
table.blockSignals(True)
|
|
607
|
+
table.setCurrentCell(row, 0)
|
|
608
|
+
table.selectRow(row)
|
|
609
|
+
table.blockSignals(False)
|
|
610
|
+
|
|
611
|
+
@QtCore.pyqtSlot()
|
|
612
|
+
def _colorbar_colormap_selection_changed(self):
|
|
613
|
+
"""
|
|
614
|
+
Apply the color map selected in the dialog.
|
|
615
|
+
|
|
616
|
+
"""
|
|
617
|
+
table = self.colorbar_colormap_table
|
|
618
|
+
row = table.currentRow()
|
|
619
|
+
if row < 0:
|
|
620
|
+
return
|
|
621
|
+
|
|
622
|
+
item = table.item(row, 0)
|
|
623
|
+
if item is None:
|
|
624
|
+
return
|
|
625
|
+
|
|
626
|
+
name = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
|
627
|
+
if name is None:
|
|
628
|
+
return
|
|
629
|
+
|
|
630
|
+
self.setColorbarColorMap(name)
|
|
631
|
+
|
|
632
|
+
@QtCore.pyqtSlot(int)
|
|
633
|
+
def _colorbar_colormap_changed(self, index):
|
|
634
|
+
"""
|
|
635
|
+
Compatibility slot for older combo-box based tests or callers.
|
|
636
|
+
|
|
637
|
+
"""
|
|
638
|
+
combo = getattr(self, "colorbar_colormap_combo", None)
|
|
639
|
+
if combo is None:
|
|
640
|
+
return
|
|
641
|
+
|
|
642
|
+
name = combo.itemData(index)
|
|
643
|
+
if name is not None:
|
|
644
|
+
self.setColorbarColorMap(name)
|
|
645
|
+
|
|
646
|
+
@QtCore.pyqtSlot()
|
|
647
|
+
def open_colorbar_scale_dialog(self):
|
|
648
|
+
"""
|
|
649
|
+
Opens the color scale controls in a dialog.
|
|
650
|
+
|
|
651
|
+
"""
|
|
652
|
+
controls = getattr(self, "colorbar_scale_controls", None)
|
|
653
|
+
if controls is None:
|
|
654
|
+
return
|
|
655
|
+
|
|
656
|
+
self._populate_colorbar_colormap_table()
|
|
657
|
+
self._sync_colorbar_scale_controls()
|
|
658
|
+
|
|
659
|
+
dialog = getattr(self, "colorbar_scale_dialog", None)
|
|
660
|
+
if dialog is None:
|
|
661
|
+
dialog = qtw.QDialog(cast(qtw.QWidget, self))
|
|
662
|
+
dialog.setWindowTitle("Color scale")
|
|
663
|
+
dialog.resize(520, 560)
|
|
664
|
+
layout = qtw.QVBoxLayout(dialog)
|
|
665
|
+
layout.addWidget(controls)
|
|
666
|
+
|
|
667
|
+
buttons = qtw.QDialogButtonBox(qtw.QDialogButtonBox.StandardButton.Close)
|
|
668
|
+
buttons.rejected.connect(dialog.close)
|
|
669
|
+
layout.addWidget(buttons)
|
|
670
|
+
|
|
671
|
+
self.colorbar_scale_dialog = dialog
|
|
672
|
+
|
|
673
|
+
dialog.show()
|
|
674
|
+
dialog.raise_()
|
|
675
|
+
dialog.activateWindow()
|
|
676
|
+
|
|
677
|
+
@QtCore.pyqtSlot()
|
|
678
|
+
def _apply_colorbar_manual_fields(self):
|
|
679
|
+
"""
|
|
680
|
+
Apply color scale levels entered in the dialog.
|
|
681
|
+
|
|
682
|
+
"""
|
|
683
|
+
if not all(
|
|
684
|
+
field.hasAcceptableInput()
|
|
685
|
+
for field in (self.colorbar_min_text, self.colorbar_max_text)
|
|
686
|
+
):
|
|
687
|
+
self.show_status("Invalid color scale range.", 5000)
|
|
688
|
+
self._sync_colorbar_scale_controls()
|
|
689
|
+
return
|
|
690
|
+
|
|
691
|
+
try:
|
|
692
|
+
vmin = float(self.colorbar_min_text.text())
|
|
693
|
+
vmax = float(self.colorbar_max_text.text())
|
|
694
|
+
except ValueError:
|
|
695
|
+
self.show_status("Invalid color scale range.", 5000)
|
|
696
|
+
self._sync_colorbar_scale_controls()
|
|
697
|
+
return
|
|
698
|
+
|
|
699
|
+
self.setColorbarManualRange(vmin, vmax)
|
|
700
|
+
|
|
701
|
+
def setColorbarColorMap(self, name):
|
|
702
|
+
"""
|
|
703
|
+
Set and persist the colorbar color map.
|
|
704
|
+
|
|
705
|
+
"""
|
|
706
|
+
if name not in self._available_colorbar_colormaps():
|
|
707
|
+
show_status = getattr(self, "show_status", None)
|
|
708
|
+
if show_status is not None:
|
|
709
|
+
show_status("Unknown color map.", 5000)
|
|
710
|
+
return False
|
|
711
|
+
|
|
712
|
+
config_obj = self.__dict__.get("config")
|
|
713
|
+
if config_obj is not None:
|
|
714
|
+
previous_name = config_obj.get("user_preference.bar_colour")
|
|
715
|
+
|
|
716
|
+
def rollback():
|
|
717
|
+
self._select_colorbar_colormap(previous_name)
|
|
718
|
+
|
|
719
|
+
if not persist_config_value(
|
|
720
|
+
self,
|
|
721
|
+
config_obj,
|
|
722
|
+
"user_preference.bar_colour",
|
|
723
|
+
name,
|
|
724
|
+
"the color map",
|
|
725
|
+
rollback,
|
|
726
|
+
):
|
|
727
|
+
return False
|
|
728
|
+
|
|
729
|
+
self._colorbar_colormap_name = name
|
|
730
|
+
bar = self.__dict__.get("bar")
|
|
731
|
+
if bar is not None:
|
|
732
|
+
bar.setColorMap(self._colorbar_colormap(name))
|
|
733
|
+
|
|
734
|
+
appearance_dialog = self.__dict__.get("_heatmap_appearance_dialog")
|
|
735
|
+
if appearance_dialog is not None:
|
|
736
|
+
appearance_dialog.refresh_color_scale()
|
|
737
|
+
|
|
738
|
+
return True
|
|
739
|
+
|
|
740
|
+
def setColorbarManualRange(self, vmin, vmax):
|
|
741
|
+
"""
|
|
742
|
+
Set a persistent manual color scale range.
|
|
743
|
+
|
|
744
|
+
"""
|
|
745
|
+
if not np.isfinite(vmin) or not np.isfinite(vmax) or vmin >= vmax:
|
|
746
|
+
self.show_status("Color scale minimum must be below maximum.", 5000)
|
|
747
|
+
self._sync_colorbar_scale_controls()
|
|
748
|
+
return False
|
|
749
|
+
|
|
750
|
+
if not np.isfinite(float(vmax) - float(vmin)):
|
|
751
|
+
self.show_status("The color scale range is too wide to display safely.", 5000)
|
|
752
|
+
self._sync_colorbar_scale_controls()
|
|
753
|
+
return False
|
|
754
|
+
|
|
755
|
+
self._colorbar_manual_levels = (float(vmin), float(vmax))
|
|
756
|
+
|
|
757
|
+
if "relevel_refresh" in self.__dict__:
|
|
758
|
+
self.relevel_refresh.setChecked(False)
|
|
759
|
+
|
|
760
|
+
self._set_colorbar_levels(*self._colorbar_manual_levels)
|
|
761
|
+
if "colorbar_manual_radio" in self.__dict__:
|
|
762
|
+
self.colorbar_manual_radio.setChecked(True)
|
|
763
|
+
if self.__dict__.get("_heatmap_color_range_rejected", False):
|
|
764
|
+
self.refreshWindow(force=True)
|
|
765
|
+
return True
|
|
766
|
+
|
|
767
|
+
@QtCore.pyqtSlot()
|
|
768
|
+
def setColorbarAuto(self):
|
|
769
|
+
"""
|
|
770
|
+
Return the color scale to automatic data-range scaling.
|
|
771
|
+
|
|
772
|
+
"""
|
|
773
|
+
self._colorbar_manual_levels = None
|
|
774
|
+
if "relevel_refresh" in self.__dict__:
|
|
775
|
+
self.relevel_refresh.setChecked(True)
|
|
776
|
+
self.scaleColorbar()
|
|
777
|
+
|
|
778
|
+
@QtCore.pyqtSlot(bool)
|
|
779
|
+
def _colorbar_auto_refresh_changed(self, enabled):
|
|
780
|
+
"""
|
|
781
|
+
Keep colorbar manual state in sync with the refresh toolbar checkbox.
|
|
782
|
+
|
|
783
|
+
"""
|
|
784
|
+
if enabled:
|
|
785
|
+
self._colorbar_manual_levels = None
|
|
786
|
+
self.scaleColorbar()
|