bec-widgets 0.87.0__py3-none-any.whl → 0.88.0__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 +66 -70
- PKG-INFO +1 -1
- bec_widgets/assets/designer_icons/BECWaveformWidget.png +0 -0
- bec_widgets/assets/designer_icons/colormap_selector.png +0 -0
- bec_widgets/assets/toolbar_icons/add.svg +3 -0
- bec_widgets/assets/toolbar_icons/auto_range.svg +3 -0
- bec_widgets/assets/toolbar_icons/drag_pan_mode.svg +3 -0
- bec_widgets/assets/toolbar_icons/export.svg +9 -0
- bec_widgets/assets/toolbar_icons/fitting_parameters.svg +3 -0
- bec_widgets/assets/toolbar_icons/import.svg +9 -0
- bec_widgets/assets/toolbar_icons/line_axis.svg +3 -0
- bec_widgets/assets/toolbar_icons/photo_library.svg +3 -0
- bec_widgets/assets/toolbar_icons/rectangle_mode.svg +3 -0
- bec_widgets/assets/toolbar_icons/remove.svg +5 -0
- bec_widgets/assets/toolbar_icons/save.svg +3 -0
- bec_widgets/assets/toolbar_icons/settings.svg +4 -0
- bec_widgets/cli/client.py +307 -5
- bec_widgets/cli/server.py +2 -1
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +13 -7
- bec_widgets/examples/plugin_example_pyside/tictactoe.py +1 -0
- bec_widgets/utils/bec_connector.py +19 -18
- bec_widgets/utils/bec_widget.py +19 -4
- bec_widgets/widgets/base_classes/device_input_base.py +3 -5
- bec_widgets/widgets/bec_queue/bec_queue.py +3 -2
- bec_widgets/widgets/bec_status_box/bec_status_box.py +2 -11
- bec_widgets/widgets/{color_map_selector/color_map_selector.py → colormap_selector/colormap_selector.py} +3 -1
- bec_widgets/widgets/colormap_selector/colormap_selector.pyproject +1 -0
- bec_widgets/widgets/{color_map_selector/color_map_selector_plugin.py → colormap_selector/colormap_selector_plugin.py} +8 -6
- bec_widgets/widgets/{color_map_selector/register_color_map_selector.py → colormap_selector/register_colormap_selector.py} +1 -1
- bec_widgets/widgets/device_box/device_box.py +2 -2
- bec_widgets/widgets/device_combobox/device_combobox.py +1 -8
- bec_widgets/widgets/device_line_edit/device_line_edit.py +2 -9
- bec_widgets/widgets/dock/dock.py +8 -6
- bec_widgets/widgets/dock/dock_area.py +4 -2
- bec_widgets/widgets/figure/figure.py +16 -8
- bec_widgets/widgets/figure/plots/axis_settings.py +38 -11
- bec_widgets/widgets/figure/plots/image/image.py +2 -4
- bec_widgets/widgets/figure/plots/motor_map/motor_map.py +1 -1
- bec_widgets/widgets/figure/plots/plot_base.py +7 -8
- bec_widgets/widgets/figure/plots/waveform/waveform.py +49 -53
- bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +10 -1
- bec_widgets/widgets/jupyter_console/jupyter_console.py +6 -0
- bec_widgets/widgets/motor_map/bec_motor_map_widget_plugin.py +1 -1
- bec_widgets/widgets/motor_map/motor_map_widget.py +9 -6
- bec_widgets/widgets/ring_progress_bar/ring.py +0 -4
- bec_widgets/widgets/ring_progress_bar/ring_progress_bar.py +8 -8
- bec_widgets/widgets/scan_control/scan_control.py +2 -6
- bec_widgets/widgets/stop_button/stop_button.py +2 -2
- bec_widgets/widgets/text_box/text_box.py +3 -2
- bec_widgets/widgets/waveform/__init__.py +0 -0
- bec_widgets/widgets/waveform/bec_waveform_widget.pyproject +1 -0
- bec_widgets/widgets/waveform/bec_waveform_widget_plugin.py +59 -0
- bec_widgets/widgets/waveform/register_bec_waveform_widget.py +15 -0
- bec_widgets/widgets/waveform/waveform_toolbar/__init__.py +0 -0
- bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/__init__.py +0 -0
- bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py +341 -0
- bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui +358 -0
- bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/__init__.py +0 -0
- bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/dap_summary.ui +127 -0
- bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/dap_summary_dialog.py +69 -0
- bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py +117 -0
- bec_widgets/widgets/waveform/waveform_widget.py +571 -0
- bec_widgets/widgets/website/website.py +2 -2
- {bec_widgets-0.87.0.dist-info → bec_widgets-0.88.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.87.0.dist-info → bec_widgets-0.88.0.dist-info}/RECORD +75 -48
- pyproject.toml +1 -1
- tests/unit_tests/test_color_map_selector.py +1 -1
- tests/unit_tests/test_device_input_base.py +10 -4
- tests/unit_tests/test_waveform_widget.py +264 -0
- bec_widgets/widgets/color_map_selector/assets/color_map_selector_icon.png +0 -0
- bec_widgets/widgets/color_map_selector/color_map_selector.pyproject +0 -1
- /bec_widgets/assets/{bec_widgets_icon.png → app_icons/bec_widgets_icon.png} +0 -0
- /bec_widgets/assets/{terminal_icon.png → app_icons/terminal_icon.png} +0 -0
- /bec_widgets/widgets/{color_map_selector → colormap_selector}/__init__.py +0 -0
- {bec_widgets-0.87.0.dist-info → bec_widgets-0.88.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.87.0.dist-info → bec_widgets-0.88.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.87.0.dist-info → bec_widgets-0.88.0.dist-info}/licenses/LICENSE +0 -0
bec_widgets/cli/client.py
CHANGED
@@ -19,6 +19,7 @@ class Widgets(str, enum.Enum):
|
|
19
19
|
BECMotorMapWidget = "BECMotorMapWidget"
|
20
20
|
BECQueue = "BECQueue"
|
21
21
|
BECStatusBox = "BECStatusBox"
|
22
|
+
BECWaveformWidget = "BECWaveformWidget"
|
22
23
|
DeviceBox = "DeviceBox"
|
23
24
|
DeviceComboBox = "DeviceComboBox"
|
24
25
|
DeviceLineEdit = "DeviceLineEdit"
|
@@ -184,7 +185,7 @@ class BECDock(RPCBase):
|
|
184
185
|
|
185
186
|
@property
|
186
187
|
@rpc_call
|
187
|
-
def widget_list(self) -> "list[
|
188
|
+
def widget_list(self) -> "list[BECWidget]":
|
188
189
|
"""
|
189
190
|
Get the widgets in the dock.
|
190
191
|
|
@@ -225,13 +226,13 @@ class BECDock(RPCBase):
|
|
225
226
|
@rpc_call
|
226
227
|
def add_widget(
|
227
228
|
self,
|
228
|
-
widget: "
|
229
|
+
widget: "BECWidget | str",
|
229
230
|
row=None,
|
230
231
|
col=0,
|
231
232
|
rowspan=1,
|
232
233
|
colspan=1,
|
233
234
|
shift: "Literal['down', 'up', 'left', 'right']" = "down",
|
234
|
-
) -> "
|
235
|
+
) -> "BECWidget":
|
235
236
|
"""
|
236
237
|
Add a widget to the dock.
|
237
238
|
|
@@ -614,6 +615,12 @@ class BECFigure(RPCBase):
|
|
614
615
|
theme(Literal["dark","light"]): The theme to set for the figure widget.
|
615
616
|
"""
|
616
617
|
|
618
|
+
@rpc_call
|
619
|
+
def export(self):
|
620
|
+
"""
|
621
|
+
Export the plot widget.
|
622
|
+
"""
|
623
|
+
|
617
624
|
@rpc_call
|
618
625
|
def clear_all(self):
|
619
626
|
"""
|
@@ -1096,6 +1103,12 @@ class BECImageShow(RPCBase):
|
|
1096
1103
|
lock(bool): True to lock, False to unlock.
|
1097
1104
|
"""
|
1098
1105
|
|
1106
|
+
@rpc_call
|
1107
|
+
def export(self):
|
1108
|
+
"""
|
1109
|
+
Show the Export Dialog of the plot widget.
|
1110
|
+
"""
|
1111
|
+
|
1099
1112
|
@rpc_call
|
1100
1113
|
def remove(self):
|
1101
1114
|
"""
|
@@ -1204,6 +1217,12 @@ class BECMotorMap(RPCBase):
|
|
1204
1217
|
dict: Data of the motor map.
|
1205
1218
|
"""
|
1206
1219
|
|
1220
|
+
@rpc_call
|
1221
|
+
def export(self):
|
1222
|
+
"""
|
1223
|
+
Show the Export Dialog of the plot widget.
|
1224
|
+
"""
|
1225
|
+
|
1207
1226
|
@rpc_call
|
1208
1227
|
def remove(self):
|
1209
1228
|
"""
|
@@ -1298,6 +1317,12 @@ class BECMotorMapWidget(RPCBase):
|
|
1298
1317
|
Reset the history of the motor map.
|
1299
1318
|
"""
|
1300
1319
|
|
1320
|
+
@rpc_call
|
1321
|
+
def export(self):
|
1322
|
+
"""
|
1323
|
+
Show the export dialog for the motor map.
|
1324
|
+
"""
|
1325
|
+
|
1301
1326
|
|
1302
1327
|
class BECPlotBase(RPCBase):
|
1303
1328
|
@property
|
@@ -1426,6 +1451,12 @@ class BECPlotBase(RPCBase):
|
|
1426
1451
|
lock(bool): True to lock, False to unlock.
|
1427
1452
|
"""
|
1428
1453
|
|
1454
|
+
@rpc_call
|
1455
|
+
def export(self):
|
1456
|
+
"""
|
1457
|
+
Show the Export Dialog of the plot widget.
|
1458
|
+
"""
|
1459
|
+
|
1429
1460
|
@rpc_call
|
1430
1461
|
def remove(self):
|
1431
1462
|
"""
|
@@ -1563,8 +1594,6 @@ class BECWaveform(RPCBase):
|
|
1563
1594
|
y_name(str): Name of the y signal.
|
1564
1595
|
y_entry(str): Entry of the y signal.
|
1565
1596
|
color(str, optional): Color of the curve. Defaults to None.
|
1566
|
-
color_map_z(str): The color map to use for the z-axis.
|
1567
|
-
label(str, optional): Label of the curve. Defaults to None.
|
1568
1597
|
dap(str): The dap model to use for the curve.
|
1569
1598
|
validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
|
1570
1599
|
**kwargs: Additional keyword arguments for the curve configuration.
|
@@ -1756,6 +1785,15 @@ class BECWaveform(RPCBase):
|
|
1756
1785
|
y(bool): Show grid on the y-axis.
|
1757
1786
|
"""
|
1758
1787
|
|
1788
|
+
@rpc_call
|
1789
|
+
def set_colormap(self, colormap: "str | None" = None):
|
1790
|
+
"""
|
1791
|
+
Set the colormap of the plot widget.
|
1792
|
+
|
1793
|
+
Args:
|
1794
|
+
colormap(str, optional): Scale the colors of curves to colormap. If None, use the default color palette.
|
1795
|
+
"""
|
1796
|
+
|
1759
1797
|
@rpc_call
|
1760
1798
|
def lock_aspect_ratio(self, lock):
|
1761
1799
|
"""
|
@@ -1765,6 +1803,12 @@ class BECWaveform(RPCBase):
|
|
1765
1803
|
lock(bool): True to lock, False to unlock.
|
1766
1804
|
"""
|
1767
1805
|
|
1806
|
+
@rpc_call
|
1807
|
+
def export(self):
|
1808
|
+
"""
|
1809
|
+
Show the Export Dialog of the plot widget.
|
1810
|
+
"""
|
1811
|
+
|
1768
1812
|
@rpc_call
|
1769
1813
|
def remove(self):
|
1770
1814
|
"""
|
@@ -1787,6 +1831,264 @@ class BECWaveform(RPCBase):
|
|
1787
1831
|
"""
|
1788
1832
|
|
1789
1833
|
|
1834
|
+
class BECWaveformWidget(RPCBase):
|
1835
|
+
@property
|
1836
|
+
@rpc_call
|
1837
|
+
def curves(self) -> "list[BECCurve]":
|
1838
|
+
"""
|
1839
|
+
Get the curves of the plot widget as a list
|
1840
|
+
Returns:
|
1841
|
+
list: List of curves.
|
1842
|
+
"""
|
1843
|
+
|
1844
|
+
@rpc_call
|
1845
|
+
def plot(
|
1846
|
+
self,
|
1847
|
+
arg1: "list | np.ndarray | str | None" = None,
|
1848
|
+
x: "list | np.ndarray | None" = None,
|
1849
|
+
y: "list | np.ndarray | None" = None,
|
1850
|
+
x_name: "str | None" = None,
|
1851
|
+
y_name: "str | None" = None,
|
1852
|
+
z_name: "str | None" = None,
|
1853
|
+
x_entry: "str | None" = None,
|
1854
|
+
y_entry: "str | None" = None,
|
1855
|
+
z_entry: "str | None" = None,
|
1856
|
+
color: "str | None" = None,
|
1857
|
+
color_map_z: "str | None" = "plasma",
|
1858
|
+
label: "str | None" = None,
|
1859
|
+
validate: "bool" = True,
|
1860
|
+
dap: "str | None" = None,
|
1861
|
+
**kwargs,
|
1862
|
+
) -> "BECCurve":
|
1863
|
+
"""
|
1864
|
+
Plot a curve to the plot widget.
|
1865
|
+
Args:
|
1866
|
+
arg1(list | np.ndarray | str | None): First argument which can be x data(list | np.ndarray), y data(list | np.ndarray), or y_name(str).
|
1867
|
+
x(list | np.ndarray): Custom x data to plot.
|
1868
|
+
y(list | np.ndarray): Custom y data to plot.
|
1869
|
+
x_name(str): The name of the device for the x-axis.
|
1870
|
+
y_name(str): The name of the device for the y-axis.
|
1871
|
+
z_name(str): The name of the device for the z-axis.
|
1872
|
+
x_entry(str): The name of the entry for the x-axis.
|
1873
|
+
y_entry(str): The name of the entry for the y-axis.
|
1874
|
+
z_entry(str): The name of the entry for the z-axis.
|
1875
|
+
color(str): The color of the curve.
|
1876
|
+
color_map_z(str): The color map to use for the z-axis.
|
1877
|
+
label(str): The label of the curve.
|
1878
|
+
validate(bool): If True, validate the device names and entries.
|
1879
|
+
dap(str): The dap model to use for the curve. If not specified, none will be added.
|
1880
|
+
|
1881
|
+
Returns:
|
1882
|
+
BECCurve: The curve object.
|
1883
|
+
"""
|
1884
|
+
|
1885
|
+
@rpc_call
|
1886
|
+
def add_dap(
|
1887
|
+
self,
|
1888
|
+
x_name: "str",
|
1889
|
+
y_name: "str",
|
1890
|
+
x_entry: "str | None" = None,
|
1891
|
+
y_entry: "str | None" = None,
|
1892
|
+
color: "str | None" = None,
|
1893
|
+
dap: "str" = "GaussianModel",
|
1894
|
+
validate_bec: "bool" = True,
|
1895
|
+
**kwargs,
|
1896
|
+
) -> "BECCurve":
|
1897
|
+
"""
|
1898
|
+
Add LMFIT dap model curve to the plot widget.
|
1899
|
+
|
1900
|
+
Args:
|
1901
|
+
x_name(str): Name of the x signal.
|
1902
|
+
x_entry(str): Entry of the x signal.
|
1903
|
+
y_name(str): Name of the y signal.
|
1904
|
+
y_entry(str): Entry of the y signal.
|
1905
|
+
color(str, optional): Color of the curve. Defaults to None.
|
1906
|
+
dap(str): The dap model to use for the curve.
|
1907
|
+
validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
|
1908
|
+
**kwargs: Additional keyword arguments for the curve configuration.
|
1909
|
+
|
1910
|
+
Returns:
|
1911
|
+
BECCurve: The curve object.
|
1912
|
+
"""
|
1913
|
+
|
1914
|
+
@rpc_call
|
1915
|
+
def get_dap_params(self) -> "dict":
|
1916
|
+
"""
|
1917
|
+
Get the DAP parameters of all DAP curves.
|
1918
|
+
|
1919
|
+
Returns:
|
1920
|
+
dict: DAP parameters of all DAP curves.
|
1921
|
+
"""
|
1922
|
+
|
1923
|
+
@rpc_call
|
1924
|
+
def remove_curve(self, *identifiers):
|
1925
|
+
"""
|
1926
|
+
Remove a curve from the plot widget.
|
1927
|
+
|
1928
|
+
Args:
|
1929
|
+
*identifiers: Identifier of the curve to be removed. Can be either an integer (index) or a string (curve_id).
|
1930
|
+
"""
|
1931
|
+
|
1932
|
+
@rpc_call
|
1933
|
+
def scan_history(self, scan_index: "int" = None, scan_id: "str" = None):
|
1934
|
+
"""
|
1935
|
+
Update the scan curves with the data from the scan storage.
|
1936
|
+
Provide only one of scan_id or scan_index.
|
1937
|
+
|
1938
|
+
Args:
|
1939
|
+
scan_id(str, optional): ScanID of the scan to be updated. Defaults to None.
|
1940
|
+
scan_index(int, optional): Index of the scan to be updated. Defaults to None.
|
1941
|
+
"""
|
1942
|
+
|
1943
|
+
@rpc_call
|
1944
|
+
def get_all_data(self, output: "Literal['dict', 'pandas']" = "dict") -> "dict | pd.DataFrame":
|
1945
|
+
"""
|
1946
|
+
Extract all curve data into a dictionary or a pandas DataFrame.
|
1947
|
+
|
1948
|
+
Args:
|
1949
|
+
output (Literal["dict", "pandas"]): Format of the output data.
|
1950
|
+
|
1951
|
+
Returns:
|
1952
|
+
dict | pd.DataFrame: Data of all curves in the specified format.
|
1953
|
+
"""
|
1954
|
+
|
1955
|
+
@rpc_call
|
1956
|
+
def set(self, **kwargs):
|
1957
|
+
"""
|
1958
|
+
Set the properties of the plot widget.
|
1959
|
+
|
1960
|
+
Args:
|
1961
|
+
**kwargs: Keyword arguments for the properties to be set.
|
1962
|
+
|
1963
|
+
Possible properties:
|
1964
|
+
- title: str
|
1965
|
+
- x_label: str
|
1966
|
+
- y_label: str
|
1967
|
+
- x_scale: Literal["linear", "log"]
|
1968
|
+
- y_scale: Literal["linear", "log"]
|
1969
|
+
- x_lim: tuple
|
1970
|
+
- y_lim: tuple
|
1971
|
+
- legend_label_size: int
|
1972
|
+
"""
|
1973
|
+
|
1974
|
+
@rpc_call
|
1975
|
+
def set_x(self, x_name: "str", x_entry: "str | None" = None):
|
1976
|
+
"""
|
1977
|
+
Change the x axis of the plot widget.
|
1978
|
+
|
1979
|
+
Args:
|
1980
|
+
x_name(str): Name of the x signal.
|
1981
|
+
- "best_effort": Use the best effort signal.
|
1982
|
+
- "timestamp": Use the timestamp signal.
|
1983
|
+
- "index": Use the index signal.
|
1984
|
+
- Custom signal name of device from BEC.
|
1985
|
+
x_entry(str): Entry of the x signal.
|
1986
|
+
"""
|
1987
|
+
|
1988
|
+
@rpc_call
|
1989
|
+
def set_title(self, title: "str"):
|
1990
|
+
"""
|
1991
|
+
Set the title of the plot widget.
|
1992
|
+
|
1993
|
+
Args:
|
1994
|
+
title(str): Title of the plot.
|
1995
|
+
"""
|
1996
|
+
|
1997
|
+
@rpc_call
|
1998
|
+
def set_x_label(self, x_label: "str"):
|
1999
|
+
"""
|
2000
|
+
Set the x-axis label of the plot widget.
|
2001
|
+
|
2002
|
+
Args:
|
2003
|
+
x_label(str): Label of the x-axis.
|
2004
|
+
"""
|
2005
|
+
|
2006
|
+
@rpc_call
|
2007
|
+
def set_y_label(self, y_label: "str"):
|
2008
|
+
"""
|
2009
|
+
Set the y-axis label of the plot widget.
|
2010
|
+
|
2011
|
+
Args:
|
2012
|
+
y_label(str): Label of the y-axis.
|
2013
|
+
"""
|
2014
|
+
|
2015
|
+
@rpc_call
|
2016
|
+
def set_x_scale(self, x_scale: "Literal['linear', 'log']"):
|
2017
|
+
"""
|
2018
|
+
Set the scale of the x-axis of the plot widget.
|
2019
|
+
|
2020
|
+
Args:
|
2021
|
+
x_scale(Literal["linear", "log"]): Scale of the x-axis.
|
2022
|
+
"""
|
2023
|
+
|
2024
|
+
@rpc_call
|
2025
|
+
def set_y_scale(self, y_scale: "Literal['linear', 'log']"):
|
2026
|
+
"""
|
2027
|
+
Set the scale of the y-axis of the plot widget.
|
2028
|
+
|
2029
|
+
Args:
|
2030
|
+
y_scale(Literal["linear", "log"]): Scale of the y-axis.
|
2031
|
+
"""
|
2032
|
+
|
2033
|
+
@rpc_call
|
2034
|
+
def set_x_lim(self, x_lim: "tuple"):
|
2035
|
+
"""
|
2036
|
+
Set the limits of the x-axis of the plot widget.
|
2037
|
+
|
2038
|
+
Args:
|
2039
|
+
x_lim(tuple): Limits of the x-axis.
|
2040
|
+
"""
|
2041
|
+
|
2042
|
+
@rpc_call
|
2043
|
+
def set_y_lim(self, y_lim: "tuple"):
|
2044
|
+
"""
|
2045
|
+
Set the limits of the y-axis of the plot widget.
|
2046
|
+
|
2047
|
+
Args:
|
2048
|
+
y_lim(tuple): Limits of the y-axis.
|
2049
|
+
"""
|
2050
|
+
|
2051
|
+
@rpc_call
|
2052
|
+
def set_legend_label_size(self, legend_label_size: "int"):
|
2053
|
+
"""
|
2054
|
+
Set the size of the legend labels of the plot widget.
|
2055
|
+
|
2056
|
+
Args:
|
2057
|
+
legend_label_size(int): Size of the legend labels.
|
2058
|
+
"""
|
2059
|
+
|
2060
|
+
@rpc_call
|
2061
|
+
def set_grid(self, x_grid: "bool", y_grid: "bool"):
|
2062
|
+
"""
|
2063
|
+
Set the grid visibility of the plot widget.
|
2064
|
+
|
2065
|
+
Args:
|
2066
|
+
x_grid(bool): Visibility of the x-axis grid.
|
2067
|
+
y_grid(bool): Visibility of the y-axis grid.
|
2068
|
+
"""
|
2069
|
+
|
2070
|
+
@rpc_call
|
2071
|
+
def lock_aspect_ratio(self, lock: "bool"):
|
2072
|
+
"""
|
2073
|
+
Lock the aspect ratio of the plot widget.
|
2074
|
+
|
2075
|
+
Args:
|
2076
|
+
lock(bool): Lock the aspect ratio.
|
2077
|
+
"""
|
2078
|
+
|
2079
|
+
@rpc_call
|
2080
|
+
def export(self):
|
2081
|
+
"""
|
2082
|
+
Show the export dialog for the plot widget.
|
2083
|
+
"""
|
2084
|
+
|
2085
|
+
@rpc_call
|
2086
|
+
def export_to_matplotlib(self):
|
2087
|
+
"""
|
2088
|
+
Export the plot widget to Matplotlib.
|
2089
|
+
"""
|
2090
|
+
|
2091
|
+
|
1790
2092
|
class DeviceBox(RPCBase):
|
1791
2093
|
@property
|
1792
2094
|
@rpc_call
|
bec_widgets/cli/server.py
CHANGED
@@ -202,7 +202,8 @@ def main():
|
|
202
202
|
module_path = os.path.dirname(bec_widgets.__file__)
|
203
203
|
icon = QIcon()
|
204
204
|
icon.addFile(
|
205
|
-
os.path.join(module_path, "assets", "bec_widgets_icon.png"),
|
205
|
+
os.path.join(module_path, "assets", "app_icons", "bec_widgets_icon.png"),
|
206
|
+
size=QSize(48, 48),
|
206
207
|
)
|
207
208
|
app.setWindowIcon(icon)
|
208
209
|
|
@@ -49,8 +49,9 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
49
49
|
"d0": self.d0,
|
50
50
|
"d1": self.d1,
|
51
51
|
"d2": self.d2,
|
52
|
-
"
|
52
|
+
"wave": self.wave,
|
53
53
|
"bar": self.bar,
|
54
|
+
"cm": self.colormap,
|
54
55
|
}
|
55
56
|
)
|
56
57
|
|
@@ -165,22 +166,25 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
165
166
|
self.fig1.plot(x_name="samx", y_name="bpm3a")
|
166
167
|
|
167
168
|
self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
|
168
|
-
self.
|
169
|
-
|
170
|
-
self.
|
169
|
+
self.wave = self.d2.add_widget("BECWaveformWidget", row=0, col=0)
|
170
|
+
# self.wave.plot(x_name="samx", y_name="bpm3a")
|
171
|
+
# self.wave.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
|
171
172
|
self.bar = self.d2.add_widget("RingProgressBar", row=0, col=1)
|
172
173
|
self.bar.set_diameter(200)
|
173
174
|
|
175
|
+
self.d3 = self.dock.add_dock(name="dock_3", position="bottom")
|
176
|
+
self.colormap = pg.GradientWidget()
|
177
|
+
self.d3.add_widget(self.colormap, row=0, col=0)
|
178
|
+
|
174
179
|
self.dock.save_state()
|
175
180
|
|
176
181
|
def closeEvent(self, event):
|
177
182
|
"""Override to handle things when main window is closed."""
|
178
|
-
self.dock.clear_all()
|
179
183
|
self.dock.cleanup()
|
180
184
|
self.dock.close()
|
181
|
-
self.figure.clear_all()
|
182
185
|
self.figure.cleanup()
|
183
186
|
self.figure.close()
|
187
|
+
self.console.close()
|
184
188
|
|
185
189
|
super().closeEvent(event)
|
186
190
|
|
@@ -197,7 +201,9 @@ if __name__ == "__main__": # pragma: no cover
|
|
197
201
|
app.setApplicationDisplayName("Jupyter Console")
|
198
202
|
apply_theme("dark")
|
199
203
|
icon = QIcon()
|
200
|
-
icon.addFile(
|
204
|
+
icon.addFile(
|
205
|
+
os.path.join(module_path, "assets", "app_icons", "terminal_icon.png"), size=QSize(48, 48)
|
206
|
+
)
|
201
207
|
app.setWindowIcon(icon)
|
202
208
|
|
203
209
|
bec_dispatcher = BECDispatcher()
|
@@ -11,10 +11,10 @@ from bec_lib.utils.import_utils import lazy_import_from
|
|
11
11
|
from pydantic import BaseModel, Field, field_validator
|
12
12
|
from qtpy.QtCore import QObject, QRunnable, QThreadPool, Signal
|
13
13
|
from qtpy.QtCore import Slot as pyqtSlot
|
14
|
+
from qtpy.QtWidgets import QApplication
|
14
15
|
|
15
16
|
from bec_widgets.cli.rpc_register import RPCRegister
|
16
17
|
from bec_widgets.qt_utils.error_popups import ErrorPopupUtility
|
17
|
-
from bec_widgets.utils.bec_widget import BECWidget
|
18
18
|
from bec_widgets.utils.yaml_dialog import load_yaml, load_yaml_gui, save_yaml, save_yaml_gui
|
19
19
|
|
20
20
|
BECDispatcher = lazy_import_from("bec_widgets.utils.bec_dispatcher", ("BECDispatcher",))
|
@@ -65,16 +65,30 @@ class Worker(QRunnable):
|
|
65
65
|
self.signals.completed.emit()
|
66
66
|
|
67
67
|
|
68
|
-
class BECConnector
|
69
|
-
"""Connection mixin class
|
68
|
+
class BECConnector:
|
69
|
+
"""Connection mixin class to handle BEC client and device manager"""
|
70
70
|
|
71
71
|
USER_ACCESS = ["_config_dict", "_get_all_rpc"]
|
72
|
+
EXIT_HANDLERS = {}
|
72
73
|
|
73
74
|
def __init__(self, client=None, config: ConnectionConfig = None, gui_id: str = None):
|
74
75
|
# BEC related connections
|
75
76
|
self.bec_dispatcher = BECDispatcher(client=client)
|
76
77
|
self.client = self.bec_dispatcher.client if client is None else client
|
77
78
|
|
79
|
+
if not self.client in BECConnector.EXIT_HANDLERS:
|
80
|
+
# register function to clean connections at exit;
|
81
|
+
# the function depends on BECClient, and BECDispatcher
|
82
|
+
@pyqtSlot()
|
83
|
+
def terminate(client=self.client, dispatcher=self.bec_dispatcher):
|
84
|
+
print("Disconnecting", repr(dispatcher))
|
85
|
+
dispatcher.disconnect_all()
|
86
|
+
print("Shutting down BEC Client", repr(client))
|
87
|
+
client.shutdown()
|
88
|
+
|
89
|
+
BECConnector.EXIT_HANDLERS[self.client] = terminate
|
90
|
+
QApplication.instance().aboutToQuit.connect(terminate)
|
91
|
+
|
78
92
|
if config:
|
79
93
|
self.config = config
|
80
94
|
self.config.widget_class = self.__class__.__name__
|
@@ -92,6 +106,8 @@ class BECConnector(BECWidget):
|
|
92
106
|
self.gui_id = self.config.gui_id
|
93
107
|
|
94
108
|
# register widget to rpc register
|
109
|
+
# be careful: when registering, and the object is not a BECWidget,
|
110
|
+
# cleanup has to called manually since there is no 'closeEvent'
|
95
111
|
self.rpc_register = RPCRegister()
|
96
112
|
self.rpc_register.add_rpc(self)
|
97
113
|
|
@@ -284,18 +300,3 @@ class BECConnector(BECWidget):
|
|
284
300
|
return self.config.model_dump()
|
285
301
|
else:
|
286
302
|
return self.config
|
287
|
-
|
288
|
-
def cleanup(self):
|
289
|
-
"""Cleanup the widget."""
|
290
|
-
self.rpc_register.remove_rpc(self)
|
291
|
-
all_connections = self.rpc_register.list_all_connections()
|
292
|
-
if len(all_connections) == 0:
|
293
|
-
print("No more connections. Shutting down GUI BEC client.")
|
294
|
-
self.bec_dispatcher.disconnect_all()
|
295
|
-
self.client.shutdown()
|
296
|
-
if hasattr(super(), "cleanup"):
|
297
|
-
super().cleanup()
|
298
|
-
|
299
|
-
# def closeEvent(self, event):
|
300
|
-
# self.cleanup()
|
301
|
-
# super().closeEvent(event)
|
bec_widgets/utils/bec_widget.py
CHANGED
@@ -1,8 +1,23 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
from qtpy.QtWidgets import QWidget
|
2
|
+
|
3
|
+
from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
|
4
|
+
|
5
|
+
|
6
|
+
class BECWidget(BECConnector):
|
7
|
+
"""Mixin class for all BEC widgets, to handle cleanup"""
|
8
|
+
|
9
|
+
def __init__(self, client=None, config: ConnectionConfig = None, gui_id: str = None):
|
10
|
+
if not isinstance(self, QWidget):
|
11
|
+
raise RuntimeError(f"{repr(self)} is not a subclass of QWidget")
|
12
|
+
super().__init__(client, config, gui_id)
|
13
|
+
|
14
|
+
def cleanup(self):
|
15
|
+
"""Cleanup the widget."""
|
16
|
+
pass
|
3
17
|
|
4
18
|
def closeEvent(self, event):
|
5
|
-
|
19
|
+
self.rpc_register.remove_rpc(self)
|
20
|
+
try:
|
6
21
|
self.cleanup()
|
7
|
-
|
22
|
+
finally:
|
8
23
|
super().closeEvent(event)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from bec_widgets.utils import
|
3
|
+
from bec_widgets.utils import ConnectionConfig
|
4
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
4
5
|
|
5
6
|
|
6
7
|
class DeviceInputConfig(ConnectionConfig):
|
@@ -9,7 +10,7 @@ class DeviceInputConfig(ConnectionConfig):
|
|
9
10
|
arg_name: str | None = None
|
10
11
|
|
11
12
|
|
12
|
-
class DeviceInputBase(
|
13
|
+
class DeviceInputBase(BECWidget):
|
13
14
|
"""
|
14
15
|
Mixin class for device input widgets. This class provides methods to get the device list and device object based
|
15
16
|
on the current text of the widget.
|
@@ -120,6 +121,3 @@ class DeviceInputBase(BECConnector):
|
|
120
121
|
"""
|
121
122
|
if device not in self.get_device_list(self.config.device_filter):
|
122
123
|
raise ValueError(f"Device {device} is not valid.")
|
123
|
-
|
124
|
-
def cleanup(self):
|
125
|
-
super().cleanup()
|
@@ -2,10 +2,11 @@ from bec_lib.endpoints import MessageEndpoints
|
|
2
2
|
from qtpy.QtCore import Qt, Slot
|
3
3
|
from qtpy.QtWidgets import QHeaderView, QTableWidget, QTableWidgetItem, QWidget
|
4
4
|
|
5
|
-
from bec_widgets.utils.bec_connector import
|
5
|
+
from bec_widgets.utils.bec_connector import ConnectionConfig
|
6
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
6
7
|
|
7
8
|
|
8
|
-
class BECQueue(
|
9
|
+
class BECQueue(BECWidget, QTableWidget):
|
9
10
|
"""
|
10
11
|
Widget to display the BEC queue.
|
11
12
|
"""
|
@@ -13,7 +13,7 @@ from bec_lib.utils.import_utils import lazy_import_from
|
|
13
13
|
from qtpy.QtCore import QObject, QTimer, Signal, Slot
|
14
14
|
from qtpy.QtWidgets import QHBoxLayout, QTreeWidget, QTreeWidgetItem, QWidget
|
15
15
|
|
16
|
-
from bec_widgets.utils.
|
16
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
17
17
|
from bec_widgets.utils.colors import apply_theme
|
18
18
|
from bec_widgets.widgets.bec_status_box.status_item import StatusItem
|
19
19
|
|
@@ -57,7 +57,7 @@ class BECServiceStatusMixin(QObject):
|
|
57
57
|
self.services_update.emit(self.client._services_info, self.client._services_metric)
|
58
58
|
|
59
59
|
|
60
|
-
class BECStatusBox(
|
60
|
+
class BECStatusBox(BECWidget, QWidget):
|
61
61
|
"""An autonomous widget to display the status of BEC services.
|
62
62
|
|
63
63
|
Args:
|
@@ -290,15 +290,6 @@ class BECStatusBox(BECConnector, QWidget):
|
|
290
290
|
if objects["item"] == item:
|
291
291
|
objects["widget"].show_popup()
|
292
292
|
|
293
|
-
def closeEvent(self, event):
|
294
|
-
"""Upon closing the widget, clean up the BECStatusBox and the QWidget.
|
295
|
-
|
296
|
-
Args:
|
297
|
-
event: The close event.
|
298
|
-
"""
|
299
|
-
super().cleanup()
|
300
|
-
super().closeEvent(event)
|
301
|
-
|
302
293
|
|
303
294
|
def main():
|
304
295
|
"""Main method to run the BECStatusBox widget."""
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import pyqtgraph as pg
|
2
4
|
from qtpy.QtCore import Property, Signal, Slot
|
3
5
|
from qtpy.QtGui import QColor, QFontMetrics, QImage
|
@@ -46,7 +48,7 @@ class ColormapSelector(QWidget):
|
|
46
48
|
colormap_changed_signal = Signal(str)
|
47
49
|
|
48
50
|
def __init__(self, parent=None, default_colormaps=None):
|
49
|
-
super().__init__(parent)
|
51
|
+
super().__init__(parent=parent)
|
50
52
|
self._colormaps = []
|
51
53
|
self.initUI(default_colormaps)
|
52
54
|
|
@@ -0,0 +1 @@
|
|
1
|
+
{'files': ['colormap_selector.py']}
|