0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 11:41:49 +02:00

fix(waveform): colormaps of curves can be changed and normalised

feat(waveform): colormap can be changed from curve dialog

fix(curve_dialog): default dialog parameters fixed

curve Dialog colormap WIP
This commit is contained in:
2024-07-14 23:19:40 +02:00
parent 8ac35d7280
commit 33495cfe03
5 changed files with 291 additions and 259 deletions

View File

@ -49,8 +49,9 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
"d0": self.d0, "d0": self.d0,
"d1": self.d1, "d1": self.d1,
"d2": self.d2, "d2": self.d2,
"plt": self.plt, "wave": self.wave,
"bar": self.bar, "bar": self.bar,
"cm": self.colormap,
} }
) )
@ -165,12 +166,16 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
self.fig1.plot(x_name="samx", y_name="bpm3a") self.fig1.plot(x_name="samx", y_name="bpm3a")
self.d2 = self.dock.add_dock(name="dock_2", position="bottom") self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
self.fig2 = self.d2.add_widget("BECFigure", row=0, col=0) self.wave = self.d2.add_widget("BECWaveformWidget", row=0, col=0)
self.plt = self.fig2.plot(x_name="samx", y_name="bpm3a") # self.wave.plot(x_name="samx", y_name="bpm3a")
self.plt.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel") # self.wave.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
self.bar = self.d2.add_widget("RingProgressBar", row=0, col=1) self.bar = self.d2.add_widget("RingProgressBar", row=0, col=1)
self.bar.set_diameter(200) self.bar.set_diameter(200)
self.d3 = self.dock.add_dock(name="dock_3", position="bottom")
self.colormap = pg.GradientWidget()
self.d3.add_widget(self.colormap, row=0, col=0)
self.dock.save_state() self.dock.save_state()
def closeEvent(self, event): def closeEvent(self, event):

View File

