mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
feat(waveform_widget): BECWaveformWidget added with toolbar
This commit is contained in:
@ -27,6 +27,7 @@ class Widgets(str, enum.Enum):
|
|||||||
StopButton = "StopButton"
|
StopButton = "StopButton"
|
||||||
TextBox = "TextBox"
|
TextBox = "TextBox"
|
||||||
VSCodeEditor = "VSCodeEditor"
|
VSCodeEditor = "VSCodeEditor"
|
||||||
|
BECWaveformWidget = "BECWaveformWidget"
|
||||||
WebsiteWidget = "WebsiteWidget"
|
WebsiteWidget = "WebsiteWidget"
|
||||||
|
|
||||||
|
|
||||||
@ -468,9 +469,8 @@ class BECFigure(RPCBase):
|
|||||||
@rpc_call
|
@rpc_call
|
||||||
def plot(
|
def plot(
|
||||||
self,
|
self,
|
||||||
arg1: "list | np.ndarray | str | None" = None,
|
|
||||||
y: "list | np.ndarray | None" = None,
|
|
||||||
x: "list | np.ndarray | None" = None,
|
x: "list | np.ndarray | None" = None,
|
||||||
|
y: "list | np.ndarray | None" = None,
|
||||||
x_name: "str | None" = None,
|
x_name: "str | None" = None,
|
||||||
y_name: "str | None" = None,
|
y_name: "str | None" = None,
|
||||||
z_name: "str | None" = None,
|
z_name: "str | None" = None,
|
||||||
@ -492,9 +492,8 @@ class BECFigure(RPCBase):
|
|||||||
Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure.
|
Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
arg1(list | np.ndarray | str | None): First argument which can be x data, y data, or y_name.
|
|
||||||
y(list | np.ndarray): Custom y data to plot.
|
|
||||||
x(list | np.ndarray): Custom x data to plot.
|
x(list | np.ndarray): Custom x data to plot.
|
||||||
|
y(list | np.ndarray): Custom y data to plot.
|
||||||
x_name(str): The name of the device for the x-axis.
|
x_name(str): The name of the device for the x-axis.
|
||||||
y_name(str): The name of the device for the y-axis.
|
y_name(str): The name of the device for the y-axis.
|
||||||
z_name(str): The name of the device for the z-axis.
|
z_name(str): The name of the device for the z-axis.
|
||||||
@ -1499,9 +1498,8 @@ class BECWaveform(RPCBase):
|
|||||||
@rpc_call
|
@rpc_call
|
||||||
def plot(
|
def plot(
|
||||||
self,
|
self,
|
||||||
arg1: "list | np.ndarray | str | None" = None,
|
|
||||||
y: "list | np.ndarray | None" = None,
|
|
||||||
x: "list | np.ndarray | None" = None,
|
x: "list | np.ndarray | None" = None,
|
||||||
|
y: "list | np.ndarray | None" = None,
|
||||||
x_name: "str | None" = None,
|
x_name: "str | None" = None,
|
||||||
y_name: "str | None" = None,
|
y_name: "str | None" = None,
|
||||||
z_name: "str | None" = None,
|
z_name: "str | None" = None,
|
||||||
@ -1513,20 +1511,13 @@ class BECWaveform(RPCBase):
|
|||||||
label: "str | None" = None,
|
label: "str | None" = None,
|
||||||
validate: "bool" = True,
|
validate: "bool" = True,
|
||||||
dap: "str | None" = None,
|
dap: "str | None" = None,
|
||||||
**kwargs,
|
|
||||||
) -> "BECCurve":
|
) -> "BECCurve":
|
||||||
"""
|
"""
|
||||||
Plot a curve to the plot widget.
|
Plot a curve to the plot widget.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
arg1(list | np.ndarray | str | None): First argument which can be x data, y data, or y_name.
|
x(list | np.ndarray): Custom x data to plot.
|
||||||
y(list | np.ndarray): Custom y data to plot.
|
y(list | np.ndarray): Custom y data to plot.
|
||||||
x(list | np.ndarray): Custom y data to plot.
|
x_name(str): The name of the device for the x-axis.
|
||||||
x_name(str): Name of the x signal.
|
|
||||||
- "best_effort": Use the best effort signal.
|
|
||||||
- "timestamp": Use the timestamp signal.
|
|
||||||
- "index": Use the index signal.
|
|
||||||
- Custom signal name of device from BEC.
|
|
||||||
y_name(str): The name of the device for the y-axis.
|
y_name(str): The name of the device for the y-axis.
|
||||||
z_name(str): The name of the device for the z-axis.
|
z_name(str): The name of the device for the z-axis.
|
||||||
x_entry(str): The name of the entry for the x-axis.
|
x_entry(str): The name of the entry for the x-axis.
|
||||||
@ -1536,7 +1527,7 @@ class BECWaveform(RPCBase):
|
|||||||
color_map_z(str): The color map to use for the z-axis.
|
color_map_z(str): The color map to use for the z-axis.
|
||||||
label(str): The label of the curve.
|
label(str): The label of the curve.
|
||||||
validate(bool): If True, validate the device names and entries.
|
validate(bool): If True, validate the device names and entries.
|
||||||
dap(str): The dap model to use for the curve, only available for sync devices. If not specified, none will be added.
|
dap(str): The dap model to use for the curve. If not specified, none will be added.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BECCurve: The curve object.
|
BECCurve: The curve object.
|
||||||
@ -1545,13 +1536,12 @@ class BECWaveform(RPCBase):
|
|||||||
@rpc_call
|
@rpc_call
|
||||||
def add_dap(
|
def add_dap(
|
||||||
self,
|
self,
|
||||||
x_name: "str | None" = None,
|
x_name: "str",
|
||||||
y_name: "str | None" = None,
|
y_name: "str",
|
||||||
x_entry: "Optional[str]" = None,
|
x_entry: "Optional[str]" = None,
|
||||||
y_entry: "Optional[str]" = None,
|
y_entry: "Optional[str]" = None,
|
||||||
color: "Optional[str]" = None,
|
color: "Optional[str]" = None,
|
||||||
dap: "str" = "GaussianModel",
|
dap: "str" = "GaussianModel",
|
||||||
validate_bec: "bool" = True,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> "BECCurve":
|
) -> "BECCurve":
|
||||||
"""
|
"""
|
||||||
@ -1566,27 +1556,12 @@ class BECWaveform(RPCBase):
|
|||||||
color_map_z(str): The color map to use for the z-axis.
|
color_map_z(str): The color map to use for the z-axis.
|
||||||
label(str, optional): Label of the curve. Defaults to None.
|
label(str, optional): Label of the curve. Defaults to None.
|
||||||
dap(str): The dap model to use for the curve.
|
dap(str): The dap model to use for the curve.
|
||||||
validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
|
|
||||||
**kwargs: Additional keyword arguments for the curve configuration.
|
**kwargs: Additional keyword arguments for the curve configuration.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BECCurve: The curve object.
|
BECCurve: The curve object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def set_x(self, x_name: "str", x_entry: "str | None" = None):
|
|
||||||
"""
|
|
||||||
Change the x axis of the plot widget.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
x_name(str): Name of the x signal.
|
|
||||||
- "best_effort": Use the best effort signal.
|
|
||||||
- "timestamp": Use the timestamp signal.
|
|
||||||
- "index": Use the index signal.
|
|
||||||
- Custom signal name of device from BEC.
|
|
||||||
x_entry(str): Entry of the x signal.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
@rpc_call
|
||||||
def get_dap_params(self) -> "dict":
|
def get_dap_params(self) -> "dict":
|
||||||
"""
|
"""
|
||||||
@ -1771,12 +1746,6 @@ class BECWaveform(RPCBase):
|
|||||||
Remove the plot widget from the figure.
|
Remove the plot widget from the figure.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def clear_all(self):
|
|
||||||
"""
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
@rpc_call
|
||||||
def set_legend_label_size(self, size: "int" = None):
|
def set_legend_label_size(self, size: "int" = None):
|
||||||
"""
|
"""
|
||||||
@ -1805,6 +1774,235 @@ class DeviceBox(RPCBase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class BECWaveformWidget(RPCBase):
|
||||||
|
@property
|
||||||
|
@rpc_call
|
||||||
|
def curves(self) -> "list[BECCurve]":
|
||||||
|
"""
|
||||||
|
Get the curves of the plot widget as a list
|
||||||
|
Returns:
|
||||||
|
list: List of curves.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def plot(
|
||||||
|
self,
|
||||||
|
x: "list | np.ndarray | None" = None,
|
||||||
|
y: "list | np.ndarray | None" = None,
|
||||||
|
x_name: "str | None" = None,
|
||||||
|
y_name: "str | None" = None,
|
||||||
|
z_name: "str | None" = None,
|
||||||
|
x_entry: "str | None" = None,
|
||||||
|
y_entry: "str | None" = None,
|
||||||
|
z_entry: "str | None" = None,
|
||||||
|
color: "str | None" = None,
|
||||||
|
color_map_z: "str | None" = "plasma",
|
||||||
|
label: "str | None" = None,
|
||||||
|
validate: "bool" = True,
|
||||||
|
dap: "str | None" = None,
|
||||||
|
) -> "BECCurve":
|
||||||
|
"""
|
||||||
|
Plot a curve to the plot widget.
|
||||||
|
Args:
|
||||||
|
x(list | np.ndarray): Custom x data to plot.
|
||||||
|
y(list | np.ndarray): Custom y data to plot.
|
||||||
|
x_name(str): The name of the device for the x-axis.
|
||||||
|
y_name(str): The name of the device for the y-axis.
|
||||||
|
z_name(str): The name of the device for the z-axis.
|
||||||
|
x_entry(str): The name of the entry for the x-axis.
|
||||||
|
y_entry(str): The name of the entry for the y-axis.
|
||||||
|
z_entry(str): The name of the entry for the z-axis.
|
||||||
|
color(str): The color of the curve.
|
||||||
|
color_map_z(str): The color map to use for the z-axis.
|
||||||
|
label(str): The label of the curve.
|
||||||
|
validate(bool): If True, validate the device names and entries.
|
||||||
|
dap(str): The dap model to use for the curve. If not specified, none will be added.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BECCurve: The curve object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def add_dap(
|
||||||
|
self,
|
||||||
|
x_name: "str",
|
||||||
|
y_name: "str",
|
||||||
|
x_entry: "str | None" = None,
|
||||||
|
y_entry: "str | None" = None,
|
||||||
|
color: "str | None" = None,
|
||||||
|
dap: "str" = "GaussianModel",
|
||||||
|
**kwargs,
|
||||||
|
) -> "BECCurve":
|
||||||
|
"""
|
||||||
|
Add LMFIT dap model curve to the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_name(str): Name of the x signal.
|
||||||
|
x_entry(str): Entry of the x signal.
|
||||||
|
y_name(str): Name of the y signal.
|
||||||
|
y_entry(str): Entry of the y signal.
|
||||||
|
color(str, optional): Color of the curve. Defaults to None.
|
||||||
|
color_map_z(str): The color map to use for the z-axis.
|
||||||
|
label(str, optional): Label of the curve. Defaults to None.
|
||||||
|
dap(str): The dap model to use for the curve.
|
||||||
|
**kwargs: Additional keyword arguments for the curve configuration.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BECCurve: The curve object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def get_dap_params(self) -> "dict":
|
||||||
|
"""
|
||||||
|
Get the DAP parameters of all DAP curves.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: DAP parameters of all DAP curves.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def remove_curve(self, *identifiers):
|
||||||
|
"""
|
||||||
|
Remove a curve from the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*identifiers: Identifier of the curve to be removed. Can be either an integer (index) or a string (curve_id).
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def scan_history(self, scan_index: "int" = None, scan_id: "str" = None):
|
||||||
|
"""
|
||||||
|
Update the scan curves with the data from the scan storage.
|
||||||
|
Provide only one of scan_id or scan_index.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
scan_id(str, optional): ScanID of the scan to be updated. Defaults to None.
|
||||||
|
scan_index(int, optional): Index of the scan to be updated. Defaults to None.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def get_all_data(self, output: "Literal['dict', 'pandas']" = "dict") -> "dict | pd.DataFrame":
|
||||||
|
"""
|
||||||
|
Extract all curve data into a dictionary or a pandas DataFrame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
output (Literal["dict", "pandas"]): Format of the output data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict | pd.DataFrame: Data of all curves in the specified format.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Set the properties of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs: Keyword arguments for the properties to be set.
|
||||||
|
|
||||||
|
Possible properties:
|
||||||
|
- title: str
|
||||||
|
- x_label: str
|
||||||
|
- y_label: str
|
||||||
|
- x_scale: Literal["linear", "log"]
|
||||||
|
- y_scale: Literal["linear", "log"]
|
||||||
|
- x_lim: tuple
|
||||||
|
- y_lim: tuple
|
||||||
|
- legend_label_size: int
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_title(self, title: "str"):
|
||||||
|
"""
|
||||||
|
Set the title of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
title(str): Title of the plot.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_x_label(self, x_label: "str"):
|
||||||
|
"""
|
||||||
|
Set the x-axis label of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_label(str): Label of the x-axis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_y_label(self, y_label: "str"):
|
||||||
|
"""
|
||||||
|
Set the y-axis label of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y_label(str): Label of the y-axis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_x_scale(self, x_scale: "Literal['linear', 'log']"):
|
||||||
|
"""
|
||||||
|
Set the scale of the x-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_scale(Literal["linear", "log"]): Scale of the x-axis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_y_scale(self, y_scale: "Literal['linear', 'log']"):
|
||||||
|
"""
|
||||||
|
Set the scale of the y-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y_scale(Literal["linear", "log"]): Scale of the y-axis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_x_lim(self, x_lim: "tuple"):
|
||||||
|
"""
|
||||||
|
Set the limits of the x-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_lim(tuple): Limits of the x-axis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_y_lim(self, y_lim: "tuple"):
|
||||||
|
"""
|
||||||
|
Set the limits of the y-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y_lim(tuple): Limits of the y-axis.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_legend_label_size(self, legend_label_size: "int"):
|
||||||
|
"""
|
||||||
|
Set the size of the legend labels of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
legend_label_size(int): Size of the legend labels.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_grid(self, x_grid: "bool", y_grid: "bool"):
|
||||||
|
"""
|
||||||
|
Set the grid visibility of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_grid(bool): Visibility of the x-axis grid.
|
||||||
|
y_grid(bool): Visibility of the y-axis grid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def lock_aspect_ratio(self, lock: "bool"):
|
||||||
|
"""
|
||||||
|
Lock the aspect ratio of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lock(bool): Lock the aspect ratio.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class DeviceComboBox(RPCBase):
|
class DeviceComboBox(RPCBase):
|
||||||
@property
|
@property
|
||||||
@rpc_call
|
@rpc_call
|
||||||
|
@ -16,6 +16,7 @@ class TicTacToe(QWidget): # pragma: no cover
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._state = DEFAULT_STATE
|
self._state = DEFAULT_STATE
|
||||||
self._turn_number = 0
|
self._turn_number = 0
|
||||||
|
print("TicTac HERE !!!!!!")
|
||||||
|
|
||||||
def minimumSizeHint(self):
|
def minimumSizeHint(self):
|
||||||
return QSize(200, 200)
|
return QSize(200, 200)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
from PySide6.QtWidgets import QDialog, QDialogButtonBox
|
||||||
from qtpy.QtCore import Slot
|
from qtpy.QtCore import Slot
|
||||||
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
||||||
|
|
||||||
@ -9,11 +10,12 @@ from bec_widgets.utils.widget_io import WidgetIO
|
|||||||
|
|
||||||
|
|
||||||
class AxisSettings(QWidget):
|
class AxisSettings(QWidget):
|
||||||
def __init__(self, parent=None, *args, **kwargs):
|
def __init__(self, parent=None, target_widget: QWidget = None, *args, **kwargs):
|
||||||
super().__init__(parent=parent, *args, **kwargs)
|
super().__init__(parent=parent, *args, **kwargs)
|
||||||
|
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
self.ui = UILoader().load_ui(os.path.join(current_path, "axis_settings.ui"), self)
|
self.ui = UILoader().load_ui(os.path.join(current_path, "axis_settings.ui"), self)
|
||||||
|
self.target_widget = target_widget
|
||||||
|
|
||||||
self.layout = QVBoxLayout(self)
|
self.layout = QVBoxLayout(self)
|
||||||
self.layout.addWidget(self.ui)
|
self.layout.addWidget(self.ui)
|
||||||
@ -23,8 +25,14 @@ class AxisSettings(QWidget):
|
|||||||
self.setMaximumHeight(280)
|
self.setMaximumHeight(280)
|
||||||
self.resize(380, 280)
|
self.resize(380, 280)
|
||||||
|
|
||||||
|
self.display_current_settings(self.target_widget._config_dict.get("axis", {}))
|
||||||
|
|
||||||
@Slot(dict)
|
@Slot(dict)
|
||||||
def display_current_settings(self, axis_config: dict):
|
def display_current_settings(self, axis_config: dict):
|
||||||
|
|
||||||
|
if dict == {}:
|
||||||
|
return
|
||||||
|
|
||||||
# Top Box
|
# Top Box
|
||||||
WidgetIO.set_value(self.ui.plot_title, axis_config["title"])
|
WidgetIO.set_value(self.ui.plot_title, axis_config["title"])
|
||||||
|
|
||||||
@ -48,14 +56,54 @@ class AxisSettings(QWidget):
|
|||||||
WidgetIO.set_value(self.ui.y_min, axis_config["y_lim"][0])
|
WidgetIO.set_value(self.ui.y_min, axis_config["y_lim"][0])
|
||||||
WidgetIO.set_value(self.ui.y_max, axis_config["y_lim"][1])
|
WidgetIO.set_value(self.ui.y_max, axis_config["y_lim"][1])
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def accept_changes(self):
|
||||||
|
title = WidgetIO.get_value(self.ui.plot_title)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
# X Axis
|
||||||
import sys
|
x_label = WidgetIO.get_value(self.ui.x_label)
|
||||||
|
x_scale = self.ui.x_scale.currentText()
|
||||||
|
x_grid = WidgetIO.get_value(self.ui.x_grid)
|
||||||
|
x_lim = (WidgetIO.get_value(self.ui.x_min), WidgetIO.get_value(self.ui.x_max))
|
||||||
|
|
||||||
from qtpy.QtWidgets import QApplication
|
# Y Axis
|
||||||
|
y_label = WidgetIO.get_value(self.ui.y_label)
|
||||||
|
y_scale = self.ui.y_scale.currentText()
|
||||||
|
y_grid = WidgetIO.get_value(self.ui.y_grid)
|
||||||
|
y_lim = (WidgetIO.get_value(self.ui.y_min), WidgetIO.get_value(self.ui.y_max))
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
self.target_widget.set(
|
||||||
apply_theme("dark")
|
title=title,
|
||||||
window = AxisSettings()
|
x_label=x_label,
|
||||||
window.show()
|
x_scale=x_scale,
|
||||||
sys.exit(app.exec_())
|
x_lim=x_lim,
|
||||||
|
y_label=y_label,
|
||||||
|
y_scale=y_scale,
|
||||||
|
y_lim=y_lim,
|
||||||
|
)
|
||||||
|
self.target_widget.set_grid(x_grid, y_grid)
|
||||||
|
|
||||||
|
|
||||||
|
class AxisSettingsDialog(QDialog):
|
||||||
|
def __init__(self, parent=None, target_widget: QWidget = None, *args, **kwargs):
|
||||||
|
super().__init__(parent, *args, **kwargs)
|
||||||
|
|
||||||
|
self.setModal(False)
|
||||||
|
|
||||||
|
self.setWindowTitle("Axis Settings")
|
||||||
|
self.target_widget = target_widget
|
||||||
|
self.widget = AxisSettings(target_widget=self.target_widget)
|
||||||
|
# self.widget.display_current_settings(self.target_widget._config_dict)
|
||||||
|
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||||
|
|
||||||
|
self.button_box.accepted.connect(self.accept)
|
||||||
|
self.button_box.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.layout.addWidget(self.widget)
|
||||||
|
self.layout.addWidget(self.button_box)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def accept(self):
|
||||||
|
self.widget.accept_changes()
|
||||||
|
super().accept()
|
||||||
|
0
bec_widgets/widgets/waveform/__init__.py
Normal file
0
bec_widgets/widgets/waveform/__init__.py
Normal file
4
bec_widgets/widgets/waveform/assets/settings.svg
Normal file
4
bec_widgets/widgets/waveform/assets/settings.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#FFFFFF">
|
||||||
|
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||||
|
<path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,16 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from qtpy.QtCore import QSize
|
||||||
|
from qtpy.QtGui import QIcon, QAction
|
||||||
|
|
||||||
|
from bec_widgets.widgets.toolbar.toolbar import ToolBarAction
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsAction(ToolBarAction):
|
||||||
|
def add_to_toolbar(self, toolbar, target):
|
||||||
|
current_path = os.path.dirname(__file__)
|
||||||
|
parent_path = os.path.dirname(current_path)
|
||||||
|
icon = QIcon()
|
||||||
|
icon.addFile(os.path.join(parent_path, "assets", "settings.svg"), size=QSize(20, 20))
|
||||||
|
self.action = QAction(icon, "Open Configuration Dialog", target)
|
||||||
|
toolbar.addAction(self.action)
|
406
bec_widgets/widgets/waveform/waveform_widget.py
Normal file
406
bec_widgets/widgets/waveform/waveform_widget.py
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from PySide6.QtWidgets import QWidget, QVBoxLayout
|
||||||
|
from qtpy import PYSIDE6
|
||||||
|
|
||||||
|
from bec_widgets.utils import BECConnector
|
||||||
|
from bec_widgets.widgets.figure import BECFigure
|
||||||
|
from bec_widgets.widgets.figure.plots.axis_settings import AxisSettingsDialog
|
||||||
|
from bec_widgets.widgets.figure.plots.waveform.waveform import Waveform1DConfig
|
||||||
|
from bec_widgets.widgets.figure.plots.waveform.waveform_curve import BECCurve
|
||||||
|
from bec_widgets.widgets.toolbar import ModularToolBar
|
||||||
|
from bec_widgets.widgets.waveform.waveform_dialog.waveform_toolbar import SettingsAction
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pandas as pd
|
||||||
|
except ImportError:
|
||||||
|
pd = None
|
||||||
|
|
||||||
|
|
||||||
|
class BECWaveformWidget(BECConnector, QWidget):
|
||||||
|
USER_ACCESS = [
|
||||||
|
"curves",
|
||||||
|
"plot",
|
||||||
|
"add_dap",
|
||||||
|
"get_dap_params",
|
||||||
|
"remove_curve",
|
||||||
|
"scan_history",
|
||||||
|
"get_all_data",
|
||||||
|
"set",
|
||||||
|
"set_title",
|
||||||
|
"set_x_label",
|
||||||
|
"set_y_label",
|
||||||
|
"set_x_scale",
|
||||||
|
"set_y_scale",
|
||||||
|
"set_x_lim",
|
||||||
|
"set_y_lim",
|
||||||
|
"set_legend_label_size",
|
||||||
|
"set_grid",
|
||||||
|
"lock_aspect_ratio",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent: QWidget | None = None,
|
||||||
|
config: Waveform1DConfig | dict = None,
|
||||||
|
client=None,
|
||||||
|
gui_id: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
if not PYSIDE6:
|
||||||
|
raise RuntimeError(
|
||||||
|
"PYSIDE6 is not available in the environment. This widget is compatible only with PySide6."
|
||||||
|
)
|
||||||
|
if config is None:
|
||||||
|
config = Waveform1DConfig(widget_class=self.__class__.__name__)
|
||||||
|
else:
|
||||||
|
if isinstance(config, dict):
|
||||||
|
config = Waveform1DConfig(**config)
|
||||||
|
super().__init__(client=client, gui_id=gui_id)
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.layout.setSpacing(0)
|
||||||
|
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
self.fig = BECFigure()
|
||||||
|
self.toolbar = ModularToolBar(
|
||||||
|
actions={
|
||||||
|
# "connect": ConnectAction(),
|
||||||
|
# "history": ResetHistoryAction(),
|
||||||
|
"axis_settings": SettingsAction()
|
||||||
|
},
|
||||||
|
target_widget=self,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.layout.addWidget(self.toolbar)
|
||||||
|
self.layout.addWidget(self.fig)
|
||||||
|
|
||||||
|
self.waveform = self.fig.plot()
|
||||||
|
self.waveform.apply_config(config)
|
||||||
|
|
||||||
|
self.config = config # TODO not sure if this should be here
|
||||||
|
|
||||||
|
self._hook_actions()
|
||||||
|
|
||||||
|
def _hook_actions(self):
|
||||||
|
self.toolbar.widgets["axis_settings"].action.triggered.connect(self.show_axis_settings)
|
||||||
|
|
||||||
|
def show_axis_settings(self):
|
||||||
|
dialog = AxisSettingsDialog(self, target_widget=self)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# User Access Methods from Waveform
|
||||||
|
###################################
|
||||||
|
@property
|
||||||
|
def curves(self) -> list[BECCurve]:
|
||||||
|
"""
|
||||||
|
Get the curves of the plot widget as a list
|
||||||
|
Returns:
|
||||||
|
list: List of curves.
|
||||||
|
"""
|
||||||
|
return self.waveform._curves
|
||||||
|
|
||||||
|
@curves.setter
|
||||||
|
def curves(self, value: list[BECCurve]):
|
||||||
|
self.waveform._curves = value
|
||||||
|
|
||||||
|
def get_curve(self, identifier) -> BECCurve:
|
||||||
|
"""
|
||||||
|
Get the curve by its index or ID.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
identifier(int|str): Identifier of the curve. Can be either an integer (index) or a string (curve_id).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BECCurve: The curve object.
|
||||||
|
"""
|
||||||
|
return self.waveform.get_curve(identifier)
|
||||||
|
|
||||||
|
def plot(
|
||||||
|
self,
|
||||||
|
x: list | np.ndarray | None = None,
|
||||||
|
y: list | np.ndarray | None = None,
|
||||||
|
x_name: str | None = None,
|
||||||
|
y_name: str | None = None,
|
||||||
|
z_name: str | None = None,
|
||||||
|
x_entry: str | None = None,
|
||||||
|
y_entry: str | None = None,
|
||||||
|
z_entry: str | None = None,
|
||||||
|
color: str | None = None,
|
||||||
|
color_map_z: str | None = "plasma",
|
||||||
|
label: str | None = None,
|
||||||
|
validate: bool = True,
|
||||||
|
dap: str | None = None, # TODO add dap custom curve wrapper
|
||||||
|
) -> BECCurve:
|
||||||
|
"""
|
||||||
|
Plot a curve to the plot widget.
|
||||||
|
Args:
|
||||||
|
x(list | np.ndarray): Custom x data to plot.
|
||||||
|
y(list | np.ndarray): Custom y data to plot.
|
||||||
|
x_name(str): The name of the device for the x-axis.
|
||||||
|
y_name(str): The name of the device for the y-axis.
|
||||||
|
z_name(str): The name of the device for the z-axis.
|
||||||
|
x_entry(str): The name of the entry for the x-axis.
|
||||||
|
y_entry(str): The name of the entry for the y-axis.
|
||||||
|
z_entry(str): The name of the entry for the z-axis.
|
||||||
|
color(str): The color of the curve.
|
||||||
|
color_map_z(str): The color map to use for the z-axis.
|
||||||
|
label(str): The label of the curve.
|
||||||
|
validate(bool): If True, validate the device names and entries.
|
||||||
|
dap(str): The dap model to use for the curve. If not specified, none will be added.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BECCurve: The curve object.
|
||||||
|
"""
|
||||||
|
return self.waveform.plot(
|
||||||
|
x=x,
|
||||||
|
y=y,
|
||||||
|
x_name=x_name,
|
||||||
|
y_name=y_name,
|
||||||
|
z_name=z_name,
|
||||||
|
x_entry=x_entry,
|
||||||
|
y_entry=y_entry,
|
||||||
|
z_entry=z_entry,
|
||||||
|
color=color,
|
||||||
|
color_map_z=color_map_z,
|
||||||
|
label=label,
|
||||||
|
validate=validate,
|
||||||
|
dap=dap,
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_dap(
|
||||||
|
self,
|
||||||
|
x_name: str,
|
||||||
|
y_name: str,
|
||||||
|
x_entry: str | None = None,
|
||||||
|
y_entry: str | None = None,
|
||||||
|
color: str | None = None,
|
||||||
|
dap: str = "GaussianModel",
|
||||||
|
**kwargs,
|
||||||
|
) -> BECCurve:
|
||||||
|
"""
|
||||||
|
Add LMFIT dap model curve to the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_name(str): Name of the x signal.
|
||||||
|
x_entry(str): Entry of the x signal.
|
||||||
|
y_name(str): Name of the y signal.
|
||||||
|
y_entry(str): Entry of the y signal.
|
||||||
|
color(str, optional): Color of the curve. Defaults to None.
|
||||||
|
color_map_z(str): The color map to use for the z-axis.
|
||||||
|
label(str, optional): Label of the curve. Defaults to None.
|
||||||
|
dap(str): The dap model to use for the curve.
|
||||||
|
**kwargs: Additional keyword arguments for the curve configuration.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BECCurve: The curve object.
|
||||||
|
"""
|
||||||
|
return self.waveform.add_dap(
|
||||||
|
x_name=x_name,
|
||||||
|
y_name=y_name,
|
||||||
|
x_entry=x_entry,
|
||||||
|
y_entry=y_entry,
|
||||||
|
color=color,
|
||||||
|
dap=dap,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_dap_params(self) -> dict:
|
||||||
|
"""
|
||||||
|
Get the DAP parameters of all DAP curves.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: DAP parameters of all DAP curves.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.waveform.get_dap_params()
|
||||||
|
|
||||||
|
def remove_curve(self, *identifiers):
|
||||||
|
"""
|
||||||
|
Remove a curve from the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*identifiers: Identifier of the curve to be removed. Can be either an integer (index) or a string (curve_id).
|
||||||
|
"""
|
||||||
|
self.waveform.remove_curve(*identifiers)
|
||||||
|
|
||||||
|
def scan_history(self, scan_index: int = None, scan_id: str = None):
|
||||||
|
"""
|
||||||
|
Update the scan curves with the data from the scan storage.
|
||||||
|
Provide only one of scan_id or scan_index.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
scan_id(str, optional): ScanID of the scan to be updated. Defaults to None.
|
||||||
|
scan_index(int, optional): Index of the scan to be updated. Defaults to None.
|
||||||
|
"""
|
||||||
|
self.waveform.scan_history(scan_index, scan_id)
|
||||||
|
|
||||||
|
def get_all_data(self, output: Literal["dict", "pandas"] = "dict") -> dict | pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Extract all curve data into a dictionary or a pandas DataFrame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
output (Literal["dict", "pandas"]): Format of the output data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict | pd.DataFrame: Data of all curves in the specified format.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import pandas as pd
|
||||||
|
except ImportError:
|
||||||
|
pd = None
|
||||||
|
if output == "pandas":
|
||||||
|
print(
|
||||||
|
"Pandas is not installed. "
|
||||||
|
"Please install pandas using 'pip install pandas'."
|
||||||
|
"Output will be dictionary instead."
|
||||||
|
)
|
||||||
|
output = "dict"
|
||||||
|
return self.waveform.get_all_data(output)
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# User Access Methods from Plotbase
|
||||||
|
###################################
|
||||||
|
|
||||||
|
def set(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Set the properties of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs: Keyword arguments for the properties to be set.
|
||||||
|
|
||||||
|
Possible properties:
|
||||||
|
- title: str
|
||||||
|
- x_label: str
|
||||||
|
- y_label: str
|
||||||
|
- x_scale: Literal["linear", "log"]
|
||||||
|
- y_scale: Literal["linear", "log"]
|
||||||
|
- x_lim: tuple
|
||||||
|
- y_lim: tuple
|
||||||
|
- legend_label_size: int
|
||||||
|
"""
|
||||||
|
self.waveform.set(**kwargs)
|
||||||
|
|
||||||
|
def set_title(self, title: str):
|
||||||
|
"""
|
||||||
|
Set the title of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
title(str): Title of the plot.
|
||||||
|
"""
|
||||||
|
self.waveform.set_title(title)
|
||||||
|
|
||||||
|
def set_x_label(self, x_label: str):
|
||||||
|
"""
|
||||||
|
Set the x-axis label of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_label(str): Label of the x-axis.
|
||||||
|
"""
|
||||||
|
self.waveform.set_x_label(x_label)
|
||||||
|
|
||||||
|
def set_y_label(self, y_label: str):
|
||||||
|
"""
|
||||||
|
Set the y-axis label of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y_label(str): Label of the y-axis.
|
||||||
|
"""
|
||||||
|
self.waveform.set_y_label(y_label)
|
||||||
|
|
||||||
|
def set_x_scale(self, x_scale: Literal["linear", "log"]):
|
||||||
|
"""
|
||||||
|
Set the scale of the x-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_scale(Literal["linear", "log"]): Scale of the x-axis.
|
||||||
|
"""
|
||||||
|
self.waveform.set_x_scale(x_scale)
|
||||||
|
|
||||||
|
def set_y_scale(self, y_scale: Literal["linear", "log"]):
|
||||||
|
"""
|
||||||
|
Set the scale of the y-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y_scale(Literal["linear", "log"]): Scale of the y-axis.
|
||||||
|
"""
|
||||||
|
self.waveform.set_y_scale(y_scale)
|
||||||
|
|
||||||
|
def set_x_lim(self, x_lim: tuple):
|
||||||
|
"""
|
||||||
|
Set the limits of the x-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_lim(tuple): Limits of the x-axis.
|
||||||
|
"""
|
||||||
|
self.waveform.set_x_lim(x_lim)
|
||||||
|
|
||||||
|
def set_y_lim(self, y_lim: tuple):
|
||||||
|
"""
|
||||||
|
Set the limits of the y-axis of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
y_lim(tuple): Limits of the y-axis.
|
||||||
|
"""
|
||||||
|
self.waveform.set_y_lim(y_lim)
|
||||||
|
|
||||||
|
def set_legend_label_size(self, legend_label_size: int):
|
||||||
|
"""
|
||||||
|
Set the size of the legend labels of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
legend_label_size(int): Size of the legend labels.
|
||||||
|
"""
|
||||||
|
self.waveform.set_legend_label_size(legend_label_size)
|
||||||
|
|
||||||
|
def set_grid(self, x_grid: bool, y_grid: bool):
|
||||||
|
"""
|
||||||
|
Set the grid visibility of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x_grid(bool): Visibility of the x-axis grid.
|
||||||
|
y_grid(bool): Visibility of the y-axis grid.
|
||||||
|
"""
|
||||||
|
self.waveform.set_grid(x_grid, y_grid)
|
||||||
|
|
||||||
|
def lock_aspect_ratio(self, lock: bool):
|
||||||
|
"""
|
||||||
|
Lock the aspect ratio of the plot widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lock(bool): Lock the aspect ratio.
|
||||||
|
"""
|
||||||
|
self.waveform.lock_aspect_ratio(lock)
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
self.fig.cleanup()
|
||||||
|
return super().cleanup()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.cleanup()
|
||||||
|
QWidget().closeEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
def main(): # pragma: no cover
|
||||||
|
|
||||||
|
if not PYSIDE6:
|
||||||
|
print(
|
||||||
|
"PYSIDE6 is not available in the environment. UI files with BEC custom widgets are runnable only with PySide6."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
from qtpy.QtWidgets import QApplication
|
||||||
|
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
widget = BECWaveformWidget()
|
||||||
|
widget.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
main()
|
Reference in New Issue
Block a user