mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
feat(waveform_widget): dap parameter window
This commit is contained in:
3
bec_widgets/assets/toolbar_icons/fitting_parameters.svg
Normal file
3
bec_widgets/assets/toolbar_icons/fitting_parameters.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||||
|
<path d="m78.89-112.59 263.02-367.17h202l303.5-354.22v721.39H78.89Zm62.24-262.74-54.7-39.78 166.59-233.02h201L640.46-864.8l51.45 44.26-205.82 240.78H287.33l-146.2 204.43Zm70.54 194.37h567.37v-468.78L574.98-411.63H376.22L211.67-180.96Zm567.37 0Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 366 B |
@ -75,6 +75,7 @@ class BECWaveform(BECPlotBase):
|
|||||||
scan_signal_update = pyqtSignal()
|
scan_signal_update = pyqtSignal()
|
||||||
async_signal_update = pyqtSignal()
|
async_signal_update = pyqtSignal()
|
||||||
dap_params_update = pyqtSignal(dict)
|
dap_params_update = pyqtSignal(dict)
|
||||||
|
dap_summary_update = pyqtSignal(dict)
|
||||||
autorange_signal = pyqtSignal()
|
autorange_signal = pyqtSignal()
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -655,6 +656,19 @@ class BECWaveform(BECPlotBase):
|
|||||||
params[curve_id] = curve.dap_params
|
params[curve_id] = curve.dap_params
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def get_dap_summary(self) -> dict:
|
||||||
|
"""
|
||||||
|
Get the DAP summary of all DAP curves.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: DAP summary of all DAP curves.
|
||||||
|
"""
|
||||||
|
summary = {}
|
||||||
|
for curve_id, curve in self._curves_data["DAP"].items():
|
||||||
|
summary[curve_id] = curve.dap_summary
|
||||||
|
return summary
|
||||||
|
|
||||||
def _add_curve_object(
|
def _add_curve_object(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
@ -1071,7 +1085,9 @@ class BECWaveform(BECPlotBase):
|
|||||||
y = msg["data"][0]["y"]
|
y = msg["data"][0]["y"]
|
||||||
curve.setData(x, y)
|
curve.setData(x, y)
|
||||||
curve.dap_params = msg["data"][1]["fit_parameters"]
|
curve.dap_params = msg["data"][1]["fit_parameters"]
|
||||||
|
curve.dap_summary = msg["data"][1]["fit_summary"]
|
||||||
self.dap_params_update.emit(curve.dap_params)
|
self.dap_params_update.emit(curve.dap_params)
|
||||||
|
self.dap_summary_update.emit(curve.dap_summary)
|
||||||
break
|
break
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
@pyqtSlot(dict, dict)
|
||||||
|
@ -101,6 +101,7 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|||||||
self.parent_item = parent_item
|
self.parent_item = parent_item
|
||||||
self.apply_config()
|
self.apply_config()
|
||||||
self.dap_params = None
|
self.dap_params = None
|
||||||
|
self.dap_summary = None
|
||||||
if kwargs:
|
if kwargs:
|
||||||
self.set(**kwargs)
|
self.set(**kwargs)
|
||||||
|
|
||||||
@ -132,6 +133,14 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|||||||
def dap_params(self, value):
|
def dap_params(self, value):
|
||||||
self._dap_params = value
|
self._dap_params = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dap_summary(self):
|
||||||
|
return self._dap_report
|
||||||
|
|
||||||
|
@dap_summary.setter
|
||||||
|
def dap_summary(self, value):
|
||||||
|
self._dap_report = value
|
||||||
|
|
||||||
def set_data(self, x, y):
|
def set_data(self, x, y):
|
||||||
if self.config.source == "custom":
|
if self.config.source == "custom":
|
||||||
self.setData(x, y)
|
self.setData(x, y)
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Shape::VLine</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Shadow::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="opaqueResize">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="childrenCollapsible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QGroupBox" name="group_curve_selection">
|
||||||
|
<property name="title">
|
||||||
|
<string>Select Curve</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="refresh_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Refresh DAP Summary</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="curve_list"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>2</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QGroupBox" name="group_summary">
|
||||||
|
<property name="title">
|
||||||
|
<string>Fit Summary</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="summary_tree">
|
||||||
|
<property name="uniformRowHeights">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Property</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Value</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QGroupBox" name="group_parameters">
|
||||||
|
<property name="title">
|
||||||
|
<string>Parameter Details</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="param_tree">
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Parameter</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Value</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Std</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -0,0 +1,69 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from qtpy.QtCore import Slot
|
||||||
|
from qtpy.QtWidgets import QDialog, QTreeWidgetItem, QVBoxLayout
|
||||||
|
|
||||||
|
from bec_widgets.utils import UILoader
|
||||||
|
|
||||||
|
|
||||||
|
class FitSummaryWidget(QDialog):
|
||||||
|
def __init__(self, parent=None, target_widget=None):
|
||||||
|
super().__init__(parent=parent)
|
||||||
|
|
||||||
|
self.target_widget = target_widget
|
||||||
|
self.summary_data = self.target_widget.get_dap_summary()
|
||||||
|
|
||||||
|
self.setModal(True)
|
||||||
|
|
||||||
|
current_path = os.path.dirname(__file__)
|
||||||
|
self.ui = UILoader(self).loader(os.path.join(current_path, "dap_summary.ui"))
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.layout.addWidget(self.ui)
|
||||||
|
|
||||||
|
self.ui.curve_list.currentItemChanged.connect(self.display_fit_details)
|
||||||
|
self.ui.refresh_button.clicked.connect(self.refresh_dap)
|
||||||
|
|
||||||
|
self.populate_curve_list()
|
||||||
|
|
||||||
|
def populate_curve_list(self):
|
||||||
|
for curve_name in self.summary_data.keys():
|
||||||
|
self.ui.curve_list.addItem(curve_name)
|
||||||
|
|
||||||
|
def display_fit_details(self, current):
|
||||||
|
if current:
|
||||||
|
curve_name = current.text()
|
||||||
|
data = self.summary_data[curve_name]
|
||||||
|
if data is None:
|
||||||
|
return
|
||||||
|
self.refresh_trees(data)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def refresh_dap(self):
|
||||||
|
self.ui.curve_list.clear()
|
||||||
|
self.summary_data = self.target_widget.get_dap_summary()
|
||||||
|
self.populate_curve_list()
|
||||||
|
|
||||||
|
def refresh_trees(self, data):
|
||||||
|
self.update_summary_tree(data)
|
||||||
|
self.update_param_tree(data["params"])
|
||||||
|
|
||||||
|
def update_summary_tree(self, data):
|
||||||
|
self.ui.summary_tree.clear()
|
||||||
|
properties = [
|
||||||
|
("Model", data.get("model", "")),
|
||||||
|
("Method", data.get("method", "")),
|
||||||
|
("Chi-Squared", str(data.get("chisqr", ""))),
|
||||||
|
("Reduced Chi-Squared", str(data.get("redchi", ""))),
|
||||||
|
("AIC", str(data.get("aic", ""))),
|
||||||
|
("BIC", str(data.get("bic", ""))),
|
||||||
|
("R-Squared", str(data.get("rsquared", ""))),
|
||||||
|
("Message", data.get("message", "")),
|
||||||
|
]
|
||||||
|
for prop, val in properties:
|
||||||
|
QTreeWidgetItem(self.ui.summary_tree, [prop, val])
|
||||||
|
|
||||||
|
def update_param_tree(self, params):
|
||||||
|
self.ui.param_tree.clear()
|
||||||
|
for param in params:
|
||||||
|
param_name, param_value, param_std = param[0], str(param[1]), str(param[7])
|
||||||
|
QTreeWidgetItem(self.ui.param_tree, [param_name, param_value, param_std])
|
@ -41,6 +41,17 @@ class CurveAction(ToolBarAction):
|
|||||||
toolbar.addAction(self.action)
|
toolbar.addAction(self.action)
|
||||||
|
|
||||||
|
|
||||||
|
class FitParamsAction(ToolBarAction):
|
||||||
|
def add_to_toolbar(self, toolbar, target):
|
||||||
|
icon = QIcon()
|
||||||
|
icon.addFile(
|
||||||
|
os.path.join(MODULE_PATH, "assets", "toolbar_icons", "fitting_parameters.svg"),
|
||||||
|
size=QSize(20, 20),
|
||||||
|
)
|
||||||
|
self.action = QAction(icon, "Open Fitting Parameters", target)
|
||||||
|
toolbar.addAction(self.action)
|
||||||
|
|
||||||
|
|
||||||
class SettingsAction(ToolBarAction):
|
class SettingsAction(ToolBarAction):
|
||||||
def add_to_toolbar(self, toolbar, target):
|
def add_to_toolbar(self, toolbar, target):
|
||||||
icon = QIcon()
|
icon = QIcon()
|
||||||
|
@ -6,7 +6,7 @@ from typing import Literal
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.qt_utils.error_popups import WarningPopupUtility, SafeSlot
|
from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
|
||||||
from bec_widgets.qt_utils.settings_dialog import SettingsDialog
|
from bec_widgets.qt_utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.qt_utils.toolbar import ModularToolBar, SeparatorAction
|
from bec_widgets.qt_utils.toolbar import ModularToolBar, SeparatorAction
|
||||||
from bec_widgets.utils import BECConnector
|
from bec_widgets.utils import BECConnector
|
||||||
@ -15,6 +15,9 @@ from bec_widgets.widgets.figure.plots.axis_settings import AxisSettings
|
|||||||
from bec_widgets.widgets.figure.plots.waveform.waveform import Waveform1DConfig
|
from bec_widgets.widgets.figure.plots.waveform.waveform import Waveform1DConfig
|
||||||
from bec_widgets.widgets.figure.plots.waveform.waveform_curve import BECCurve
|
from bec_widgets.widgets.figure.plots.waveform.waveform_curve import BECCurve
|
||||||
from bec_widgets.widgets.waveform.waveform_toolbar.curve_dialog.curve_dialog import CurveSettings
|
from bec_widgets.widgets.waveform.waveform_toolbar.curve_dialog.curve_dialog import CurveSettings
|
||||||
|
from bec_widgets.widgets.waveform.waveform_toolbar.dap_summary_dialog.dap_summary_dialog import (
|
||||||
|
FitSummaryWidget,
|
||||||
|
)
|
||||||
from bec_widgets.widgets.waveform.waveform_toolbar.waveform_toolbar import *
|
from bec_widgets.widgets.waveform.waveform_toolbar.waveform_toolbar import *
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -73,6 +76,7 @@ class BECWaveformWidget(BECConnector, QWidget):
|
|||||||
"matplotlib": MatplotlibAction(),
|
"matplotlib": MatplotlibAction(),
|
||||||
"separator_1": SeparatorAction(),
|
"separator_1": SeparatorAction(),
|
||||||
"curves": CurveAction(),
|
"curves": CurveAction(),
|
||||||
|
"fit_params": FitParamsAction(),
|
||||||
"axis_settings": SettingsAction(),
|
"axis_settings": SettingsAction(),
|
||||||
"separator_2": SeparatorAction(),
|
"separator_2": SeparatorAction(),
|
||||||
"import": ImportAction(),
|
"import": ImportAction(),
|
||||||
@ -95,13 +99,14 @@ class BECWaveformWidget(BECConnector, QWidget):
|
|||||||
|
|
||||||
# TEst actions
|
# TEst actions
|
||||||
self.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
|
self.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
|
||||||
self.plot(x_name="samx", y_name="bpm3a")
|
self.plot(x_name="samx", y_name="bpm3a", dap="GaussianModel")
|
||||||
self.plot(x_name="samx", y_name="bpm6i")
|
self.plot(x_name="samx", y_name="bpm6i")
|
||||||
|
|
||||||
def _hook_actions(self):
|
def _hook_actions(self):
|
||||||
self.toolbar.widgets["save"].action.triggered.connect(self.export)
|
self.toolbar.widgets["save"].action.triggered.connect(self.export)
|
||||||
self.toolbar.widgets["matplotlib"].action.triggered.connect(self.export_to_matplotlib)
|
self.toolbar.widgets["matplotlib"].action.triggered.connect(self.export_to_matplotlib)
|
||||||
self.toolbar.widgets["curves"].action.triggered.connect(self.show_curve_settings)
|
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["axis_settings"].action.triggered.connect(self.show_axis_settings)
|
||||||
self.toolbar.widgets["import"].action.triggered.connect(
|
self.toolbar.widgets["import"].action.triggered.connect(
|
||||||
lambda: self.load_config(path=None, gui=True)
|
lambda: self.load_config(path=None, gui=True)
|
||||||
@ -129,6 +134,11 @@ class BECWaveformWidget(BECConnector, QWidget):
|
|||||||
dialog.resize(800, 600)
|
dialog.resize(800, 600)
|
||||||
dialog.exec()
|
dialog.exec()
|
||||||
|
|
||||||
|
def show_fit_summary_dialog(self):
|
||||||
|
dialog = FitSummaryWidget(target_widget=self)
|
||||||
|
dialog.resize(800, 600)
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
def _check_if_scans_have_same_x(
|
def _check_if_scans_have_same_x(
|
||||||
self, enabled=True, x_name_to_check: str = None
|
self, enabled=True, x_name_to_check: str = None
|
||||||
) -> bool: # TODO probably not needed anymore
|
) -> bool: # TODO probably not needed anymore
|
||||||
@ -307,7 +317,16 @@ class BECWaveformWidget(BECConnector, QWidget):
|
|||||||
dict: DAP parameters of all DAP curves.
|
dict: DAP parameters of all DAP curves.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.waveform.get_dap_params()
|
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):
|
def remove_curve(self, *identifiers):
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user