@ -10,7 +10,7 @@ import pyqtgraph as pg
from bec_lib import messages from bec_lib import messages
from bec_lib.device import ReadoutPriority from bec_lib.device import ReadoutPriority
from bec_lib.endpoints import MessageEndpoints from bec_lib.endpoints import MessageEndpoints
from pydantic import Field, ValidationError from pydantic import Field, ValidationError, field_validator
from qtpy.QtCore import Signal as pyqtSignal from qtpy.QtCore import Signal as pyqtSignal
from qtpy.QtCore import Slot as pyqtSlot from qtpy.QtCore import Slot as pyqtSlot
from qtpy.QtWidgets import QWidget from qtpy.QtWidgets import QWidget
@ -26,13 +26,16 @@ from bec_widgets.widgets.figure.plots.waveform.waveform_curve import (
class Waveform1DConfig(SubplotConfig): class Waveform1DConfig(SubplotConfig):
color_palette: Literal["plasma", "viridis", "inferno", "magma"] = Field( color_palette: Optional[str] = Field(
"plasma", description="The color palette of the figure widget." "plasma", description="The color palette of the figure widget.", validate_default=True
) )
curves: dict[str, CurveConfig] = Field( curves: dict[str, CurveConfig] = Field(
{}, description="The list of curves to be added to the 1D waveform widget." {}, description="The list of curves to be added to the 1D waveform widget."
) )
model_config: dict = {"validate_assignment": True}
_validate_color_map_z = field_validator("color_palette")(Colors.validate_color_map)
class BECWaveform(BECPlotBase): class BECWaveform(BECPlotBase):
READOUT_PRIORITY_HANDLER = { READOUT_PRIORITY_HANDLER = {
@ -63,6 +66,7 @@ class BECWaveform(BECPlotBase):
"set_x_lim", "set_x_lim",
"set_y_lim", "set_y_lim",
"set_grid", "set_grid",
"set_colormap",
"lock_aspect_ratio", "lock_aspect_ratio",
"remove", "remove",
"clear_all", "clear_all",
@ -954,6 +958,22 @@ class BECWaveform(BECPlotBase):
current_label = "" if self.config.axis.x_label is None else self.config.axis.x_label current_label = "" if self.config.axis.x_label is None else self.config.axis.x_label
self.plot_item.setLabel("bottom", f"{current_label}{self._x_axis_mode['label_suffix']}") self.plot_item.setLabel("bottom", f"{current_label}{self._x_axis_mode['label_suffix']}")
def set_colormap(self, colormap: str | None = None):
"""
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.
"""
if colormap is not None:
self.config.color_palette = colormap
colors = Colors.golden_angle_color(
colormap=self.config.color_palette, num=len(self.plot_item.curves) + 1, format="HEX"
)
for curve, color in zip(self.curves, colors):
curve.set_color(color)
def setup_dap(self, old_scan_id: str | None, new_scan_id: str | None): def setup_dap(self, old_scan_id: str | None, new_scan_id: str | None):
""" """
Setup DAP for the new scan. Setup DAP for the new scan.
@ -1214,49 +1234,6 @@ class BECWaveform(BECPlotBase):
x_data = [] x_data = []
return x_data return x_data
# def _get_x_data(self, curve: BECCurve, y_name: str, y_entry: str) -> list | np.ndarray | None:
# """
# Get the x data for the curve with the decision logic based on the curve configuration:
# - If x is called 'timestamp', use the timestamp data from the scan item.
# - If x is called 'index', use the rolling index.
# - If x is a custom signal, use the data from the scan item.
# - If x is not specified, use the first device from the scan report.
#
# Args:
# curve(BECCurve): The curve object.
#
# Returns:
# list|np.ndarray|None: X data for the curve.
# """
# x_data = None
# if curve.config.signals.x is not None:
# if curve.config.signals.x.name == "timestamp":
# timestamps = self.scan_item.data[y_name][y_entry].timestamps
# x_data = self.convert_timestamps(timestamps)
# elif curve.config.signals.x.name == "index":
# x_data = None
# else:
# x_name = curve.config.signals.x.name
# x_entry = curve.config.signals.x.entry
# try:
# x_data = self.scan_item.data[x_name][x_entry].val
# except TypeError:
# x_data = []
# else:
# if len(self._curves_data["async"]) > 0:
# x_data = None
# else:
# x_name = self.scan_item.status_message.info["scan_report_devices"][0]
# x_entry = self.entry_validator.validate_signal(x_name, None)
# x_data = self.scan_item.data[x_name][x_entry].val
# self._x_axis_mode["label_suffix"] = f" [auto: {x_name}-{x_entry}]"
# current_label = "" if self.config.axis.x_label is None else self.config.axis.x_label
# self.plot_item.setLabel(
# "bottom", f"{current_label}{self._x_axis_mode['label_suffix']}"
# )
#
# return x_data
def _make_z_gradient(self, data_z: list | np.ndarray, colormap: str) -> list | None: def _make_z_gradient(self, data_z: list | np.ndarray, colormap: str) -> list | None:
""" """
Make a gradient color for the z values. Make a gradient color for the z values.

View File

@ -10,7 +10,7 @@ from qtpy.QtCore import Slot
from qtpy.QtWidgets import QVBoxLayout from qtpy.QtWidgets import QVBoxLayout
from bec_widgets.qt_utils.settings_dialog import SettingWidget from bec_widgets.qt_utils.settings_dialog import SettingWidget
from bec_widgets.utils import UILoader from bec_widgets.utils import UILoader, Colors
from bec_widgets.widgets.color_button.color_button import ColorButton from bec_widgets.widgets.color_button.color_button import ColorButton
from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
from bec_widgets.widgets.figure.plots.plot_base import AxisConfig from bec_widgets.widgets.figure.plots.plot_base import AxisConfig
@ -30,6 +30,7 @@ class CurveSettings(SettingWidget):
self.ui.add_curve.clicked.connect(self.add_curve) self.ui.add_curve.clicked.connect(self.add_curve)
self.ui.x_mode.currentIndexChanged.connect(self.set_x_mode) self.ui.x_mode.currentIndexChanged.connect(self.set_x_mode)
self.ui.normalize_colors.clicked.connect(self.change_colormap)
@Slot(dict) @Slot(dict)
def display_current_settings(self, config: dict | BaseModel): def display_current_settings(self, config: dict | BaseModel):
@ -39,6 +40,8 @@ class CurveSettings(SettingWidget):
x_name = self.target_widget.waveform._x_axis_mode["name"] x_name = self.target_widget.waveform._x_axis_mode["name"]
x_entry = self.target_widget.waveform._x_axis_mode["entry"] x_entry = self.target_widget.waveform._x_axis_mode["entry"]
self._setup_x_box(x_name, x_entry) self._setup_x_box(x_name, x_entry)
cm = self.target_widget.config.color_palette
self.ui.color_map_selector.combo.setCurrentText(cm)
for label, curve in curves.items(): for label, curve in curves.items():
row_count = self.ui.scan_table.rowCount() row_count = self.ui.scan_table.rowCount()
@ -65,6 +68,15 @@ class CurveSettings(SettingWidget):
self.ui.x_name.setEnabled(True) self.ui.x_name.setEnabled(True)
self.ui.x_entry.setEnabled(True) self.ui.x_entry.setEnabled(True)
@Slot()
def change_colormap(self):
cm = self.ui.color_map_selector.combo.currentText()
rows = self.ui.scan_table.rowCount()
colors = Colors.golden_angle_color(colormap=cm, num=rows + 1, format="HEX")
for row, color in zip(range(rows), colors):
self.ui.scan_table.cellWidget(row, 2).setColor(color)
self.target_widget.set_colormap(cm)
@Slot() @Slot()
def accept_changes(self): def accept_changes(self):
self.accept_scan_curve_changes() self.accept_scan_curve_changes()
@ -131,15 +143,19 @@ class ScanRow(QObject):
self.entry_line_edit = QLineEdit() self.entry_line_edit = QLineEdit()
# Styling # Styling
default_color = Colors.golden_angle_color(colormap="magma", num=row + 1, format="HEX")[-1]
self.color_button = ColorButton() self.color_button = ColorButton()
self.color_button.setColor(default_color)
self.style_combo = StyleComboBox() self.style_combo = StyleComboBox()
self.width = QSpinBox() self.width = QSpinBox()
self.width.setMinimum(1) self.width.setMinimum(1)
self.width.setMaximum(20) self.width.setMaximum(20)
self.width.setValue(2)
self.symbol_size = QSpinBox() self.symbol_size = QSpinBox()
self.symbol_size.setMinimum(1) self.symbol_size.setMinimum(1)
self.symbol_size.setMaximum(20) self.symbol_size.setMaximum(20)
self.symbol_size.setValue(5)
self.table_widget = table_widget self.table_widget = table_widget
self.row = row self.row = row

View File

@ -6,92 +6,92 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>720</width> <width>720</width>
<height>806</height> <height>806</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin"> <property name="leftMargin">
<number>2</number> <number>2</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>2</number> <number>2</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>2</number> <number>2</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>2</number> <number>2</number>
</property> </property>
<item> <item>
<widget class="QGroupBox" name="x_group_box"> <widget class="QGroupBox" name="x_group_box">
<property name="title"> <property name="title">
<string>X Axis</string> <string>X Axis</string>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,3,0,1,3"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,3,0,1,3">
<item> <item>
<widget class="QLabel" name="x_mode_label"> <widget class="QLabel" name="x_mode_label">
<property name="text"> <property name="text">
<string>X Axis Mode</string> <string>X Axis Mode</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="x_mode"> <widget class="QComboBox" name="x_mode">
<item> <item>
<property name="text"> <property name="text">
<string>best_effort</string> <string>best_effort</string>
</property> </property>
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>device</string> <string>device</string>
</property> </property>
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>index</string> <string>index</string>
</property> </property>
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>timestamp</string> <string>timestamp</string>
</property> </property>
</item> </item>
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_3"> <spacer name="horizontalSpacer_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Orientation::Horizontal</enum> <enum>Qt::Orientation::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>40</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="Line" name="line_2"> <widget class="Line" name="line_2">
<property name="frameShadow"> <property name="frameShadow">
<enum>QFrame::Shadow::Sunken</enum> <enum>QFrame::Shadow::Sunken</enum>
</property> </property>
<property name="lineWidth"> <property name="lineWidth">
<number>1</number> <number>1</number>
</property> </property>
<property name="midLineWidth"> <property name="midLineWidth">
<number>0</number> <number>0</number>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Orientation::Vertical</enum> <enum>Qt::Orientation::Vertical</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="x_name_label"> <widget class="QLabel" name="x_name_label">
<property name="text"> <property name="text">
@ -157,6 +157,78 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="3">
<widget class="ColormapSelector" name="color_map_selector">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="colormaps" stdset="0">
<stringlist>
<string>inferno</string>
<string>viridis</string>
<string>plasma</string>
<string>magma</string>
</stringlist>
</property>
</widget>
</item>
<item row="1" column="0" colspan="6">
<widget class="QTableWidget" name="scan_table">
<property name="rowCount">
<number>0</number>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Entry</string>
</property>
</column>
<column>
<property name="text">
<string>Color</string>
</property>
</column>
<column>
<property name="text">
<string>Style</string>
</property>
</column>
<column>
<property name="text">
<string>Width</string>
</property>
</column>
<column>
<property name="text">
<string>Symbol Size</string>
</property>
</column>
<column>
<property name="text">
<string>Delete</string>
</property>
</column>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
@ -170,23 +242,60 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="2">
<widget class="QPushButton" name="normalize_colors">
<property name="text">
<string>Normalize Colors</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_DAP">
<attribute name="title">
<string>DAP</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QPushButton" name="add_dap">
<property name="text">
<string>Add DAP</string>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>585</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QTableWidget" name="scan_table"> <widget class="QTableWidget" name="dap_table">
<property name="rowCount"> <attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<number>0</number> <bool>true</bool>
</property> </attribute>
<attribute name="horizontalHeaderCascadingSectionResizes"> <attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool> <bool>true</bool>
</attribute> </attribute>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<column> <column>
<property name="text"> <property name="text">
<string>Name</string> <string>Name</string>
@ -197,129 +306,40 @@
<string>Entry</string> <string>Entry</string>
</property> </property>
</column> </column>
<column> <column>
<property name="text"> <property name="text">
<string>Color</string> <string>Model</string>
</property> </property>
</column> </column>
<column> <column>
<property name="text"> <property name="text">
<string>Style</string> <string>Color</string>
</property> </property>
</column> </column>
<column> <column>
<property name="text"> <property name="text">
<string>Width</string> <string>Style</string>
</property> </property>
</column> </column>
<column> <column>
<property name="text"> <property name="text">
<string>Symbol Size</string> <string>Width</string>
</property> </property>
</column> </column>
<column> <column>
<property name="text"> <property name="text">
<string>Delete</string> <string>Symbol Size</string>
</property>
</column>
<column>
<property name="text">
<string>Delete</string>
</property> </property>
</column> </column>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_DAP">
<attribute name="title">
<string>DAP</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QPushButton" name="add_dap">
<property name="text">
<string>Add DAP</string>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>585</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTableWidget" name="dap_table">
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Entry</string>
</property>
</column>
<column>
<property name="text">
<string>Model</string>
</property>
</column>
<column>
<property name="text">
<string>Color</string>
</property>
</column>
<column>
<property name="text">
<string>Style</string>
</property>
</column>
<column>
<property name="text">
<string>Width</string>
</property>
</column>
<column>
<property name="text">
<string>Symbol Size</string>
</property>
</column>
<column>
<property name="text">
<string>Delete</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_custom">
<attribute name="title">
<string>Custom</string>
</attribute>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -333,6 +353,11 @@
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
<header>device_line_edit</header> <header>device_line_edit</header>
</customwidget> </customwidget>
<customwidget>
<class>ColormapSelector</class>
<extends>QWidget</extends>
<header>color_map_selector</header>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -175,6 +175,15 @@ class BECWaveformWidget(BECConnector, QWidget):
""" """
return self.waveform.get_curve(identifier) 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)
def set_x(self, x_name: str, x_entry: str | None = None): def set_x(self, x_name: str, x_entry: str | None = None):
""" """
Change the x axis of the plot widget. Change the x axis of the plot widget.