diff --git a/bec_widgets/applications/alignment/alignment_1d/alignment_1d.py b/bec_widgets/applications/alignment/alignment_1d/alignment_1d.py
index 6050a612..8152c380 100644
--- a/bec_widgets/applications/alignment/alignment_1d/alignment_1d.py
+++ b/bec_widgets/applications/alignment/alignment_1d/alignment_1d.py
@@ -29,6 +29,7 @@ MODULE_PATH = os.path.dirname(bec_widgets.__file__)
logger = bec_logger.logger
+# FIXME BECWaveFormWidget is gone, this app will not work until adapted to new Waveform
class Alignment1D:
"""Alignment GUI to perform 1D scans"""
diff --git a/bec_widgets/cli/client.py b/bec_widgets/cli/client.py
index 87233c2c..5d4c90b0 100644
--- a/bec_widgets/cli/client.py
+++ b/bec_widgets/cli/client.py
@@ -24,7 +24,6 @@ class Widgets(str, enum.Enum):
BECProgressBar = "BECProgressBar"
BECQueue = "BECQueue"
BECStatusBox = "BECStatusBox"
- BECWaveformWidget = "BECWaveformWidget"
DapComboBox = "DapComboBox"
DarkModeButton = "DarkModeButton"
DeviceBrowser = "DeviceBrowser"
@@ -2690,313 +2689,6 @@ class BECWaveform(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,
- arg1: "list | np.ndarray | str | None" = None,
- 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" = "magma",
- label: "str | None" = None,
- validate: "bool" = True,
- dap: "str | None" = None,
- **kwargs,
- ) -> "BECCurve":
- """
- Plot a curve to the plot widget.
- Args:
- 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).
- 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",
- dap: "str",
- x_entry: "str | None" = None,
- y_entry: "str | None" = None,
- color: "str | None" = None,
- validate_bec: "bool" = True,
- **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.
- 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.
-
- 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_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
- 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_auto_range(self, enabled: "bool", axis: "str" = "xy"):
- """
- Set the auto range of the plot widget.
-
- Args:
- enabled(bool): If True, enable the auto range.
- axis(str, optional): The axis to enable the auto range.
- - "xy": Enable auto range for both x and y axis.
- - "x": Enable auto range for x axis.
- - "y": Enable auto range for y axis.
- """
-
- @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 enable_fps_monitor(self, enabled: "bool"):
- """
- Enable the FPS monitor of the plot widget.
-
- Args:
- enabled(bool): If True, enable the FPS monitor.
- """
-
- @rpc_call
- def enable_scatter(self, enabled: "bool"):
- """
- Enable the scatter plot of the plot widget.
-
- Args:
- enabled(bool): If True, enable the scatter plot.
- """
-
- @rpc_call
- def lock_aspect_ratio(self, lock: "bool"):
- """
- Lock the aspect ratio of the plot widget.
-
- Args:
- lock(bool): Lock the aspect ratio.
- """
-
- @rpc_call
- def export(self):
- """
- Show the export dialog for the plot widget.
- """
-
- @rpc_call
- def export_to_matplotlib(self):
- """
- Export the plot widget to Matplotlib.
- """
-
- @rpc_call
- def toggle_roi(self, checked: "bool"):
- """
- Toggle the linear region selector.
-
- Args:
- checked(bool): If True, enable the linear region selector.
- """
-
- @rpc_call
- def select_roi(self, region: "tuple"):
- """
- Set the region of interest of the plot widget.
-
- Args:
- region(tuple): Region of interest.
- """
-
-
class Curve(RPCBase):
@rpc_call
def remove(self):
@@ -3833,6 +3525,31 @@ class ScanControl(RPCBase):
"""
+class ScanMetadata(RPCBase):
+ @property
+ @rpc_call
+ def _config_dict(self) -> "dict":
+ """
+ Get the configuration of the widget.
+
+ Returns:
+ dict: The configuration of the widget.
+ """
+
+ @rpc_call
+ def _get_all_rpc(self) -> "dict":
+ """
+ Get all registered RPC objects.
+ """
+
+ @property
+ @rpc_call
+ def _rpc_id(self) -> "str":
+ """
+ Get the RPC ID of the widget.
+ """
+
+
class SignalComboBox(RPCBase):
@property
@rpc_call
@@ -4309,7 +4026,7 @@ class Waveform(RPCBase):
Remove a curve from the plot widget.
Args:
- curve(int|str): The curve to remove. Can be the order of the curve or the name of the curve.
+ curve(int|str): The curve to remove. It Can be the order of the curve or the name of the curve.
"""
@rpc_call
diff --git a/bec_widgets/examples/jupyter_console/jupyter_console_window.py b/bec_widgets/examples/jupyter_console/jupyter_console_window.py
index 9d4421c5..f10f1d43 100644
--- a/bec_widgets/examples/jupyter_console/jupyter_console_window.py
+++ b/bec_widgets/examples/jupyter_console/jupyter_console_window.py
@@ -52,8 +52,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
"w10": self.w10,
"d0": self.d0,
"d1": self.d1,
- "d2": self.d2,
- "wave": self.wf,
"im": self.im,
"mm": self.mm,
"mw": self.mw,
@@ -66,7 +64,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
"btn6": self.btn6,
"pb": self.pb,
"pi": self.pi,
- "wfng": self.wfng,
+ "wf": self.wf,
}
)
@@ -121,8 +119,8 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
fifth_tab = QWidget()
fifth_tab_layout = QVBoxLayout(fifth_tab)
- self.wfng = Waveform()
- fifth_tab_layout.addWidget(self.wfng)
+ self.wf = Waveform()
+ fifth_tab_layout.addWidget(self.wf)
tab_widget.addTab(fifth_tab, "Waveform Next Gen")
tab_widget.setCurrentIndex(4)
# add stuff to the new Waveform widget
@@ -140,8 +138,8 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
# self.wfng._add_curve_custom(x=np.arange(10), y=np.random.rand(10), label="curve1")
# self.wfng._add_curve_custom(x=np.arange(10), y=np.random.rand(10), label="curve2")
# self.wfng._add_curve_custom(x=np.arange(10), y=np.random.rand(10), label="curve3")
- self.wfng.plot(y_name="bpm4i", y_entry="bpm4i", dap="GaussianModel")
- self.wfng.plot(y_name="bpm3a", y_entry="bpm3a", dap="GaussianModel")
+ self.wf.plot(y_name="bpm4i", y_entry="bpm4i", dap="GaussianModel")
+ self.wf.plot(y_name="bpm3a", y_entry="bpm3a", dap="GaussianModel")
def _init_figure(self):
self.w1 = self.figure.plot(x_name="samx", y_name="bpm4i", row=0, col=0)
@@ -208,11 +206,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
self.im = self.d1.add_widget("BECImageWidget")
self.im.image("waveform", "1d")
- self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
- self.wf = self.d2.add_widget("BECWaveformWidget", row=0, col=0)
- self.wf.plot("bpm4i")
- self.wf.plot("bpm3a")
-
self.mw = None # self.wf.multi_waveform(monitor="waveform") # , config=config)
self.dock.save_state()
diff --git a/bec_widgets/qt_utils/side_panel.py b/bec_widgets/qt_utils/side_panel.py
index 5f855569..fc07ea7d 100644
--- a/bec_widgets/qt_utils/side_panel.py
+++ b/bec_widgets/qt_utils/side_panel.py
@@ -317,9 +317,9 @@ class ExampleApp(QMainWindow): # pragma: no cover
self.side_panel = SidePanel(self, orientation="left", panel_max_width=250)
self.layout.addWidget(self.side_panel)
- from bec_widgets.widgets.plots.waveform.waveform_widget import BECWaveformWidget
+ from bec_widgets.widgets.plots_next_gen.waveform.waveform import Waveform
- self.plot = BECWaveformWidget()
+ self.plot = Waveform()
self.layout.addWidget(self.plot)
self.add_side_menus()
diff --git a/bec_widgets/widgets/plots/waveform/__init__.py b/bec_widgets/widgets/plots/waveform/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject b/bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject
deleted file mode 100644
index b03b94e2..00000000
--- a/bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject
+++ /dev/null
@@ -1 +0,0 @@
-{'files': ['waveform_widget.py']}
\ No newline at end of file
diff --git a/bec_widgets/widgets/plots/waveform/bec_waveform_widget_plugin.py b/bec_widgets/widgets/plots/waveform/bec_waveform_widget_plugin.py
deleted file mode 100644
index bd110b30..00000000
--- a/bec_widgets/widgets/plots/waveform/bec_waveform_widget_plugin.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import os
-
-from qtpy.QtDesigner import QDesignerCustomWidgetInterface
-
-import bec_widgets
-from bec_widgets.utils.bec_designer import designer_material_icon
-from bec_widgets.widgets.plots.waveform.waveform_widget import BECWaveformWidget
-
-DOM_XML = """
-
-
-
-
-"""
-
-MODULE_PATH = os.path.dirname(bec_widgets.__file__)
-
-
-class BECWaveformWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
- def __init__(self):
- super().__init__()
- self._form_editor = None
-
- def createWidget(self, parent):
- t = BECWaveformWidget(parent)
- return t
-
- def domXml(self):
- return DOM_XML
-
- def group(self):
- return "BEC Plots"
-
- def icon(self):
- return designer_material_icon(BECWaveformWidget.ICON_NAME)
-
- def includeFile(self):
- return "bec_waveform_widget"
-
- def initialize(self, form_editor):
- self._form_editor = form_editor
-
- def isContainer(self):
- return False
-
- def isInitialized(self):
- return self._form_editor is not None
-
- def name(self):
- return "BECWaveformWidget"
-
- def toolTip(self):
- return "BECWaveformWidget"
-
- def whatsThis(self):
- return self.toolTip()
diff --git a/bec_widgets/widgets/plots/waveform/register_bec_waveform_widget.py b/bec_widgets/widgets/plots/waveform/register_bec_waveform_widget.py
deleted file mode 100644
index 54b299b9..00000000
--- a/bec_widgets/widgets/plots/waveform/register_bec_waveform_widget.py
+++ /dev/null
@@ -1,17 +0,0 @@
-def main(): # pragma: no cover
- from qtpy import PYSIDE6
-
- if not PYSIDE6:
- print("PYSIDE6 is not available in the environment. Cannot patch designer.")
- return
- from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
-
- from bec_widgets.widgets.plots.waveform.bec_waveform_widget_plugin import (
- BECWaveformWidgetPlugin,
- )
-
- QPyDesignerCustomWidgetCollection.addCustomWidget(BECWaveformWidgetPlugin())
-
-
-if __name__ == "__main__": # pragma: no cover
- main()
diff --git a/bec_widgets/widgets/plots/waveform/waveform_popups/__init__.py b/bec_widgets/widgets/plots/waveform/waveform_popups/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/__init__.py b/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py b/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py
deleted file mode 100644
index bc880271..00000000
--- a/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py
+++ /dev/null
@@ -1,336 +0,0 @@
-from __future__ import annotations
-
-import os
-from typing import Literal
-
-from bec_qthemes import material_icon
-from pydantic import BaseModel
-from qtpy.QtCore import QObject, Slot
-from qtpy.QtWidgets import QComboBox, QLineEdit, QPushButton, QSpinBox, QTableWidget, QVBoxLayout
-
-import bec_widgets
-from bec_widgets.qt_utils.error_popups import WarningPopupUtility
-from bec_widgets.qt_utils.settings_dialog import SettingWidget
-from bec_widgets.utils import Colors, UILoader
-from bec_widgets.widgets.control.device_input.device_line_edit.device_line_edit import (
- DeviceLineEdit,
-)
-from bec_widgets.widgets.dap.dap_combo_box.dap_combo_box import DapComboBox
-from bec_widgets.widgets.utility.visual.color_button.color_button import ColorButton
-
-MODULE_PATH = os.path.dirname(bec_widgets.__file__)
-
-
-class CurveSettings(SettingWidget):
- def __init__(self, parent=None, *args, **kwargs):
- super().__init__(parent, *args, **kwargs)
- current_path = os.path.dirname(__file__)
-
- self.ui = UILoader(self).loader(os.path.join(current_path, "curve_dialog.ui"))
- self._setup_icons()
-
- self.warning_util = WarningPopupUtility(self)
-
- self.layout = QVBoxLayout(self)
- self.layout.addWidget(self.ui)
-
- self.ui.add_curve.clicked.connect(self.add_curve)
- self.ui.add_dap.clicked.connect(self.add_dap)
- self.ui.x_mode.currentIndexChanged.connect(self.set_x_mode)
- self.ui.normalize_colors_scan.clicked.connect(lambda: self.change_colormap("scan"))
- self.ui.normalize_colors_dap.clicked.connect(lambda: self.change_colormap("dap"))
-
- def _setup_icons(self):
- add_icon = material_icon(icon_name="add", size=(20, 20), convert_to_pixmap=False)
- self.ui.add_dap.setIcon(add_icon)
- self.ui.add_dap.setToolTip("Add DAP Curve")
- self.ui.add_curve.setIcon(add_icon)
- self.ui.add_curve.setToolTip("Add Scan Curve")
-
- @Slot(dict)
- def display_current_settings(self, config: dict | BaseModel):
-
- # What elements should be enabled
- x_name = self.target_widget.waveform._x_axis_mode["name"]
- x_entry = self.target_widget.waveform._x_axis_mode["entry"]
- self._enable_ui_elements(x_name, x_entry)
- cm = self.target_widget.config.color_palette
- self.ui.color_map_selector_scan.colormap = cm
-
- # Scan Curve Table
- for source in ["scan_segment", "async"]:
- for label, curve in config[source].items():
- row_count = self.ui.scan_table.rowCount()
- self.ui.scan_table.insertRow(row_count)
- DialogRow(
- parent=self,
- table_widget=self.ui.scan_table,
- client=self.target_widget.client,
- row=row_count,
- config=curve.config,
- ).add_scan_row()
-
- # Add DAP Curves
- for label, curve in config["DAP"].items():
- row_count = self.ui.dap_table.rowCount()
- self.ui.dap_table.insertRow(row_count)
- DialogRow(
- parent=self,
- table_widget=self.ui.dap_table,
- client=self.target_widget.client,
- row=row_count,
- config=curve.config,
- ).add_dap_row()
-
- def _enable_ui_elements(self, name, entry):
- if name is None:
- name = "best_effort"
- if name in ["index", "timestamp", "best_effort"]:
- self.ui.x_mode.setCurrentText(name)
- self.set_x_mode()
- else:
- self.ui.x_mode.setCurrentText("device")
- self.set_x_mode()
- self.ui.x_name.setText(name)
- self.ui.x_entry.setText(entry)
-
- @Slot()
- def set_x_mode(self):
- x_mode = self.ui.x_mode.currentText()
- if x_mode in ["index", "timestamp", "best_effort"]:
- self.ui.x_name.setEnabled(False)
- self.ui.x_entry.setEnabled(False)
- self.ui.dap_table.setEnabled(False)
- self.ui.add_dap.setEnabled(False)
- if self.ui.dap_table.rowCount() > 0:
- self.warning_util.show_warning(
- title="DAP Warning",
- message="DAP is not supported without specific x-axis device. All current DAP curves will be removed.",
- detailed_text=f"Affected curves: {[self.ui.dap_table.cellWidget(row, 0).text() for row in range(self.ui.dap_table.rowCount())]}",
- )
- else:
- self.ui.x_name.setEnabled(True)
- self.ui.x_entry.setEnabled(True)
- self.ui.dap_table.setEnabled(True)
- self.ui.add_dap.setEnabled(True)
-
- @Slot()
- def change_colormap(self, target: Literal["scan", "dap"]):
- if target == "scan":
- cm = self.ui.color_map_selector_scan.colormap
- table = self.ui.scan_table
- if target == "dap":
- cm = self.ui.color_map_selector_dap.colormap
- table = self.ui.dap_table
- rows = table.rowCount()
- colors = Colors.golden_angle_color(colormap=cm, num=max(10, rows + 1), format="HEX")
- color_button_col = 2 if target == "scan" else 3
- for row in range(rows):
- table.cellWidget(row, color_button_col).set_color(colors[row])
-
- @Slot()
- def accept_changes(self):
- self.accept_curve_changes()
-
- def accept_curve_changes(self):
- sources = ["scan_segment", "async", "DAP"]
- old_curves = []
-
- for source in sources:
- old_curves += list(self.target_widget.waveform._curves_data[source].values())
- for curve in old_curves:
- curve.remove()
- self.get_curve_params()
-
- def get_curve_params(self):
- x_mode = self.ui.x_mode.currentText()
-
- if x_mode in ["index", "timestamp", "best_effort"]:
- x_name = x_mode
- x_entry = x_mode
- else:
- x_name = self.ui.x_name.text()
- x_entry = self.ui.x_entry.text()
-
- self.target_widget.set_x(x_name=x_name, x_entry=x_entry)
-
- for row in range(self.ui.scan_table.rowCount()):
- y_name = self.ui.scan_table.cellWidget(row, 0).text()
- y_entry = self.ui.scan_table.cellWidget(row, 1).text()
- color = self.ui.scan_table.cellWidget(row, 2).get_color()
- style = self.ui.scan_table.cellWidget(row, 3).currentText()
- width = self.ui.scan_table.cellWidget(row, 4).value()
- symbol_size = self.ui.scan_table.cellWidget(row, 5).value()
- self.target_widget.plot(
- y_name=y_name,
- y_entry=y_entry,
- color=color,
- pen_style=style,
- pen_width=width,
- symbol_size=symbol_size,
- )
-
- if x_mode not in ["index", "timestamp", "best_effort"]:
-
- for row in range(self.ui.dap_table.rowCount()):
- y_name = self.ui.dap_table.cellWidget(row, 0).text()
- y_entry = self.ui.dap_table.cellWidget(row, 1).text()
- dap = self.ui.dap_table.cellWidget(row, 2).currentText()
- color = self.ui.dap_table.cellWidget(row, 3).get_color()
- style = self.ui.dap_table.cellWidget(row, 4).currentText()
- width = self.ui.dap_table.cellWidget(row, 5).value()
- symbol_size = self.ui.dap_table.cellWidget(row, 6).value()
-
- self.target_widget.add_dap(
- x_name=x_name,
- x_entry=x_entry,
- y_name=y_name,
- y_entry=y_entry,
- dap=dap,
- color=color,
- pen_style=style,
- pen_width=width,
- symbol_size=symbol_size,
- )
- self.target_widget.scan_history(-1)
-
- def add_curve(self):
- row_count = self.ui.scan_table.rowCount()
- self.ui.scan_table.insertRow(row_count)
- DialogRow(
- parent=self,
- table_widget=self.ui.scan_table,
- client=self.target_widget.client,
- row=row_count,
- config=None,
- ).add_scan_row()
-
- def add_dap(self):
- row_count = self.ui.dap_table.rowCount()
- self.ui.dap_table.insertRow(row_count)
- DialogRow(
- parent=self,
- table_widget=self.ui.dap_table,
- client=self.target_widget.client,
- row=row_count,
- config=None,
- ).add_dap_row()
-
-
-class DialogRow(QObject):
- def __init__(
- self,
- parent=None,
- table_widget: QTableWidget = None,
- row: int = None,
- config: dict = None,
- client=None,
- ):
-
- super().__init__(parent=parent)
- self.client = client
-
- self.table_widget = table_widget
- self.row = row
- self.config = config
- self.init_default_widgets()
-
- def init_default_widgets(self):
-
- # Remove Button
- self.remove_button = RemoveButton()
-
- # Name and Entry
- self.device_line_edit = DeviceLineEdit()
- self.entry_line_edit = QLineEdit()
-
- self.dap_combo = DapComboBox()
- self.dap_combo.populate_fit_model_combobox()
- self.dap_combo.select_fit_model("GaussianModel")
-
- # Styling
- self.color_button = ColorButton()
- self.style_combo = StyleComboBox()
- self.width = QSpinBox()
- self.width.setMinimum(1)
- self.width.setMaximum(20)
- self.width.setValue(4)
-
- self.symbol_size = QSpinBox()
- self.symbol_size.setMinimum(1)
- self.symbol_size.setMaximum(20)
- self.symbol_size.setValue(7)
-
- self.remove_button.clicked.connect(
- lambda: self.remove_row()
- ) # From some reason do not work without lambda
-
- def add_scan_row(self):
- if self.config is not None:
- self.device_line_edit.setText(self.config.signals.y.name)
- self.entry_line_edit.setText(self.config.signals.y.entry)
- self.color_button.set_color(self.config.color)
- self.style_combo.setCurrentText(self.config.pen_style)
- self.width.setValue(self.config.pen_width)
- self.symbol_size.setValue(self.config.symbol_size)
- else:
- default_colors = Colors.golden_angle_color(
- colormap="magma", num=max(10, self.row + 1), format="HEX"
- )
- default_color = default_colors[self.row]
- self.color_button.set_color(default_color)
-
- self.table_widget.setCellWidget(self.row, 0, self.device_line_edit)
- self.table_widget.setCellWidget(self.row, 1, self.entry_line_edit)
- self.table_widget.setCellWidget(self.row, 2, self.color_button)
- self.table_widget.setCellWidget(self.row, 3, self.style_combo)
- self.table_widget.setCellWidget(self.row, 4, self.width)
- self.table_widget.setCellWidget(self.row, 5, self.symbol_size)
- self.table_widget.setCellWidget(self.row, 6, self.remove_button)
-
- def add_dap_row(self):
- if self.config is not None:
- self.device_line_edit.setText(self.config.signals.y.name)
- self.entry_line_edit.setText(self.config.signals.y.entry)
- self.dap_combo.fit_model_combobox.setCurrentText(self.config.signals.dap)
- self.color_button.set_color(self.config.color)
- self.style_combo.setCurrentText(self.config.pen_style)
- self.width.setValue(self.config.pen_width)
- self.symbol_size.setValue(self.config.symbol_size)
- else:
- default_colors = Colors.golden_angle_color(
- colormap="magma", num=max(10, self.row + 1), format="HEX"
- )
- default_color = default_colors[self.row]
- self.color_button.set_color(default_color)
-
- self.table_widget.setCellWidget(self.row, 0, self.device_line_edit)
- self.table_widget.setCellWidget(self.row, 1, self.entry_line_edit)
- self.table_widget.setCellWidget(self.row, 2, self.dap_combo.fit_model_combobox)
- self.table_widget.setCellWidget(self.row, 3, self.color_button)
- self.table_widget.setCellWidget(self.row, 4, self.style_combo)
- self.table_widget.setCellWidget(self.row, 5, self.width)
- self.table_widget.setCellWidget(self.row, 6, self.symbol_size)
- self.table_widget.setCellWidget(self.row, 7, self.remove_button)
-
- @Slot()
- def remove_row(self):
- row = self.table_widget.indexAt(self.remove_button.pos()).row()
- self.cleanup()
- self.table_widget.removeRow(row)
-
- def cleanup(self):
- self.device_line_edit.cleanup()
-
-
-class StyleComboBox(QComboBox):
- def __init__(self, parent=None):
- super().__init__(parent)
- self.addItems(["solid", "dash", "dot", "dashdot"])
-
-
-class RemoveButton(QPushButton):
- def __init__(self, parent=None):
- super().__init__(parent)
- icon = material_icon("disabled_by_default", size=(20, 20), convert_to_pixmap=False)
- self.setIcon(icon)
diff --git a/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui b/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui
deleted file mode 100644
index 1f087e90..00000000
--- a/bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui
+++ /dev/null
@@ -1,372 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 720
- 806
-
-
-
- Form
-
-
-
- 2
-
-
- 2
-
-
- 2
-
-
- 2
-
- -
-
-
- X Axis
-
-
-
-
-
-
- X Axis Mode
-
-
-
- -
-
-
-
- 150
- 26
-
-
-
-
-
- best_effort
-
-
- -
-
- device
-
-
- -
-
- index
-
-
- -
-
- timestamp
-
-
-
-
- -
-
-
- Qt::Orientation::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Qt::Orientation::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Name
-
-
-
- -
-
-
- -
-
-
- Entry
-
-
-
- -
-
-
-
-
-
- -
-
-
- Y Axis
-
-
-
-
-
-
- 0
-
-
-
- Scan
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
-
-
-
- Normalize Colors
-
-
-
- -
-
-
- 0
-
-
- false
-
-
- true
-
-
- true
-
-
- false
-
-
-
- Name
-
-
-
-
- Entry
-
-
-
-
- Color
-
-
-
-
- Style
-
-
-
-
- Width
-
-
-
-
- Symbol Size
-
-
-
-
- Delete
-
-
-
-
- -
-
-
- Qt::Orientation::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- DAP
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
- -
-
-
- true
-
-
- true
-
-
-
- Name
-
-
-
-
- Entry
-
-
-
-
- Model
-
-
-
-
- Color
-
-
-
-
- Style
-
-
-
-
- Width
-
-
-
-
- Symbol Size
-
-
-
-
- Delete
-
-
-
-
- -
-
-
- Normalize Colors
-
-
-
- -
-
-
- Qt::Orientation::Horizontal
-
-
-
- 585
- 20
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- DeviceLineEdit
- QLineEdit
-
-
-
- BECColorMapWidget
- QWidget
-
-
-
-
-
-
diff --git a/bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/__init__.py b/bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py b/bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py
deleted file mode 100644
index 4a1adba5..00000000
--- a/bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from qtpy.QtWidgets import QDialog, QVBoxLayout
-
-from bec_widgets.widgets.dap.lmfit_dialog.lmfit_dialog import LMFitDialog
-
-
-class FitSummaryWidget(QDialog):
-
- def __init__(self, parent=None, target_widget=None):
- super().__init__(parent=parent)
-
- self.setModal(True)
- self.target_widget = target_widget
- self.dap_dialog = LMFitDialog(parent=self, ui_file="lmfit_dialog_compact.ui")
- self.layout = QVBoxLayout(self)
- self.layout.addWidget(self.dap_dialog)
- self.target_widget.dap_summary_update.connect(self.dap_dialog.update_summary_tree)
- self.setLayout(self.layout)
- self._get_dap_from_target_widget()
-
- def _get_dap_from_target_widget(self) -> None:
- """Get the DAP data from the target widget and update the DAP dialog manually on creation."""
- dap_summary = self.target_widget.get_dap_summary()
- for curve_id, data in dap_summary.items():
- md = {"curve_id": curve_id}
- self.dap_dialog.update_summary_tree(data=data, metadata=md)
diff --git a/bec_widgets/widgets/plots/waveform/waveform_widget.py b/bec_widgets/widgets/plots/waveform/waveform_widget.py
deleted file mode 100644
index a5be8759..00000000
--- a/bec_widgets/widgets/plots/waveform/waveform_widget.py
+++ /dev/null
@@ -1,751 +0,0 @@
-from __future__ import annotations
-
-import sys
-from typing import Literal
-
-import numpy as np
-import pyqtgraph as pg
-from bec_lib.logger import bec_logger
-from qtpy.QtCore import Property, Signal, Slot
-from qtpy.QtWidgets import QVBoxLayout, QWidget
-
-from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
-from bec_widgets.qt_utils.settings_dialog import SettingsDialog
-from bec_widgets.qt_utils.toolbar import MaterialIconAction, ModularToolBar, SeparatorAction
-from bec_widgets.utils.bec_widget import BECWidget
-from bec_widgets.widgets.containers.figure import BECFigure
-from bec_widgets.widgets.containers.figure.plots.axis_settings import AxisSettings
-from bec_widgets.widgets.containers.figure.plots.waveform.waveform import Waveform1DConfig
-from bec_widgets.widgets.containers.figure.plots.waveform.waveform_curve import BECCurve
-from bec_widgets.widgets.plots.waveform.waveform_popups.curve_dialog.curve_dialog import (
- CurveSettings,
-)
-from bec_widgets.widgets.plots.waveform.waveform_popups.dap_summary_dialog.dap_summary_dialog import (
- FitSummaryWidget,
-)
-
-try:
- import pandas as pd
-except ImportError:
- pd = None
-
-logger = bec_logger.logger
-
-
-class BECWaveformWidget(BECWidget, QWidget):
- PLUGIN = True
- ICON_NAME = "show_chart"
- USER_ACCESS = [
- "curves",
- "plot",
- "add_dap",
- "get_dap_params",
- "remove_curve",
- "scan_history",
- "get_all_data",
- "set",
- "set_x",
- "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_auto_range",
- "set_grid",
- "enable_fps_monitor",
- "enable_scatter",
- "lock_aspect_ratio",
- "export",
- "export_to_matplotlib",
- "toggle_roi",
- "select_roi",
- ]
- scan_signal_update = Signal()
- async_signal_update = Signal()
- dap_summary_update = Signal(dict, dict)
- dap_params_update = Signal(dict, dict)
- autorange_signal = Signal()
- new_scan = Signal()
- crosshair_position_changed = Signal(tuple)
- crosshair_position_changed_string = Signal(str)
- crosshair_position_clicked = Signal(tuple)
- crosshair_position_clicked_string = Signal(str)
- crosshair_coordinates_changed = Signal(tuple)
- crosshair_coordinates_changed_string = Signal(str)
- crosshair_coordinates_clicked = Signal(tuple)
- crosshair_coordinates_clicked_string = Signal(str)
- roi_changed = Signal(tuple)
- roi_active = Signal(bool)
-
- def __init__(
- self,
- parent: QWidget | None = None,
- config: Waveform1DConfig | dict = None,
- client=None,
- gui_id: str | None = None,
- **kwargs,
- ) -> None:
- 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, **kwargs)
- 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={
- "save": MaterialIconAction(icon_name="save", tooltip="Open Export Dialog"),
- "matplotlib": MaterialIconAction(
- icon_name="photo_library", tooltip="Open Matplotlib Plot"
- ),
- "separator_1": SeparatorAction(),
- "drag_mode": MaterialIconAction(
- icon_name="drag_pan", tooltip="Drag Mouse Mode", checkable=True
- ),
- "rectangle_mode": MaterialIconAction(
- icon_name="frame_inspect", tooltip="Rectangle Zoom Mode", checkable=True
- ),
- "auto_range": MaterialIconAction(
- icon_name="open_in_full", tooltip="Autorange Plot"
- ),
- "separator_2": SeparatorAction(),
- "curves": MaterialIconAction(
- icon_name="timeline", tooltip="Open Curves Configuration"
- ),
- "fit_params": MaterialIconAction(
- icon_name="monitoring", tooltip="Open Fitting Parameters"
- ),
- "separator_3": SeparatorAction(),
- "crosshair": MaterialIconAction(
- icon_name="point_scan", tooltip="Show Crosshair", checkable=True
- ),
- "roi_select": MaterialIconAction(
- icon_name="align_justify_space_between",
- tooltip="Add ROI region for DAP",
- checkable=True,
- ),
- "separator_4": SeparatorAction(),
- "fps_monitor": MaterialIconAction(
- icon_name="speed", tooltip="Show FPS Monitor", checkable=True
- ),
- "axis_settings": MaterialIconAction(
- icon_name="settings", tooltip="Open Configuration Dialog"
- ),
- },
- target_widget=self,
- )
-
- self.layout.addWidget(self.toolbar)
- self.layout.addWidget(self.fig)
-
- self.warning_util = WarningPopupUtility(self)
-
- self.waveform = self.fig.plot()
- self.waveform.apply_config(config)
-
- self.config = config
- self._clear_curves_on_plot_update = False
-
- self.hook_waveform_signals()
- self._hook_actions()
-
- def hook_waveform_signals(self):
- self.waveform.scan_signal_update.connect(self.scan_signal_update)
- self.waveform.async_signal_update.connect(self.async_signal_update)
- self.waveform.dap_params_update.connect(self.dap_params_update)
- self.waveform.dap_summary_update.connect(self.dap_summary_update)
- self.waveform.autorange_signal.connect(self.autorange_signal)
- self.waveform.new_scan.connect(self.new_scan)
- self.waveform.crosshair_coordinates_changed.connect(self.crosshair_coordinates_changed)
- self.waveform.crosshair_coordinates_clicked.connect(self.crosshair_coordinates_clicked)
- self.waveform.crosshair_coordinates_changed.connect(
- self._emit_crosshair_coordinates_changed_string
- )
- self.waveform.crosshair_coordinates_clicked.connect(
- self._emit_crosshair_coordinates_clicked_string
- )
- self.waveform.crosshair_position_changed.connect(self.crosshair_position_changed)
- self.waveform.crosshair_position_clicked.connect(self.crosshair_position_clicked)
- self.waveform.crosshair_position_changed.connect(
- self._emit_crosshair_position_changed_string
- )
- self.waveform.crosshair_position_clicked.connect(
- self._emit_crosshair_position_clicked_string
- )
- self.waveform.roi_changed.connect(self.roi_changed)
- self.waveform.roi_active.connect(self.roi_active)
-
- def _hook_actions(self):
- self.toolbar.widgets["save"].action.triggered.connect(self.export)
- self.toolbar.widgets["matplotlib"].action.triggered.connect(self.export_to_matplotlib)
- self.toolbar.widgets["drag_mode"].action.triggered.connect(self.enable_mouse_pan_mode)
- self.toolbar.widgets["rectangle_mode"].action.triggered.connect(
- self.enable_mouse_rectangle_mode
- )
- self.toolbar.widgets["auto_range"].action.triggered.connect(self._auto_range_from_toolbar)
- self.toolbar.widgets["curves"].action.triggered.connect(self.show_curve_settings)
- self.toolbar.widgets["fit_params"].action.triggered.connect(self.show_fit_summary_dialog)
- self.toolbar.widgets["axis_settings"].action.triggered.connect(self.show_axis_settings)
- self.toolbar.widgets["crosshair"].action.triggered.connect(self.waveform.toggle_crosshair)
- self.toolbar.widgets["roi_select"].action.toggled.connect(self.waveform.toggle_roi)
- self.toolbar.widgets["fps_monitor"].action.toggled.connect(self.enable_fps_monitor)
- # self.toolbar.widgets["import"].action.triggered.connect(
- # lambda: self.load_config(path=None, gui=True)
- # )
- # self.toolbar.widgets["export"].action.triggered.connect(
- # lambda: self.save_config(path=None, gui=True)
- # )
-
- @Slot(bool)
- def toogle_roi_select(self, checked: bool):
- """Toggle the linear region selector.
-
- Args:
- checked(bool): If True, enable the linear region selector.
- """
- self.toolbar.widgets["roi_select"].action.setChecked(checked)
-
- @Property(bool)
- def clear_curves_on_plot_update(self) -> bool:
- """If True, clear curves on plot update."""
- return self._clear_curves_on_plot_update
-
- @clear_curves_on_plot_update.setter
- def clear_curves_on_plot_update(self, value: bool):
- """Set the clear curves on plot update property.
-
- Args:
- value(bool): If True, clear curves on plot update.
- """
- self._clear_curves_on_plot_update = value
-
- @SafeSlot(tuple)
- def _emit_crosshair_coordinates_changed_string(self, coordinates):
- self.crosshair_coordinates_changed_string.emit(str(coordinates))
-
- @SafeSlot(tuple)
- def _emit_crosshair_coordinates_clicked_string(self, coordinates):
- self.crosshair_coordinates_clicked_string.emit(str(coordinates))
-
- @SafeSlot(tuple)
- def _emit_crosshair_position_changed_string(self, position):
- self.crosshair_position_changed_string.emit(str(position))
-
- @SafeSlot(tuple)
- def _emit_crosshair_position_clicked_string(self, position):
- self.crosshair_position_clicked_string.emit(str(position))
-
- ###################################
- # Dialog Windows
- ###################################
- def show_axis_settings(self):
- dialog = SettingsDialog(
- self,
- settings_widget=AxisSettings(),
- window_title="Axis Settings",
- config=self._config_dict["axis"],
- )
- dialog.exec()
-
- def show_curve_settings(self):
- dialog = SettingsDialog(
- self,
- settings_widget=CurveSettings(),
- window_title="Curve Settings",
- config=self.waveform._curves_data,
- )
- dialog.resize(800, 600)
- dialog.exec()
-
- def show_fit_summary_dialog(self):
- dialog = FitSummaryWidget(target_widget=self)
- dialog.resize(800, 600)
- 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 set_colormap(self, colormap: str):
- """
- Set the colormap of the plot widget.
-
- Args:
- colormap(str, optional): Scale the colors of curves to colormap. If None, use the default color palette.
- """
- self.waveform.set_colormap(colormap)
-
- @Slot(str, str) # Slot for x_name, x_entry
- @SafeSlot(str, popup_error=True) # Slot for x_name and
- 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.
- """
- self.waveform.set_x(x_name, x_entry)
-
- @Slot(str) # Slot for y_name
- @SafeSlot(popup_error=True)
- def plot(
- self,
- arg1: list | np.ndarray | str | None = None,
- 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 = "magma",
- label: str | None = None,
- validate: bool = True,
- dap: str | None = None, # TODO add dap custom curve wrapper
- **kwargs,
- ) -> BECCurve:
- """
- Plot a curve to the plot widget.
- Args:
- 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).
- 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.
- """
- if self.clear_curves_on_plot_update is True:
- self.waveform.clear_source(source="scan_segment")
- return self.waveform.plot(
- arg1=arg1,
- 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,
- **kwargs,
- )
-
- @Slot(
- str, str, str, str, str, str, bool
- ) # Slot for x_name, y_name, x_entry, y_entry, color, validate_bec
- @SafeSlot(str, str, str, popup_error=True)
- def add_dap(
- self,
- x_name: str,
- y_name: str,
- dap: str,
- x_entry: str | None = None,
- y_entry: str | None = None,
- color: str | None = None,
- validate_bec: bool = True,
- **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.
- 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.
-
- Returns:
- BECCurve: The curve object.
- """
- if self.clear_curves_on_plot_update is True:
- self.waveform.clear_source(source="DAP")
- 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,
- validate_bec=validate_bec,
- **kwargs,
- )
-
- def get_dap_params(self) -> dict:
- """
- Get the DAP parameters of all DAP curves.
-
- Returns:
- dict: DAP parameters of all DAP curves.
- """
-
- return self.waveform.get_dap_params()
-
- def get_dap_summary(self) -> dict:
- """
- Get the DAP summary of all DAP curves.
-
- Returns:
- dict: DAP summary of all DAP curves.
- """
- return self.waveform.get_dap_summary()
-
- 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":
- logger.warning(
- "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_auto_range(self, enabled: bool, axis: str = "xy"):
- """
- Set the auto range of the plot widget.
-
- Args:
- enabled(bool): If True, enable the auto range.
- axis(str, optional): The axis to enable the auto range.
- - "xy": Enable auto range for both x and y axis.
- - "x": Enable auto range for x axis.
- - "y": Enable auto range for y axis.
- """
- self.waveform.set_auto_range(enabled, axis)
-
- def toggle_roi(self, checked: bool):
- """Toggle the linear region selector.
-
- Args:
- checked(bool): If True, enable the linear region selector.
- """
- self.waveform.toggle_roi(checked)
- if self.toolbar.widgets["roi_select"].action.isChecked() != checked:
- self.toolbar.widgets["roi_select"].action.setChecked(checked)
-
- def select_roi(self, region: tuple):
- """
- Set the region of interest of the plot widget.
-
- Args:
- region(tuple): Region of interest.
- """
- self.waveform.select_roi(region)
-
- def enable_fps_monitor(self, enabled: bool):
- """
- Enable the FPS monitor of the plot widget.
-
- Args:
- enabled(bool): If True, enable the FPS monitor.
- """
- self.waveform.enable_fps_monitor(enabled)
- if self.toolbar.widgets["fps_monitor"].action.isChecked() != enabled:
- self.toolbar.widgets["fps_monitor"].action.setChecked(enabled)
-
- @SafeSlot()
- def _auto_range_from_toolbar(self):
- """
- Set the auto range of the plot widget from the toolbar.
- """
- self.waveform.set_auto_range(True, "xy")
-
- 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 set_outer_axes(self, show: bool):
- """
- Set the outer axes visibility of the plot widget.
-
- Args:
- show(bool): Visibility of the outer axes.
- """
- self.waveform.set_outer_axes(show)
-
- def enable_scatter(self, enabled: bool):
- """
- Enable the scatter plot of the plot widget.
-
- Args:
- enabled(bool): If True, enable the scatter plot.
- """
- self.waveform.enable_scatter(enabled)
-
- 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)
-
- @SafeSlot()
- def enable_mouse_rectangle_mode(self):
- self.toolbar.widgets["rectangle_mode"].action.setChecked(True)
- self.toolbar.widgets["drag_mode"].action.setChecked(False)
- self.waveform.plot_item.getViewBox().setMouseMode(pg.ViewBox.RectMode)
-
- @SafeSlot()
- def enable_mouse_pan_mode(self):
- self.toolbar.widgets["drag_mode"].action.setChecked(True)
- self.toolbar.widgets["rectangle_mode"].action.setChecked(False)
- self.waveform.plot_item.getViewBox().setMouseMode(pg.ViewBox.PanMode)
-
- def export(self):
- """
- Show the export dialog for the plot widget.
- """
- self.waveform.export()
-
- def export_to_matplotlib(self):
- """
- Export the plot widget to Matplotlib.
- """
- try:
- import matplotlib as mpl
- except ImportError:
- self.warning_util.show_warning(
- title="Matplotlib not installed",
- message="Matplotlib is required for this feature.",
- detailed_text="Please install matplotlib in your Python environment by using 'pip install matplotlib'.",
- )
- return
- self.waveform.export_to_matplotlib()
-
- #######################################
- # User Access Methods from BECConnector
- ######################################
- def load_config(self, path: str | None = None, gui: bool = False):
- """
- Load the configuration of the widget from YAML.
-
- Args:
- path(str): Path to the configuration file for non-GUI dialog mode.
- gui(bool): If True, use the GUI dialog to load the configuration file.
- """
- self.fig.load_config(path=path, gui=gui)
-
- def save_config(self, path: str | None = None, gui: bool = False):
- """
- Save the configuration of the widget to YAML.
-
- Args:
- path(str): Path to save the configuration file for non-GUI dialog mode.
- gui(bool): If True, use the GUI dialog to save the configuration file.
- """
- self.fig.save_config(path=path, gui=gui)
-
- def cleanup(self):
- self.fig.cleanup()
- return super().cleanup()
-
-
-def main(): # pragma: no cover
- from qtpy.QtWidgets import QApplication
-
- app = QApplication(sys.argv)
- widget = BECWaveformWidget()
- widget.plot(x_name="samx", y_name="bpm4i")
- widget.plot(y_name="bpm3i")
- widget.plot(y_name="bpm4a")
- widget.plot(y_name="bpm5i")
- widget.show()
- sys.exit(app.exec_())
-
-
-if __name__ == "__main__": # pragma: no cover
- main()
diff --git a/tests/unit_tests/test_bec_dock.py b/tests/unit_tests/test_bec_dock.py
index e205a0f5..fe50a219 100644
--- a/tests/unit_tests/test_bec_dock.py
+++ b/tests/unit_tests/test_bec_dock.py
@@ -115,7 +115,7 @@ def test_undock_and_dock_docks(bec_dock_area, qtbot):
def test_toolbar_add_plot_waveform(bec_dock_area):
bec_dock_area.toolbar.widgets["menu_plots"].widgets["waveform"].trigger()
assert "waveform_1" in bec_dock_area.panels
- assert bec_dock_area.panels["waveform_1"].widgets[0].config.widget_class == "BECWaveformWidget"
+ assert bec_dock_area.panels["waveform_1"].widgets[0].config.widget_class == "Waveform"
def test_toolbar_add_plot_image(bec_dock_area):
diff --git a/tests/unit_tests/test_crosshair.py b/tests/unit_tests/test_crosshair.py
index 8c614a55..5f0bf98a 100644
--- a/tests/unit_tests/test_crosshair.py
+++ b/tests/unit_tests/test_crosshair.py
@@ -1,9 +1,10 @@
import numpy as np
+import pyqtgraph as pg
import pytest
from qtpy.QtCore import QPointF, Qt
+from bec_widgets.utils import Crosshair
from bec_widgets.widgets.plots.image.image_widget import BECImageWidget
-from bec_widgets.widgets.plots.waveform.waveform_widget import BECWaveformWidget
from .client_mocks import mocked_client
@@ -11,14 +12,16 @@ from .client_mocks import mocked_client
@pytest.fixture
-def plot_widget_with_crosshair(qtbot, mocked_client):
- widget = BECWaveformWidget(client=mocked_client())
- widget.plot(x=[1, 2, 3], y=[4, 5, 6])
- widget.waveform.hook_crosshair()
+def plot_widget_with_crosshair(qtbot):
+ widget = pg.PlotWidget()
qtbot.addWidget(widget)
qtbot.waitExposed(widget)
- yield widget.waveform.crosshair, widget.waveform.plot_item
+ widget.plot(x=[1, 2, 3], y=[4, 5, 6], name="Curve 1")
+ plot_item = widget.getPlotItem()
+ crosshair = Crosshair(plot_item=plot_item, precision=3)
+
+ yield crosshair, plot_item
@pytest.fixture
@@ -35,15 +38,14 @@ def image_widget_with_crosshair(qtbot, mocked_client):
def test_mouse_moved_lines(plot_widget_with_crosshair):
crosshair, plot_item = plot_widget_with_crosshair
- # Simulate a mouse moved event at a specific position
pos_in_view = QPointF(2, 5)
pos_in_scene = plot_item.vb.mapViewToScene(pos_in_view)
event_mock = [pos_in_scene]
- # Call the mouse_moved method
+ # Simulate mouse movement
crosshair.mouse_moved(event_mock)
- # Assert the expected behavior
+ # Check that the vertical line is indeed at x=2
assert np.isclose(crosshair.v_line.pos().x(), 2)
assert np.isclose(crosshair.h_line.pos().y(), 5)
diff --git a/tests/unit_tests/test_waveform_widget.py b/tests/unit_tests/test_waveform_widget.py
deleted file mode 100644
index d40a0f4b..00000000
--- a/tests/unit_tests/test_waveform_widget.py
+++ /dev/null
@@ -1,573 +0,0 @@
-from unittest.mock import MagicMock, patch
-
-import pyqtgraph as pg
-import pytest
-from qtpy.QtGui import QColor
-from qtpy.QtWidgets import QApplication
-
-from bec_widgets.qt_utils.settings_dialog import SettingsDialog
-from bec_widgets.utils.colors import apply_theme, get_theme_palette, set_theme
-from bec_widgets.utils.linear_region_selector import LinearRegionWrapper
-from bec_widgets.widgets.containers.figure.plots.axis_settings import AxisSettings
-from bec_widgets.widgets.plots.waveform.waveform_popups.curve_dialog.curve_dialog import (
- CurveSettings,
-)
-from bec_widgets.widgets.plots.waveform.waveform_popups.dap_summary_dialog.dap_summary_dialog import (
- FitSummaryWidget,
-)
-from bec_widgets.widgets.plots.waveform.waveform_widget import BECWaveformWidget
-
-from .client_mocks import mocked_client
-from .conftest import create_widget
-
-
-@pytest.fixture
-def waveform_widget(qtbot, mocked_client):
- models = ["GaussianModel", "LorentzModel", "SineModel"]
- mocked_client.dap._available_dap_plugins.keys.return_value = models
- widget = BECWaveformWidget(client=mocked_client())
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- yield widget
-
-
-@pytest.fixture
-def mock_waveform(waveform_widget):
- waveform_mock = MagicMock()
- waveform_widget.waveform = waveform_mock
- return waveform_mock
-
-
-def test_waveform_widget_init(waveform_widget):
- assert waveform_widget is not None
- assert waveform_widget.client is not None
- assert isinstance(waveform_widget, BECWaveformWidget)
- assert waveform_widget.config.widget_class == "BECWaveformWidget"
-
-
-###################################
-# Wrapper methods for Waveform
-###################################
-
-
-def test_waveform_widget_get_curve(waveform_widget, mock_waveform):
- waveform_widget.get_curve("curve_id")
- waveform_widget.waveform.get_curve.assert_called_once_with("curve_id")
-
-
-def test_waveform_widget_set_colormap(waveform_widget, mock_waveform):
- waveform_widget.set_colormap("colormap")
- waveform_widget.waveform.set_colormap.assert_called_once_with("colormap")
-
-
-def test_waveform_widget_set_x(waveform_widget, mock_waveform):
- waveform_widget.set_x("samx", "samx")
- waveform_widget.waveform.set_x.assert_called_once_with("samx", "samx")
-
-
-def test_waveform_plot_data(waveform_widget, mock_waveform):
- waveform_widget.plot(x=[1, 2, 3], y=[1, 2, 3])
- waveform_widget.waveform.plot.assert_called_once_with(
- arg1=None,
- x=[1, 2, 3],
- y=[1, 2, 3],
- x_name=None,
- y_name=None,
- z_name=None,
- x_entry=None,
- y_entry=None,
- z_entry=None,
- color=None,
- color_map_z="magma",
- label=None,
- validate=True,
- dap=None,
- )
-
-
-def test_waveform_plot_scan_curves(waveform_widget, mock_waveform):
- waveform_widget.plot(x_name="samx", y_name="samy", dap="GaussianModel")
- waveform_widget.waveform.plot.assert_called_once_with(
- arg1=None,
- x=None,
- y=None,
- x_name="samx",
- y_name="samy",
- z_name=None,
- x_entry=None,
- y_entry=None,
- z_entry=None,
- color=None,
- color_map_z="magma",
- label=None,
- validate=True,
- dap="GaussianModel",
- )
-
-
-def test_waveform_widget_add_dap(waveform_widget, mock_waveform):
- waveform_widget.add_dap(x_name="samx", y_name="bpm4i", dap="GaussianModel")
- waveform_widget.waveform.add_dap.assert_called_once_with(
- x_name="samx",
- y_name="bpm4i",
- x_entry=None,
- y_entry=None,
- color=None,
- dap="GaussianModel",
- validate_bec=True,
- )
-
-
-def test_waveform_widget_get_dap_params(waveform_widget, mock_waveform):
- waveform_widget.get_dap_params()
- waveform_widget.waveform.get_dap_params.assert_called_once()
-
-
-def test_waveform_widget_get_dap_summary(waveform_widget, mock_waveform):
- waveform_widget.get_dap_summary()
- waveform_widget.waveform.get_dap_summary.assert_called_once()
-
-
-def test_waveform_widget_remove_curve(waveform_widget, mock_waveform):
- waveform_widget.remove_curve("curve_id")
- waveform_widget.waveform.remove_curve.assert_called_once_with("curve_id")
-
-
-def test_waveform_widget_scan_history(waveform_widget, mock_waveform):
- waveform_widget.scan_history(0)
- waveform_widget.waveform.scan_history.assert_called_once_with(0, None)
-
-
-def test_waveform_widget_get_all_data(waveform_widget, mock_waveform):
- waveform_widget.get_all_data()
- waveform_widget.waveform.get_all_data.assert_called_once()
-
-
-def test_waveform_widget_set_title(waveform_widget, mock_waveform):
- waveform_widget.set_title("Title")
- waveform_widget.waveform.set_title.assert_called_once_with("Title")
-
-
-def test_waveform_widget_set_base(waveform_widget, mock_waveform):
- waveform_widget.set(
- title="Test Title",
- x_label="X Label",
- y_label="Y Label",
- x_scale="linear",
- y_scale="log",
- x_lim=(0, 10),
- y_lim=(0, 10),
- legend_label_size=12,
- )
- waveform_widget.waveform.set.assert_called_once_with(
- title="Test Title",
- x_label="X Label",
- y_label="Y Label",
- x_scale="linear",
- y_scale="log",
- x_lim=(0, 10),
- y_lim=(0, 10),
- legend_label_size=12,
- )
-
-
-def test_waveform_widget_set_x_label(waveform_widget, mock_waveform):
- waveform_widget.set_x_label("X Label")
- waveform_widget.waveform.set_x_label.assert_called_once_with("X Label")
-
-
-def test_waveform_widget_set_y_label(waveform_widget, mock_waveform):
- waveform_widget.set_y_label("Y Label")
- waveform_widget.waveform.set_y_label.assert_called_once_with("Y Label")
-
-
-def test_waveform_widget_set_x_scale(waveform_widget, mock_waveform):
- waveform_widget.set_x_scale("linear")
- waveform_widget.waveform.set_x_scale.assert_called_once_with("linear")
-
-
-def test_waveform_widget_set_y_scale(waveform_widget, mock_waveform):
- waveform_widget.set_y_scale("log")
- waveform_widget.waveform.set_y_scale.assert_called_once_with("log")
-
-
-def test_waveform_widget_set_x_lim(waveform_widget, mock_waveform):
- waveform_widget.set_x_lim((0, 10))
- waveform_widget.waveform.set_x_lim.assert_called_once_with((0, 10))
-
-
-def test_waveform_widget_set_y_lim(waveform_widget, mock_waveform):
- waveform_widget.set_y_lim((0, 10))
- waveform_widget.waveform.set_y_lim.assert_called_once_with((0, 10))
-
-
-def test_waveform_widget_set_legend_label_size(waveform_widget, mock_waveform):
- waveform_widget.set_legend_label_size(12)
- waveform_widget.waveform.set_legend_label_size.assert_called_once_with(12)
-
-
-def test_waveform_widget_set_auto_range(waveform_widget, mock_waveform):
- waveform_widget.set_auto_range(True, "xy")
- waveform_widget.waveform.set_auto_range.assert_called_once_with(True, "xy")
-
-
-def test_waveform_widget_set_grid(waveform_widget, mock_waveform):
- waveform_widget.set_grid(True, False)
- waveform_widget.waveform.set_grid.assert_called_once_with(True, False)
-
-
-def test_waveform_widget_lock_aspect_ratio(waveform_widget, mock_waveform):
- waveform_widget.lock_aspect_ratio(True)
- waveform_widget.waveform.lock_aspect_ratio.assert_called_once_with(True)
-
-
-def test_waveform_widget_export(waveform_widget, mock_waveform):
- waveform_widget.export()
- waveform_widget.waveform.export.assert_called_once()
-
-
-###################################
-# ToolBar interactions
-###################################
-
-
-def test_toolbar_drag_mode_action_triggered(waveform_widget, qtbot):
- action_drag = waveform_widget.toolbar.widgets["drag_mode"].action
- action_rectangle = waveform_widget.toolbar.widgets["rectangle_mode"].action
- action_drag.trigger()
- assert action_drag.isChecked() == True
- assert action_rectangle.isChecked() == False
-
-
-def test_toolbar_rectangle_mode_action_triggered(waveform_widget, qtbot):
- action_drag = waveform_widget.toolbar.widgets["drag_mode"].action
- action_rectangle = waveform_widget.toolbar.widgets["rectangle_mode"].action
- action_rectangle.trigger()
- assert action_drag.isChecked() == False
- assert action_rectangle.isChecked() == True
-
-
-def test_toolbar_auto_range_action_triggered(waveform_widget, mock_waveform, qtbot):
- action = waveform_widget.toolbar.widgets["auto_range"].action
- action.trigger()
- qtbot.wait(200)
- waveform_widget.waveform.set_auto_range.assert_called_once_with(True, "xy")
-
-
-def test_enable_mouse_pan_mode(qtbot, waveform_widget):
- action_drag = waveform_widget.toolbar.widgets["drag_mode"].action
- action_rectangle = waveform_widget.toolbar.widgets["rectangle_mode"].action
-
- mock_view_box = MagicMock()
- waveform_widget.waveform.plot_item.getViewBox = MagicMock(return_value=mock_view_box)
-
- waveform_widget.enable_mouse_pan_mode()
-
- assert action_drag.isChecked() == True
- assert action_rectangle.isChecked() == False
- mock_view_box.setMouseMode.assert_called_once_with(pg.ViewBox.PanMode)
-
-
-###################################
-# Curve Dialog Tests
-###################################
-def show_curve_dialog(qtbot, waveform_widget):
- curve_dialog = SettingsDialog(
- waveform_widget,
- settings_widget=CurveSettings(),
- window_title="Curve Settings",
- config=waveform_widget.waveform._curves_data,
- )
- qtbot.addWidget(curve_dialog)
- qtbot.waitExposed(curve_dialog)
- return curve_dialog
-
-
-def test_curve_dialog_scan_curves_interactions(qtbot, waveform_widget):
- waveform_widget.plot(y_name="bpm4i")
- waveform_widget.plot(y_name="bpm3a")
-
- curve_dialog = show_curve_dialog(qtbot, waveform_widget)
-
- # Check default display of config from waveform widget
- assert curve_dialog is not None
- assert curve_dialog.widget.ui.scan_table.rowCount() == 2
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 0).text() == "bpm4i"
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 1).text() == "bpm4i"
- assert curve_dialog.widget.ui.scan_table.cellWidget(1, 0).text() == "bpm3a"
- assert curve_dialog.widget.ui.scan_table.cellWidget(1, 1).text() == "bpm3a"
- assert curve_dialog.widget.ui.x_mode.currentText() == "best_effort"
- assert curve_dialog.widget.ui.x_name.isEnabled() == False
- assert curve_dialog.widget.ui.x_entry.isEnabled() == False
-
- # Add a new curve
- curve_dialog.widget.ui.add_curve.click()
- qtbot.wait(200)
- assert curve_dialog.widget.ui.scan_table.rowCount() == 3
-
- # Set device to new curve
- curve_dialog.widget.ui.scan_table.cellWidget(2, 0).setText("bpm3i")
-
- # Change the x mode to device
- curve_dialog.widget.ui.x_mode.setCurrentText("device")
- qtbot.wait(200)
- assert curve_dialog.widget.ui.x_name.isEnabled() == True
- assert curve_dialog.widget.ui.x_entry.isEnabled() == True
-
- # Set the x device
- curve_dialog.widget.ui.x_name.setText("samx")
-
- # Delete first curve ('bpm4i')
- curve_dialog.widget.ui.scan_table.cellWidget(0, 6).click()
- qtbot.wait(200)
- assert curve_dialog.widget.ui.scan_table.rowCount() == 2
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 0).text() == "bpm3a"
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 1).text() == "bpm3a"
- assert curve_dialog.widget.ui.scan_table.cellWidget(1, 0).text() == "bpm3i"
-
- # Close the dialog
- curve_dialog.accept()
- qtbot.wait(200)
-
- # Check the curve data in the target widget
- assert list(waveform_widget.waveform._curves_data["scan_segment"].keys()) == [
- "bpm3a-bpm3a",
- "bpm3i-bpm3i",
- ]
- assert len(waveform_widget.curves) == 2
-
-
-def test_curve_dialog_async(qtbot, waveform_widget):
- waveform_widget.plot(y_name="bpm4i")
- waveform_widget.plot(y_name="async_device")
-
- curve_dialog = show_curve_dialog(qtbot, waveform_widget)
-
- assert curve_dialog is not None
- assert curve_dialog.widget.ui.scan_table.rowCount() == 2
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 0).text() == "bpm4i"
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 1).text() == "bpm4i"
- assert curve_dialog.widget.ui.scan_table.cellWidget(1, 0).text() == "async_device"
- assert curve_dialog.widget.ui.scan_table.cellWidget(1, 1).text() == "async_device"
-
-
-def test_curve_dialog_dap(qtbot, waveform_widget):
- # Don't use default dap for curve_dialog dialog
- waveform_widget.plot(x_name="samx", y_name="bpm4i", dap="LorentzModel")
-
- curve_dialog = show_curve_dialog(qtbot, waveform_widget)
-
- assert curve_dialog is not None
- assert curve_dialog.widget.ui.scan_table.rowCount() == 1
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 0).text() == "bpm4i"
- assert curve_dialog.widget.ui.scan_table.cellWidget(0, 1).text() == "bpm4i"
- assert curve_dialog.widget.ui.dap_table.isEnabled() == True
- assert curve_dialog.widget.ui.dap_table.rowCount() == 1
- assert curve_dialog.widget.ui.dap_table.cellWidget(0, 0).text() == "bpm4i"
- assert curve_dialog.widget.ui.dap_table.cellWidget(0, 1).text() == "bpm4i"
- assert curve_dialog.widget.ui.dap_table.cellWidget(0, 2).currentText() == "LorentzModel"
- assert curve_dialog.widget.ui.x_mode.currentText() == "device"
- assert curve_dialog.widget.ui.x_name.isEnabled() == True
- assert curve_dialog.widget.ui.x_entry.isEnabled() == True
- assert curve_dialog.widget.ui.x_name.text() == "samx"
- assert curve_dialog.widget.ui.x_entry.text() == "samx"
-
- curve_dialog.accept()
- qtbot.wait(200)
-
- assert list(waveform_widget.waveform._curves_data["scan_segment"].keys()) == ["bpm4i-bpm4i"]
- assert len(waveform_widget.curves) == 2
-
-
-def test_fit_dialog_summary(qtbot, waveform_widget):
- """Test the fit dialog summary widget"""
- waveform_widget.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
- fit_dialog_summary = create_widget(qtbot, FitSummaryWidget, target_widget=waveform_widget)
- assert fit_dialog_summary.dap_dialog.fit_curve_id == "bpm4i-bpm4i-GaussianModel"
- assert fit_dialog_summary.dap_dialog.ui.curve_list.count() == 1
-
-
-###################################
-# Axis Dialog Tests
-###################################
-
-
-def show_axis_dialog(qtbot, waveform_widget):
- axis_dialog = SettingsDialog(
- waveform_widget,
- settings_widget=AxisSettings(),
- window_title="Axis Settings",
- config=waveform_widget._config_dict["axis"],
- )
- qtbot.addWidget(axis_dialog)
- qtbot.waitExposed(axis_dialog)
- return axis_dialog
-
-
-def test_axis_dialog_with_axis_limits(qtbot, waveform_widget):
- waveform_widget.set(
- title="Test Title",
- x_label="X Label",
- y_label="Y Label",
- x_scale="linear",
- y_scale="log",
- x_lim=(0, 10),
- y_lim=(0, 10),
- )
-
- axis_dialog = show_axis_dialog(qtbot, waveform_widget)
-
- assert axis_dialog is not None
- assert axis_dialog.widget.ui.plot_title.text() == "Test Title"
- assert axis_dialog.widget.ui.x_label.text() == "X Label"
- assert axis_dialog.widget.ui.y_label.text() == "Y Label"
- assert axis_dialog.widget.ui.x_scale.currentText() == "linear"
- assert axis_dialog.widget.ui.y_scale.currentText() == "log"
- assert axis_dialog.widget.ui.x_min.value() == 0
- assert axis_dialog.widget.ui.x_max.value() == 10
- assert axis_dialog.widget.ui.y_min.value() == 0
- assert axis_dialog.widget.ui.y_max.value() == 10
-
-
-def test_axis_dialog_without_axis_limits(qtbot, waveform_widget):
- waveform_widget.set(
- title="Test Title", x_label="X Label", y_label="Y Label", x_scale="linear", y_scale="log"
- )
- x_range = waveform_widget.fig.widget_list[0].plot_item.viewRange()[0]
- y_range = waveform_widget.fig.widget_list[0].plot_item.viewRange()[1]
-
- axis_dialog = show_axis_dialog(qtbot, waveform_widget)
-
- assert axis_dialog is not None
- assert axis_dialog.widget.ui.plot_title.text() == "Test Title"
- assert axis_dialog.widget.ui.x_label.text() == "X Label"
- assert axis_dialog.widget.ui.y_label.text() == "Y Label"
- assert axis_dialog.widget.ui.x_scale.currentText() == "linear"
- assert axis_dialog.widget.ui.y_scale.currentText() == "log"
- assert axis_dialog.widget.ui.x_min.value() == x_range[0]
- assert axis_dialog.widget.ui.x_max.value() == x_range[1]
- assert axis_dialog.widget.ui.y_min.value() == y_range[0]
- assert axis_dialog.widget.ui.y_max.value() == y_range[1]
-
-
-def test_axis_dialog_set_properties(qtbot, waveform_widget):
- axis_dialog = show_axis_dialog(qtbot, waveform_widget)
-
- axis_dialog.widget.ui.plot_title.setText("New Title")
- axis_dialog.widget.ui.x_label.setText("New X Label")
- axis_dialog.widget.ui.y_label.setText("New Y Label")
- axis_dialog.widget.ui.x_scale.setCurrentText("log")
- axis_dialog.widget.ui.y_scale.setCurrentText("linear")
- axis_dialog.widget.ui.x_min.setValue(5)
- axis_dialog.widget.ui.x_max.setValue(15)
- axis_dialog.widget.ui.y_min.setValue(5)
- axis_dialog.widget.ui.y_max.setValue(15)
-
- axis_dialog.accept()
-
- assert waveform_widget._config_dict["axis"]["title"] == "New Title"
- assert waveform_widget._config_dict["axis"]["x_label"] == "New X Label"
- assert waveform_widget._config_dict["axis"]["y_label"] == "New Y Label"
- assert waveform_widget._config_dict["axis"]["x_scale"] == "log"
- assert waveform_widget._config_dict["axis"]["y_scale"] == "linear"
- assert waveform_widget._config_dict["axis"]["x_lim"] == (5, 15)
- assert waveform_widget._config_dict["axis"]["y_lim"] == (5, 15)
-
-
-def test_waveform_widget_theme_update(qtbot, waveform_widget):
- """Test theme update for waveform widget."""
- qapp = QApplication.instance()
-
- # Set the theme directly; equivalent to clicking the dark mode button
- # The background color should be black and the axis color should be white
- set_theme("dark")
- palette = get_theme_palette()
- waveform_color_dark = waveform_widget.waveform.plot_item.getAxis("left").pen().color()
- bg_color = waveform_widget.fig.backgroundBrush().color()
- assert bg_color == QColor(20, 20, 20)
- assert waveform_color_dark == palette.text().color()
-
- # Set the theme to light; equivalent to clicking the light mode button
- # The background color should be white and the axis color should be black
- set_theme("light")
- palette = get_theme_palette()
- waveform_color_light = waveform_widget.waveform.plot_item.getAxis("left").pen().color()
- bg_color = waveform_widget.fig.backgroundBrush().color()
- assert bg_color == QColor(233, 236, 239)
- assert waveform_color_light == palette.text().color()
-
- assert waveform_color_dark != waveform_color_light
-
- # Set the theme to auto; equivalent starting the application with no theme set
- set_theme("auto")
- # Simulate that the OS theme changes to dark
- qapp.theme_signal.theme_updated.emit("dark")
- apply_theme("dark")
-
- # The background color should be black and the axis color should be white
- # As we don't have access to the listener here, we can't test the palette change. Instead,
- # we compare the waveform color to the dark theme color
- waveform_color = waveform_widget.waveform.plot_item.getAxis("left").pen().color()
- bg_color = waveform_widget.fig.backgroundBrush().color()
- assert bg_color == QColor(20, 20, 20)
- assert waveform_color == waveform_color_dark
-
-
-def test_waveform_roi_selection_creation(waveform_widget, qtbot):
- """Test ROI selection for waveform widget.
-
- This checks that the ROI select is properly created and removed when the button is toggled.
- """
- # Check if curve is create upon ROI select slot
- # This also checks that the button in the toolbar works
- container = []
-
- def callback(msg):
- container.append(msg)
-
- waveform_widget.waveform.roi_active.connect(callback)
- assert waveform_widget.waveform.roi_select is None
- assert waveform_widget.waveform.roi_region == (None, None)
- # Toggle the ROI select
- waveform_widget.toogle_roi_select(True)
- assert isinstance(waveform_widget.waveform.roi_select, LinearRegionWrapper)
- # This is the default region for the pg.LinearRegionItem
- assert waveform_widget.waveform.roi_region == (0, 1)
- # Untoggle the ROI select
- waveform_widget.toogle_roi_select(False)
- assert waveform_widget.waveform.roi_select is None
- assert container[0] is True
- assert container[1] is False
-
-
-def test_waveform_roi_selection_updates_fit(waveform_widget, qtbot):
- """This test checks that upon selection of a new region, the fit is updated and all signals are emitted as expected."""
- container = []
-
- def callback(msg):
- container.append(msg)
-
- waveform_widget.waveform.roi_changed.connect(callback)
- # Mock refresh_dap method
- with patch.object(waveform_widget.waveform, "refresh_dap") as mock_refresh_dap:
- waveform_widget.toogle_roi_select(True)
- waveform_widget.waveform.roi_select.linear_region_selector.setRegion([0.5, 1.5])
- qtbot.wait(200)
- assert waveform_widget.waveform.roi_region == (0.5, 1.5)
- waveform_widget.toogle_roi_select(False)
- assert waveform_widget.waveform.roi_region == (None, None)
- assert len(container) == 1
- assert container[0] == (0.5, 1.5)
- # 3 refresh DAP calls: 1x upon hook, 1x unhook and 1x from roi_changed
- assert mock_refresh_dap.call_count == 3
-
-
-def test_waveform_roi_selection_change_color(waveform_widget, qtbot):
- """This test checks that the color of the ROI region can be changed."""
- waveform_widget.toogle_roi_select(True)
- waveform_widget.waveform.roi_select.change_roi_color((QColor("red"), QColor("blue")))
- # I can only get the brush from the RegionSelectItem
- assert (
- waveform_widget.waveform.roi_select.linear_region_selector.currentBrush.color()
- == QColor("red")
- )