bec-widgets 0.78.1__py3-none-any.whl → 0.79.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.
- CHANGELOG.md +26 -26
- PKG-INFO +1 -1
- bec_widgets/cli/client.py +90 -0
- bec_widgets/utils/bec_designer.py +14 -12
- bec_widgets/utils/widget_io.py +25 -2
- bec_widgets/widgets/figure/plots/axis_settings.py +61 -0
- bec_widgets/widgets/figure/plots/axis_settings.ui +249 -0
- bec_widgets/widgets/figure/plots/motor_map/motor_map.py +18 -5
- bec_widgets/widgets/motor_map/__init__.py +0 -0
- bec_widgets/widgets/motor_map/assets/connection.svg +4 -0
- bec_widgets/widgets/motor_map/assets/history.svg +4 -0
- bec_widgets/widgets/motor_map/assets/motor_map.png +0 -0
- bec_widgets/widgets/motor_map/assets/settings.svg +4 -0
- bec_widgets/widgets/motor_map/bec_motor_map_widget.pyproject +1 -0
- bec_widgets/widgets/motor_map/bec_motor_map_widget_plugin.py +55 -0
- bec_widgets/widgets/motor_map/motor_map_dialog/__init__.py +0 -0
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.py +73 -0
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.ui +108 -0
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_toolbar.py +59 -0
- bec_widgets/widgets/motor_map/motor_map_widget.py +235 -0
- bec_widgets/widgets/motor_map/register_bec_motor_map_widget.py +15 -0
- bec_widgets/widgets/toolbar/toolbar.py +43 -103
- {bec_widgets-0.78.1.dist-info → bec_widgets-0.79.1.dist-info}/METADATA +1 -1
- {bec_widgets-0.78.1.dist-info → bec_widgets-0.79.1.dist-info}/RECORD +28 -13
- pyproject.toml +1 -1
- {bec_widgets-0.78.1.dist-info → bec_widgets-0.79.1.dist-info}/WHEEL +0 -0
- {bec_widgets-0.78.1.dist-info → bec_widgets-0.79.1.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.78.1.dist-info → bec_widgets-0.79.1.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v0.79.1 (2024-07-03)
|
4
|
+
|
5
|
+
### Fix
|
6
|
+
|
7
|
+
* fix: use libdir env var to preload Python library, also for Linux platform ([`d7718d4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d7718d4dcb9728c050b6421388af4d484f3741f2))
|
8
|
+
|
9
|
+
## v0.79.0 (2024-07-03)
|
10
|
+
|
11
|
+
### Feature
|
12
|
+
|
13
|
+
* feat(motor_map_widget): standalone MotorMap Widget with toolbar + plugin ([`6e75642`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6e756420907d7093557e945bc92bc4cfc0138d07))
|
14
|
+
|
15
|
+
* feat(motor_map): method to reset history trace ([`5960918`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5960918137dd41cdeb94e50f8abc4f169cf45c11))
|
16
|
+
|
17
|
+
### Fix
|
18
|
+
|
19
|
+
* fix(toolbar): change default color to black to match BECFigure theme ([`b8774e0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b8774e0b0bc43dcd00f94f42539a778e507ca27d))
|
20
|
+
|
21
|
+
* fix(motor_map): fixed bug with residual trace after changing motors ([`aaa0d10`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/aaa0d1003d2e94b45bafe4f700852c2c05288aea))
|
22
|
+
|
23
|
+
* fix(widget_io): widget handler adjusted for spinboxes and comboboxes ([`3dc0532`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3dc0532df05b6ec0a2522107fa0b1e210ce7d91b))
|
24
|
+
|
25
|
+
### Refactor
|
26
|
+
|
27
|
+
* refactor(toolbar): cleanup and adjusted colors ([`96863ad`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/96863adf53c15112645d20eb6200733617801c6d))
|
28
|
+
|
3
29
|
## v0.78.1 (2024-07-02)
|
4
30
|
|
5
31
|
### Fix
|
@@ -123,29 +149,3 @@
|
|
123
149
|
### Fix
|
124
150
|
|
125
151
|
* fix(vscode): only run terminate if the process is still alive ([`7120f3e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7120f3e93b054b788f15e2d5bcd688e3c140c1ce))
|
126
|
-
|
127
|
-
* fix(rpc): trigger shutdown of server when gui is terminated ([`acc1318`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/acc13183e28030e3ca9af21bb081e1eed081622b))
|
128
|
-
|
129
|
-
* fix(rpc): remove of calling "close" and waiting for gui_is_alive ([`f75fc19`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f75fc19c5b10022763252917ca473f404a25165a))
|
130
|
-
|
131
|
-
## v0.73.1 (2024-06-25)
|
132
|
-
|
133
|
-
### Fix
|
134
|
-
|
135
|
-
* fix(ringprogressbar): removed hard-coded endpoint strings ([`1de3cbf`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1de3cbf65a1832150917a7549a1bf3efdee6371a))
|
136
|
-
|
137
|
-
## v0.73.0 (2024-06-25)
|
138
|
-
|
139
|
-
### Feature
|
140
|
-
|
141
|
-
* feat: add new default scaling of image_item ([`df812ea`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/df812eaad5989f2930dde41d87491868505af946))
|
142
|
-
|
143
|
-
### Test
|
144
|
-
|
145
|
-
* test: add test for imageitem ([`88ecd05`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/88ecd05b95974938ef1efff40e81854baf004cb4))
|
146
|
-
|
147
|
-
## v0.72.2 (2024-06-25)
|
148
|
-
|
149
|
-
### Fix
|
150
|
-
|
151
|
-
* fix(designer): fixed designer for pyenv and venv; closes #237 ([`e631fc1`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e631fc15d8707b73d58cb64316e115a7e43961ea))
|
PKG-INFO
CHANGED
bec_widgets/cli/client.py
CHANGED
@@ -18,6 +18,7 @@ class Widgets(str, enum.Enum):
|
|
18
18
|
BECDock = "BECDock"
|
19
19
|
BECDockArea = "BECDockArea"
|
20
20
|
BECFigure = "BECFigure"
|
21
|
+
BECMotorMapWidget = "BECMotorMapWidget"
|
21
22
|
RingProgressBar = "RingProgressBar"
|
22
23
|
ScanControl = "ScanControl"
|
23
24
|
TextBox = "TextBox"
|
@@ -1192,6 +1193,7 @@ class BECMotorMap(RPCBase):
|
|
1192
1193
|
def get_data(self) -> "dict":
|
1193
1194
|
"""
|
1194
1195
|
Get the data of the motor map.
|
1196
|
+
|
1195
1197
|
Returns:
|
1196
1198
|
dict: Data of the motor map.
|
1197
1199
|
"""
|
@@ -1202,6 +1204,94 @@ class BECMotorMap(RPCBase):
|
|
1202
1204
|
Remove the plot widget from the figure.
|
1203
1205
|
"""
|
1204
1206
|
|
1207
|
+
@rpc_call
|
1208
|
+
def reset_history(self):
|
1209
|
+
"""
|
1210
|
+
Reset the history of the motor map.
|
1211
|
+
"""
|
1212
|
+
|
1213
|
+
|
1214
|
+
class BECMotorMapWidget(RPCBase):
|
1215
|
+
@rpc_call
|
1216
|
+
def change_motors(
|
1217
|
+
self,
|
1218
|
+
motor_x: "str",
|
1219
|
+
motor_y: "str",
|
1220
|
+
motor_x_entry: "str" = None,
|
1221
|
+
motor_y_entry: "str" = None,
|
1222
|
+
validate_bec: "bool" = True,
|
1223
|
+
) -> "None":
|
1224
|
+
"""
|
1225
|
+
Change the active motors for the plot.
|
1226
|
+
|
1227
|
+
Args:
|
1228
|
+
motor_x(str): Motor name for the X axis.
|
1229
|
+
motor_y(str): Motor name for the Y axis.
|
1230
|
+
motor_x_entry(str): Motor entry for the X axis.
|
1231
|
+
motor_y_entry(str): Motor entry for the Y axis.
|
1232
|
+
validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
|
1233
|
+
"""
|
1234
|
+
|
1235
|
+
@rpc_call
|
1236
|
+
def set_max_points(self, max_points: "int") -> "None":
|
1237
|
+
"""
|
1238
|
+
Set the maximum number of points to display on the motor map.
|
1239
|
+
|
1240
|
+
Args:
|
1241
|
+
max_points(int): Maximum number of points to display.
|
1242
|
+
"""
|
1243
|
+
|
1244
|
+
@rpc_call
|
1245
|
+
def set_precision(self, precision: "int") -> "None":
|
1246
|
+
"""
|
1247
|
+
Set the precision of the motor map.
|
1248
|
+
|
1249
|
+
Args:
|
1250
|
+
precision(int): Precision to set.
|
1251
|
+
"""
|
1252
|
+
|
1253
|
+
@rpc_call
|
1254
|
+
def set_num_dim_points(self, num_dim_points: "int") -> "None":
|
1255
|
+
"""
|
1256
|
+
Set the number of points to display on the motor map.
|
1257
|
+
|
1258
|
+
Args:
|
1259
|
+
num_dim_points(int): Number of points to display.
|
1260
|
+
"""
|
1261
|
+
|
1262
|
+
@rpc_call
|
1263
|
+
def set_background_value(self, background_value: "int") -> "None":
|
1264
|
+
"""
|
1265
|
+
Set the background value of the motor map.
|
1266
|
+
|
1267
|
+
Args:
|
1268
|
+
background_value(int): Background value of the motor map.
|
1269
|
+
"""
|
1270
|
+
|
1271
|
+
@rpc_call
|
1272
|
+
def set_scatter_size(self, scatter_size: "int") -> "None":
|
1273
|
+
"""
|
1274
|
+
Set the scatter size of the motor map.
|
1275
|
+
|
1276
|
+
Args:
|
1277
|
+
scatter_size(int): Scatter size of the motor map.
|
1278
|
+
"""
|
1279
|
+
|
1280
|
+
@rpc_call
|
1281
|
+
def get_data(self) -> "dict":
|
1282
|
+
"""
|
1283
|
+
Get the data of the motor map.
|
1284
|
+
|
1285
|
+
Returns:
|
1286
|
+
dict: Data of the motor map.
|
1287
|
+
"""
|
1288
|
+
|
1289
|
+
@rpc_call
|
1290
|
+
def reset_history(self) -> "None":
|
1291
|
+
"""
|
1292
|
+
Reset the history of the motor map.
|
1293
|
+
"""
|
1294
|
+
|
1205
1295
|
|
1206
1296
|
class BECPlotBase(RPCBase):
|
1207
1297
|
@property
|
@@ -73,26 +73,28 @@ def patch_designer(): # pragma: no cover
|
|
73
73
|
os.environ["PY_MAJOR_VERSION"] = str(major_version)
|
74
74
|
os.environ["PY_MINOR_VERSION"] = str(minor_version)
|
75
75
|
|
76
|
-
if sys.platform == "
|
76
|
+
if sys.platform == "win32":
|
77
|
+
if is_virtual_env():
|
78
|
+
_extend_path_var("PATH", os.fspath(Path(sys._base_executable).parent), True)
|
79
|
+
else:
|
80
|
+
if sys.platform == "linux":
|
81
|
+
suffix = f"{sys.abiflags}.so"
|
82
|
+
env_var = "LD_PRELOAD"
|
83
|
+
elif sys.platform == "darwin":
|
84
|
+
suffix = ".dylib"
|
85
|
+
env_var = "DYLD_INSERT_LIBRARIES"
|
86
|
+
else:
|
87
|
+
raise RuntimeError(f"Unsupported platform: {sys.platform}")
|
77
88
|
version = f"{major_version}.{minor_version}"
|
78
|
-
library_name = f"libpython{version}{
|
79
|
-
if is_pyenv_python():
|
80
|
-
library_name = str(Path(sysconfig.get_config_var("LIBDIR")) / library_name)
|
81
|
-
os.environ["LD_PRELOAD"] = library_name
|
82
|
-
elif sys.platform == "darwin":
|
83
|
-
library_name = f"libpython{major_version}.{minor_version}.dylib"
|
89
|
+
library_name = f"libpython{version}{suffix}"
|
84
90
|
lib_path = str(Path(sysconfig.get_config_var("LIBDIR")) / library_name)
|
85
|
-
os.environ[
|
91
|
+
os.environ[env_var] = lib_path
|
86
92
|
|
87
93
|
if is_pyenv_python() or is_virtual_env():
|
88
94
|
# append all editable packages to the PYTHONPATH
|
89
95
|
editable_packages = list_editable_packages()
|
90
96
|
for pckg in editable_packages:
|
91
97
|
_extend_path_var("PYTHONPATH", pckg, True)
|
92
|
-
elif sys.platform == "win32":
|
93
|
-
if is_virtual_env():
|
94
|
-
_extend_path_var("PATH", os.fspath(Path(sys._base_executable).parent), True)
|
95
|
-
|
96
98
|
qt_tool_wrapper(ui_tool_binary("designer"), sys.argv[1:])
|
97
99
|
|
98
100
|
|
bec_widgets/utils/widget_io.py
CHANGED
@@ -44,8 +44,11 @@ class ComboBoxHandler(WidgetHandler):
|
|
44
44
|
def get_value(self, widget: QComboBox) -> int:
|
45
45
|
return widget.currentIndex()
|
46
46
|
|
47
|
-
def set_value(self, widget: QComboBox, value: int) -> None:
|
48
|
-
|
47
|
+
def set_value(self, widget: QComboBox, value: int | str) -> None:
|
48
|
+
if isinstance(value, str):
|
49
|
+
value = widget.findText(value)
|
50
|
+
if isinstance(value, int):
|
51
|
+
widget.setCurrentIndex(value)
|
49
52
|
|
50
53
|
|
51
54
|
class TableWidgetHandler(WidgetHandler):
|
@@ -142,6 +145,26 @@ class WidgetIO:
|
|
142
145
|
elif not ignore_errors:
|
143
146
|
raise ValueError(f"No handler for widget type: {type(widget)}")
|
144
147
|
|
148
|
+
@staticmethod
|
149
|
+
def check_and_adjust_limits(spin_box: QDoubleSpinBox, number: float):
|
150
|
+
"""
|
151
|
+
Check if the new limits are within the current limits, if not adjust the limits.
|
152
|
+
|
153
|
+
Args:
|
154
|
+
number(float): The new value to check against the limits.
|
155
|
+
"""
|
156
|
+
|
157
|
+
min_value = spin_box.minimum()
|
158
|
+
max_value = spin_box.maximum()
|
159
|
+
|
160
|
+
# Calculate the new limits
|
161
|
+
new_limit = number + 5 * number
|
162
|
+
|
163
|
+
if number < min_value:
|
164
|
+
spin_box.setMinimum(new_limit)
|
165
|
+
elif number > max_value:
|
166
|
+
spin_box.setMaximum(new_limit)
|
167
|
+
|
145
168
|
@staticmethod
|
146
169
|
def _find_handler(widget):
|
147
170
|
"""
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import qdarktheme
|
4
|
+
from qtpy.QtCore import Slot
|
5
|
+
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
6
|
+
|
7
|
+
from bec_widgets.utils import UILoader
|
8
|
+
from bec_widgets.utils.widget_io import WidgetIO
|
9
|
+
|
10
|
+
|
11
|
+
class AxisSettings(QWidget):
|
12
|
+
def __init__(self, parent=None, *args, **kwargs):
|
13
|
+
super().__init__(parent=parent, *args, **kwargs)
|
14
|
+
|
15
|
+
current_path = os.path.dirname(__file__)
|
16
|
+
self.ui = UILoader().load_ui(os.path.join(current_path, "axis_settings.ui"), self)
|
17
|
+
|
18
|
+
self.layout = QVBoxLayout(self)
|
19
|
+
self.layout.addWidget(self.ui)
|
20
|
+
|
21
|
+
# Hardcoded values for best appearance
|
22
|
+
self.setMinimumHeight(280)
|
23
|
+
self.setMaximumHeight(280)
|
24
|
+
self.resize(380, 280)
|
25
|
+
|
26
|
+
@Slot(dict)
|
27
|
+
def display_current_settings(self, axis_config: dict):
|
28
|
+
# Top Box
|
29
|
+
WidgetIO.set_value(self.ui.plot_title, axis_config["title"])
|
30
|
+
|
31
|
+
# X Axis Box
|
32
|
+
WidgetIO.set_value(self.ui.x_label, axis_config["x_label"])
|
33
|
+
WidgetIO.set_value(self.ui.x_scale, axis_config["x_scale"])
|
34
|
+
WidgetIO.set_value(self.ui.x_grid, axis_config["x_grid"])
|
35
|
+
if axis_config["x_lim"] is not None:
|
36
|
+
WidgetIO.check_and_adjust_limits(self.ui.x_min, axis_config["x_lim"][0])
|
37
|
+
WidgetIO.check_and_adjust_limits(self.ui.x_max, axis_config["x_lim"][1])
|
38
|
+
WidgetIO.set_value(self.ui.x_min, axis_config["x_lim"][0])
|
39
|
+
WidgetIO.set_value(self.ui.x_max, axis_config["x_lim"][1])
|
40
|
+
|
41
|
+
# Y Axis Box
|
42
|
+
WidgetIO.set_value(self.ui.y_label, axis_config["y_label"])
|
43
|
+
WidgetIO.set_value(self.ui.y_scale, axis_config["y_scale"])
|
44
|
+
WidgetIO.set_value(self.ui.y_grid, axis_config["y_grid"])
|
45
|
+
if axis_config["y_lim"] is not None:
|
46
|
+
WidgetIO.check_and_adjust_limits(self.ui.y_min, axis_config["y_lim"][0])
|
47
|
+
WidgetIO.check_and_adjust_limits(self.ui.y_max, axis_config["y_lim"][1])
|
48
|
+
WidgetIO.set_value(self.ui.y_min, axis_config["y_lim"][0])
|
49
|
+
WidgetIO.set_value(self.ui.y_max, axis_config["y_lim"][1])
|
50
|
+
|
51
|
+
|
52
|
+
if __name__ == "__main__":
|
53
|
+
import sys
|
54
|
+
|
55
|
+
from qtpy.QtWidgets import QApplication
|
56
|
+
|
57
|
+
app = QApplication(sys.argv)
|
58
|
+
qdarktheme.setup_theme("dark")
|
59
|
+
window = AxisSettings()
|
60
|
+
window.show()
|
61
|
+
sys.exit(app.exec_())
|
@@ -0,0 +1,249 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<ui version="4.0">
|
3
|
+
<class>Form</class>
|
4
|
+
<widget class="QWidget" name="Form">
|
5
|
+
<property name="geometry">
|
6
|
+
<rect>
|
7
|
+
<x>0</x>
|
8
|
+
<y>0</y>
|
9
|
+
<width>417</width>
|
10
|
+
<height>250</height>
|
11
|
+
</rect>
|
12
|
+
</property>
|
13
|
+
<property name="minimumSize">
|
14
|
+
<size>
|
15
|
+
<width>0</width>
|
16
|
+
<height>250</height>
|
17
|
+
</size>
|
18
|
+
</property>
|
19
|
+
<property name="maximumSize">
|
20
|
+
<size>
|
21
|
+
<width>16777215</width>
|
22
|
+
<height>278</height>
|
23
|
+
</size>
|
24
|
+
</property>
|
25
|
+
<property name="windowTitle">
|
26
|
+
<string>Form</string>
|
27
|
+
</property>
|
28
|
+
<layout class="QGridLayout" name="gridLayout">
|
29
|
+
<item row="0" column="0" colspan="3">
|
30
|
+
<layout class="QHBoxLayout" name="horizontalLayout">
|
31
|
+
<item>
|
32
|
+
<widget class="QLabel" name="plot_title_label">
|
33
|
+
<property name="text">
|
34
|
+
<string>Plot Title</string>
|
35
|
+
</property>
|
36
|
+
</widget>
|
37
|
+
</item>
|
38
|
+
<item>
|
39
|
+
<widget class="QLineEdit" name="plot_title"/>
|
40
|
+
</item>
|
41
|
+
</layout>
|
42
|
+
</item>
|
43
|
+
<item row="1" column="0" colspan="3">
|
44
|
+
<widget class="Line" name="line_H">
|
45
|
+
<property name="orientation">
|
46
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
47
|
+
</property>
|
48
|
+
</widget>
|
49
|
+
</item>
|
50
|
+
<item row="2" column="0">
|
51
|
+
<widget class="QGroupBox" name="x_axis_box">
|
52
|
+
<property name="title">
|
53
|
+
<string>X Axis</string>
|
54
|
+
</property>
|
55
|
+
<layout class="QGridLayout" name="gridLayout_4">
|
56
|
+
<item row="3" column="0">
|
57
|
+
<widget class="QLabel" name="x_scale_label">
|
58
|
+
<property name="text">
|
59
|
+
<string>Scale</string>
|
60
|
+
</property>
|
61
|
+
</widget>
|
62
|
+
</item>
|
63
|
+
<item row="1" column="2">
|
64
|
+
<widget class="QDoubleSpinBox" name="x_min">
|
65
|
+
<property name="alignment">
|
66
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
67
|
+
</property>
|
68
|
+
<property name="minimum">
|
69
|
+
<double>-9999.000000000000000</double>
|
70
|
+
</property>
|
71
|
+
<property name="maximum">
|
72
|
+
<double>9999.000000000000000</double>
|
73
|
+
</property>
|
74
|
+
</widget>
|
75
|
+
</item>
|
76
|
+
<item row="1" column="0" colspan="2">
|
77
|
+
<widget class="QLabel" name="x_min_label">
|
78
|
+
<property name="text">
|
79
|
+
<string>Min</string>
|
80
|
+
</property>
|
81
|
+
</widget>
|
82
|
+
</item>
|
83
|
+
<item row="2" column="2">
|
84
|
+
<widget class="QDoubleSpinBox" name="x_max">
|
85
|
+
<property name="alignment">
|
86
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
87
|
+
</property>
|
88
|
+
<property name="minimum">
|
89
|
+
<double>-9999.000000000000000</double>
|
90
|
+
</property>
|
91
|
+
<property name="maximum">
|
92
|
+
<double>9999.000000000000000</double>
|
93
|
+
</property>
|
94
|
+
</widget>
|
95
|
+
</item>
|
96
|
+
<item row="3" column="2">
|
97
|
+
<widget class="QComboBox" name="x_scale">
|
98
|
+
<item>
|
99
|
+
<property name="text">
|
100
|
+
<string>linear</string>
|
101
|
+
</property>
|
102
|
+
</item>
|
103
|
+
<item>
|
104
|
+
<property name="text">
|
105
|
+
<string>log</string>
|
106
|
+
</property>
|
107
|
+
</item>
|
108
|
+
</widget>
|
109
|
+
</item>
|
110
|
+
<item row="2" column="0">
|
111
|
+
<widget class="QLabel" name="x_max_label">
|
112
|
+
<property name="text">
|
113
|
+
<string>Max</string>
|
114
|
+
</property>
|
115
|
+
</widget>
|
116
|
+
</item>
|
117
|
+
<item row="0" column="2">
|
118
|
+
<widget class="QLineEdit" name="x_label"/>
|
119
|
+
</item>
|
120
|
+
<item row="0" column="0">
|
121
|
+
<widget class="QLabel" name="x_label_label">
|
122
|
+
<property name="text">
|
123
|
+
<string>Label</string>
|
124
|
+
</property>
|
125
|
+
</widget>
|
126
|
+
</item>
|
127
|
+
<item row="4" column="2">
|
128
|
+
<widget class="QCheckBox" name="x_grid">
|
129
|
+
<property name="text">
|
130
|
+
<string/>
|
131
|
+
</property>
|
132
|
+
</widget>
|
133
|
+
</item>
|
134
|
+
<item row="4" column="0">
|
135
|
+
<widget class="QLabel" name="x_grid_label">
|
136
|
+
<property name="text">
|
137
|
+
<string>Grid</string>
|
138
|
+
</property>
|
139
|
+
</widget>
|
140
|
+
</item>
|
141
|
+
</layout>
|
142
|
+
</widget>
|
143
|
+
</item>
|
144
|
+
<item row="2" column="1">
|
145
|
+
<widget class="Line" name="line_V">
|
146
|
+
<property name="orientation">
|
147
|
+
<enum>Qt::Orientation::Vertical</enum>
|
148
|
+
</property>
|
149
|
+
</widget>
|
150
|
+
</item>
|
151
|
+
<item row="2" column="2">
|
152
|
+
<widget class="QGroupBox" name="y_axis_box">
|
153
|
+
<property name="title">
|
154
|
+
<string>Y Axis</string>
|
155
|
+
</property>
|
156
|
+
<layout class="QGridLayout" name="gridLayout_5">
|
157
|
+
<item row="3" column="2">
|
158
|
+
<widget class="QComboBox" name="y_scale">
|
159
|
+
<item>
|
160
|
+
<property name="text">
|
161
|
+
<string>linear</string>
|
162
|
+
</property>
|
163
|
+
</item>
|
164
|
+
<item>
|
165
|
+
<property name="text">
|
166
|
+
<string>log</string>
|
167
|
+
</property>
|
168
|
+
</item>
|
169
|
+
</widget>
|
170
|
+
</item>
|
171
|
+
<item row="2" column="2">
|
172
|
+
<widget class="QDoubleSpinBox" name="y_max">
|
173
|
+
<property name="alignment">
|
174
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
175
|
+
</property>
|
176
|
+
<property name="minimum">
|
177
|
+
<double>-9999.000000000000000</double>
|
178
|
+
</property>
|
179
|
+
<property name="maximum">
|
180
|
+
<double>9999.000000000000000</double>
|
181
|
+
</property>
|
182
|
+
</widget>
|
183
|
+
</item>
|
184
|
+
<item row="1" column="0" colspan="2">
|
185
|
+
<widget class="QLabel" name="y_min_label">
|
186
|
+
<property name="text">
|
187
|
+
<string>Min</string>
|
188
|
+
</property>
|
189
|
+
</widget>
|
190
|
+
</item>
|
191
|
+
<item row="1" column="2">
|
192
|
+
<widget class="QDoubleSpinBox" name="y_min">
|
193
|
+
<property name="alignment">
|
194
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
195
|
+
</property>
|
196
|
+
<property name="minimum">
|
197
|
+
<double>-9999.000000000000000</double>
|
198
|
+
</property>
|
199
|
+
<property name="maximum">
|
200
|
+
<double>9999.000000000000000</double>
|
201
|
+
</property>
|
202
|
+
</widget>
|
203
|
+
</item>
|
204
|
+
<item row="0" column="2">
|
205
|
+
<widget class="QLineEdit" name="y_label"/>
|
206
|
+
</item>
|
207
|
+
<item row="3" column="0">
|
208
|
+
<widget class="QLabel" name="y_scale_label">
|
209
|
+
<property name="text">
|
210
|
+
<string>Scale</string>
|
211
|
+
</property>
|
212
|
+
</widget>
|
213
|
+
</item>
|
214
|
+
<item row="0" column="0">
|
215
|
+
<widget class="QLabel" name="y_label_label">
|
216
|
+
<property name="text">
|
217
|
+
<string>Label</string>
|
218
|
+
</property>
|
219
|
+
</widget>
|
220
|
+
</item>
|
221
|
+
<item row="2" column="0">
|
222
|
+
<widget class="QLabel" name="y_max_label">
|
223
|
+
<property name="text">
|
224
|
+
<string>Max</string>
|
225
|
+
</property>
|
226
|
+
</widget>
|
227
|
+
</item>
|
228
|
+
<item row="4" column="2">
|
229
|
+
<widget class="QCheckBox" name="y_grid">
|
230
|
+
<property name="text">
|
231
|
+
<string/>
|
232
|
+
</property>
|
233
|
+
</widget>
|
234
|
+
</item>
|
235
|
+
<item row="4" column="0">
|
236
|
+
<widget class="QLabel" name="y_grid_label">
|
237
|
+
<property name="text">
|
238
|
+
<string>Grid</string>
|
239
|
+
</property>
|
240
|
+
</widget>
|
241
|
+
</item>
|
242
|
+
</layout>
|
243
|
+
</widget>
|
244
|
+
</item>
|
245
|
+
</layout>
|
246
|
+
</widget>
|
247
|
+
<resources/>
|
248
|
+
<connections/>
|
249
|
+
</ui>
|
@@ -10,7 +10,7 @@ from pydantic import Field, ValidationError, field_validator
|
|
10
10
|
from pydantic_core import PydanticCustomError
|
11
11
|
from qtpy import QtCore, QtGui
|
12
12
|
from qtpy.QtCore import Signal as pyqtSignal
|
13
|
-
from qtpy.QtCore import Slot
|
13
|
+
from qtpy.QtCore import Slot
|
14
14
|
from qtpy.QtWidgets import QWidget
|
15
15
|
|
16
16
|
from bec_widgets.utils import Colors, EntryValidator
|
@@ -24,7 +24,7 @@ class MotorMapConfig(SubplotConfig):
|
|
24
24
|
(255, 255, 255, 255), description="The color of the last point of current position."
|
25
25
|
)
|
26
26
|
scatter_size: Optional[int] = Field(5, description="Size of the scatter points.")
|
27
|
-
max_points: Optional[int] = Field(
|
27
|
+
max_points: Optional[int] = Field(5000, description="Maximum number of points to display.")
|
28
28
|
num_dim_points: Optional[int] = Field(
|
29
29
|
100,
|
30
30
|
description="Number of points to dim before the color remains same for older recorded position.",
|
@@ -59,6 +59,7 @@ class BECMotorMap(BECPlotBase):
|
|
59
59
|
"set_scatter_size",
|
60
60
|
"get_data",
|
61
61
|
"remove",
|
62
|
+
"reset_history",
|
62
63
|
]
|
63
64
|
|
64
65
|
# QT Signals
|
@@ -120,7 +121,7 @@ class BECMotorMap(BECPlotBase):
|
|
120
121
|
motor_y_entry=self.config.signals.y.entry,
|
121
122
|
)
|
122
123
|
|
123
|
-
@
|
124
|
+
@Slot(str, str, str, str, bool)
|
124
125
|
def change_motors(
|
125
126
|
self,
|
126
127
|
motor_x: str,
|
@@ -139,6 +140,8 @@ class BECMotorMap(BECPlotBase):
|
|
139
140
|
motor_y_entry(str): Motor entry for the Y axis.
|
140
141
|
validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
|
141
142
|
"""
|
143
|
+
self.plot_item.clear()
|
144
|
+
|
142
145
|
motor_x_entry, motor_y_entry = self._validate_signal_entries(
|
143
146
|
motor_x, motor_y, motor_x_entry, motor_y_entry, validate_bec
|
144
147
|
)
|
@@ -164,13 +167,22 @@ class BECMotorMap(BECPlotBase):
|
|
164
167
|
def get_data(self) -> dict:
|
165
168
|
"""
|
166
169
|
Get the data of the motor map.
|
170
|
+
|
167
171
|
Returns:
|
168
172
|
dict: Data of the motor map.
|
169
173
|
"""
|
170
174
|
data = {"x": self.database_buffer["x"], "y": self.database_buffer["y"]}
|
171
175
|
return data
|
172
176
|
|
173
|
-
def
|
177
|
+
def reset_history(self):
|
178
|
+
"""
|
179
|
+
Reset the history of the motor map.
|
180
|
+
"""
|
181
|
+
self.database_buffer["x"] = [self.database_buffer["x"][-1]]
|
182
|
+
self.database_buffer["y"] = [self.database_buffer["y"][-1]]
|
183
|
+
self.update_signal.emit()
|
184
|
+
|
185
|
+
def set_color(self, color: str | tuple):
|
174
186
|
"""
|
175
187
|
Set color of the motor trace.
|
176
188
|
|
@@ -428,6 +440,7 @@ class BECMotorMap(BECPlotBase):
|
|
428
440
|
print(f"The device '{motor}' does not have defined limits.")
|
429
441
|
return None
|
430
442
|
|
443
|
+
@Slot()
|
431
444
|
def _update_plot(self):
|
432
445
|
"""Update the motor map plot."""
|
433
446
|
# If the number of points exceeds max_points, delete the oldest points
|
@@ -477,7 +490,7 @@ class BECMotorMap(BECPlotBase):
|
|
477
490
|
f"Motor position: ({round(float(current_x),precision)}, {round(float(current_y),precision)})"
|
478
491
|
)
|
479
492
|
|
480
|
-
@
|
493
|
+
@Slot(dict)
|
481
494
|
def on_device_readback(self, msg: dict) -> None:
|
482
495
|
"""
|
483
496
|
Update the motor map plot with the new motor position.
|
File without changes
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#FFFFFF">
|
2
|
+
<path d="M0 0h24v24H0V0z" fill="none"/>
|
3
|
+
<path d="M17 7h-4v2h4c1.65 0 3 1.35 3 3s-1.35 3-3 3h-4v2h4c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-6 8H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-2zm-3-4h8v2H8z"/>
|
4
|
+
</svg>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#FFFFFF">
|
2
|
+
<path d="M0 0h24v24H0V0z" fill="none"/>
|
3
|
+
<path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.25 2.52.77-1.28-3.52-2.09V8z"/>
|
4
|
+
</svg>
|