2022-03-28 14:26:10 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from functools import reduce
|
2022-03-08 09:27:40 +00:00
|
|
|
from itertools import count, cycle
|
2022-03-28 14:26:10 +00:00
|
|
|
from operator import add
|
2022-03-08 09:27:40 +00:00
|
|
|
from string import ascii_letters
|
|
|
|
|
2022-03-30 15:27:02 +00:00
|
|
|
import numpy as np
|
2022-03-24 19:24:28 +00:00
|
|
|
from pyqtgraph import mkPen
|
2022-03-08 09:27:40 +00:00
|
|
|
|
2022-10-20 15:23:15 +00:00
|
|
|
from nmreval.fit._meta import MultiModel, ModelFactory
|
2023-09-18 11:52:10 +00:00
|
|
|
from nmreval.fit.model import Model
|
2022-10-20 15:23:15 +00:00
|
|
|
from nmreval.fit.result import FitResult
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
from .fit_forms import FitTableWidget
|
|
|
|
from .fit_parameter import QFitParameterWidget
|
2023-07-12 18:48:28 +00:00
|
|
|
from ..lib import Relations
|
2022-03-24 19:24:28 +00:00
|
|
|
from ..lib.pg_objects import PlotItem
|
|
|
|
from ..Qt import QtGui, QtCore, QtWidgets
|
|
|
|
from .._py.fitdialog import Ui_FitDialog
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
|
|
|
func_cnt = count()
|
|
|
|
model_cnt = cycle(ascii_letters)
|
|
|
|
preview_num = 201
|
|
|
|
|
|
|
|
preview_emit = QtCore.pyqtSignal(dict, int, bool)
|
|
|
|
fitStartSig = QtCore.pyqtSignal(dict, list, dict)
|
|
|
|
abortFit = QtCore.pyqtSignal()
|
|
|
|
|
|
|
|
def __init__(self, mgmt=None, parent=None):
|
|
|
|
super().__init__(parent=parent)
|
|
|
|
self.setupUi(self)
|
|
|
|
|
|
|
|
self.parameters = {}
|
|
|
|
self.preview_lines = []
|
|
|
|
self._current_function = None
|
2022-03-28 14:26:10 +00:00
|
|
|
self.param_widgets = {}
|
2022-03-08 09:27:40 +00:00
|
|
|
self._management = mgmt
|
|
|
|
|
|
|
|
self._current_model = next(QFitDialog.model_cnt)
|
|
|
|
self.show_combobox.setItemData(0, self._current_model, QtCore.Qt.UserRole)
|
|
|
|
self.default_combobox.setItemData(0, self._current_model, QtCore.Qt.UserRole)
|
|
|
|
|
|
|
|
self.data_table = FitTableWidget(self.data_widget)
|
|
|
|
self.data_widget.addWidget(self.data_table)
|
|
|
|
self.data_widget.setText('Data')
|
|
|
|
|
|
|
|
self.models = {}
|
|
|
|
self._func_list = {}
|
|
|
|
self._complex = {}
|
|
|
|
|
2023-05-03 17:04:25 +00:00
|
|
|
self.connected_figure = None
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
self.model_frame.hide()
|
|
|
|
self.preview_button.hide()
|
|
|
|
|
|
|
|
self.abort_button.clicked.connect(lambda: self.abortFit.emit())
|
|
|
|
|
|
|
|
self.functionwidget.newFunction.connect(self.add_function)
|
|
|
|
self.functionwidget.showFunction.connect(self.show_function_parameter)
|
|
|
|
self.functionwidget.itemRemoved.connect(self.remove_function)
|
|
|
|
|
2022-11-07 19:44:18 +00:00
|
|
|
self.read_and_load_functions = self.functionwidget.read_and_load_functions
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
@QtCore.pyqtSlot(int, int)
|
|
|
|
def add_function(self, function_idx: int, function_id: int):
|
|
|
|
self.show_function_parameter(function_id, function_idx)
|
|
|
|
self.newmodel_button.setEnabled(True)
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(int)
|
|
|
|
def remove_function(self, idx: int):
|
|
|
|
"""
|
|
|
|
Remove function and children from tree and dictionary
|
|
|
|
"""
|
2022-03-28 14:26:10 +00:00
|
|
|
w = self.param_widgets[idx]
|
2022-03-08 09:27:40 +00:00
|
|
|
self.stackedWidget.removeWidget(w)
|
|
|
|
w.deleteLater()
|
2022-03-28 14:26:10 +00:00
|
|
|
del self.param_widgets[idx]
|
2022-03-08 09:27:40 +00:00
|
|
|
|
2023-05-19 13:48:32 +00:00
|
|
|
self._current_function = None
|
|
|
|
if len(self.param_widgets) == 0:
|
2022-03-08 09:27:40 +00:00
|
|
|
# empty model
|
|
|
|
self.newmodel_button.setEnabled(False)
|
|
|
|
self.deletemodel_button.setEnabled(False)
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(int)
|
|
|
|
def show_function_parameter(self, function_id: int, function_idx: int = None):
|
|
|
|
"""
|
|
|
|
Display parameter associated with selected function.
|
|
|
|
"""
|
2022-03-28 14:26:10 +00:00
|
|
|
if function_id in self.param_widgets:
|
|
|
|
dialog = self.param_widgets[function_id]
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
else:
|
|
|
|
# create new widget for function
|
|
|
|
if function_idx is not None:
|
|
|
|
function = self.functionwidget.functions[function_idx]
|
|
|
|
else:
|
|
|
|
raise ValueError('No function index given')
|
|
|
|
|
|
|
|
if function is None:
|
|
|
|
return
|
|
|
|
|
2023-01-15 15:33:32 +00:00
|
|
|
dialog = QFitParameterWidget(self.stackedWidget)
|
2022-03-08 09:27:40 +00:00
|
|
|
data_names = self.data_table.data_list(include_name=True)
|
|
|
|
|
|
|
|
dialog.set_function(function, function_idx)
|
|
|
|
dialog.load(data_names)
|
|
|
|
dialog.value_requested.connect(self.look_value)
|
|
|
|
|
|
|
|
self.stackedWidget.addWidget(dialog)
|
2022-03-28 14:26:10 +00:00
|
|
|
self.param_widgets[function_id] = dialog
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
self.stackedWidget.setCurrentWidget(dialog)
|
|
|
|
|
|
|
|
# collect parameter names etc. to allow linkage
|
|
|
|
self._func_list[self._current_model] = self.functionwidget.get_parameter_list()
|
2023-09-11 16:09:08 +00:00
|
|
|
# dialog.set_links(self._func_list)
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
# show same tab (general parameter/Data parameter)
|
|
|
|
tab_idx = 0
|
|
|
|
if self._current_function is not None:
|
2022-03-28 14:26:10 +00:00
|
|
|
tab_idx = self.param_widgets[self._current_function].tabWidget.currentIndex()
|
2022-03-08 09:27:40 +00:00
|
|
|
dialog.tabWidget.setCurrentIndex(tab_idx)
|
|
|
|
|
|
|
|
self._current_function = function_id
|
|
|
|
|
2022-03-28 14:26:10 +00:00
|
|
|
def look_value(self, idx: int):
|
|
|
|
func_widget = self.param_widgets[self._current_function]
|
2022-03-08 09:27:40 +00:00
|
|
|
set_ids = [func_widget.comboBox.itemData(i) for i in range(func_widget.comboBox.count())]
|
|
|
|
for s in set_ids:
|
|
|
|
func_widget.data_values[s][idx] = self._management[s].value
|
|
|
|
func_widget.change_data(func_widget.comboBox.currentIndex())
|
|
|
|
|
|
|
|
def get_functions(self):
|
|
|
|
""" update functions, parameters"""
|
|
|
|
self.models[self._current_model] = self.functionwidget.get_functions()
|
|
|
|
self._complex[self._current_model] = self.functionwidget.get_complex_state()
|
|
|
|
self._func_list[self._current_model] = self.functionwidget.get_parameter_list()
|
|
|
|
|
2023-03-01 18:26:12 +00:00
|
|
|
def load(self, ids: list[str]):
|
2022-03-08 09:27:40 +00:00
|
|
|
"""
|
|
|
|
Add name and id of dataset to list.
|
|
|
|
"""
|
|
|
|
self.data_table.load(ids)
|
2023-04-12 15:28:12 +00:00
|
|
|
|
|
|
|
# deselect all fit sets
|
|
|
|
for i in range(self.data_table.rowCount()):
|
|
|
|
data_id = self.data_table.item(i, 0).data(QtCore.Qt.UserRole+1)
|
2023-07-12 18:48:28 +00:00
|
|
|
if self._management[data_id].mode == 'fit' or self._management[data_id].has_relation(Relations.isFitPartOf):
|
2023-04-12 15:28:12 +00:00
|
|
|
self.data_table.item(i, 0).setCheckState(QtCore.Qt.Unchecked)
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
if self.models:
|
|
|
|
for m in self.models.keys():
|
|
|
|
self.data_table.add_model(m)
|
|
|
|
else:
|
|
|
|
self.data_table.add_model(self._current_model)
|
|
|
|
|
2022-03-28 14:26:10 +00:00
|
|
|
for dialog in self.param_widgets.values():
|
2022-03-08 09:27:40 +00:00
|
|
|
dialog.load(ids)
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(name='on_newmodel_button_clicked')
|
|
|
|
def make_new_model(self):
|
|
|
|
"""
|
|
|
|
Save model with all its functions in dictionary and adjust gui.
|
|
|
|
"""
|
|
|
|
self.deletemodel_button.setEnabled(True)
|
|
|
|
self.model_frame.show()
|
|
|
|
idx = next(QFitDialog.model_cnt)
|
|
|
|
|
|
|
|
self.data_table.add_model(idx)
|
|
|
|
|
|
|
|
self.default_combobox.addItem('Model '+idx, userData=idx)
|
|
|
|
self.show_combobox.addItem('Model '+idx, userData=idx)
|
|
|
|
self.show_combobox.setItemData(self.show_combobox.count()-1, idx, QtCore.Qt.UserRole)
|
|
|
|
self.show_combobox.setCurrentIndex(self.show_combobox.count()-1)
|
|
|
|
|
|
|
|
self._current_model = idx
|
|
|
|
self.stackedWidget.setCurrentIndex(0)
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(int, name='on_show_combobox_currentIndexChanged')
|
|
|
|
def change_model(self, idx: int):
|
|
|
|
"""
|
|
|
|
Save old model and display new model.
|
|
|
|
"""
|
|
|
|
self.get_functions()
|
|
|
|
self.functionwidget.clear()
|
|
|
|
|
|
|
|
self._current_model = self.show_combobox.itemData(idx, QtCore.Qt.UserRole)
|
|
|
|
if self._current_model in self.models and len(self.models[self._current_model]):
|
|
|
|
for el in self.models[self._current_model]:
|
|
|
|
self.functionwidget.add_function(**el)
|
|
|
|
self.functionwidget.set_complex_state(self._complex[self._current_model])
|
|
|
|
else:
|
|
|
|
self.stackedWidget.setCurrentIndex(0)
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(name='on_deletemodel_button_clicked')
|
|
|
|
def remove_model(self):
|
|
|
|
model_id = self._current_model
|
|
|
|
|
|
|
|
self.show_combobox.removeItem(self.show_combobox.findData(model_id))
|
|
|
|
self.default_combobox.removeItem(self.default_combobox.findData(model_id))
|
|
|
|
|
|
|
|
for m in self.models[model_id]:
|
|
|
|
func_id = m['cnt']
|
2022-03-28 14:26:10 +00:00
|
|
|
self.stackedWidget.removeWidget(self.param_widgets[func_id])
|
2022-03-08 09:27:40 +00:00
|
|
|
|
2022-03-28 14:26:10 +00:00
|
|
|
self.param_widgets.pop(func_id)
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
self._complex.pop(model_id)
|
|
|
|
self._func_list.pop(model_id)
|
|
|
|
self.models.pop(model_id)
|
|
|
|
|
|
|
|
self.data_table.remove_model(model_id)
|
|
|
|
|
|
|
|
if len(self.models) == 1:
|
|
|
|
self.model_frame.hide()
|
|
|
|
|
2022-03-28 14:26:10 +00:00
|
|
|
def _prepare(self, model: list, function_use: list = None,
|
2023-03-01 18:26:12 +00:00
|
|
|
parameter: dict = None, add_idx: bool = False, cnt: int = 0) -> tuple[dict, int]:
|
2023-09-18 11:52:10 +00:00
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
if parameter is None:
|
2023-09-18 09:43:28 +00:00
|
|
|
parameter = {
|
2023-09-18 11:52:10 +00:00
|
|
|
'data_parameter': {},
|
|
|
|
'global_parameter': [],
|
2023-09-18 09:43:28 +00:00
|
|
|
'links': [],
|
|
|
|
'color': [],
|
|
|
|
}
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
for i, f in enumerate(model):
|
|
|
|
if not f['active']:
|
|
|
|
continue
|
2022-03-28 14:26:10 +00:00
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
try:
|
2023-09-18 09:43:28 +00:00
|
|
|
p, glob = self.param_widgets[f['cnt']].get_parameter(function_use)
|
2022-03-08 09:27:40 +00:00
|
|
|
except ValueError as e:
|
|
|
|
_ = QtWidgets.QMessageBox().warning(self, 'Invalid value', str(e),
|
|
|
|
QtWidgets.QMessageBox.Ok)
|
2022-03-28 14:26:10 +00:00
|
|
|
return {}, -1
|
2022-03-08 09:27:40 +00:00
|
|
|
|
2023-09-18 09:43:28 +00:00
|
|
|
parameter['color'].append(f['color'])
|
2023-09-18 11:52:10 +00:00
|
|
|
parameter['global_parameter'].extend(glob)
|
2022-03-08 09:27:40 +00:00
|
|
|
|
2023-03-01 18:26:12 +00:00
|
|
|
cnt = f['cnt']
|
2022-03-08 09:27:40 +00:00
|
|
|
for p_k, v_k in p.items():
|
|
|
|
if add_idx:
|
|
|
|
kw_k = {f'{k}_{cnt}': v for k, v in v_k[1].items()}
|
|
|
|
else:
|
|
|
|
kw_k = v_k[1]
|
|
|
|
|
2023-09-18 11:52:10 +00:00
|
|
|
if p_k in parameter['data_parameter']:
|
|
|
|
params, kw = parameter['data_parameter'][p_k]
|
2022-03-08 09:27:40 +00:00
|
|
|
params += v_k[0]
|
|
|
|
kw.update(kw_k)
|
|
|
|
else:
|
2023-09-18 11:52:10 +00:00
|
|
|
parameter['data_parameter'][p_k] = (v_k[0], kw_k)
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
if add_idx:
|
|
|
|
cnt += 1
|
|
|
|
|
|
|
|
if f['children']:
|
|
|
|
# recurse for children
|
2023-08-25 16:46:36 +00:00
|
|
|
_, cnt = self._prepare(f['children'], parameter=parameter, add_idx=add_idx, cnt=cnt)
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
return parameter, cnt
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(name='on_fit_button_clicked')
|
|
|
|
def start_fit(self):
|
|
|
|
self.get_functions()
|
|
|
|
|
|
|
|
data = self.data_table.collect_data(default=self.default_combobox.currentData())
|
|
|
|
|
|
|
|
func_dict = {}
|
2023-09-18 11:52:10 +00:00
|
|
|
for model_name, model_parameter in self.models.items():
|
|
|
|
func, order, param_len = ModelFactory.create_from_list(model_parameter)
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
if func is None:
|
|
|
|
continue
|
|
|
|
|
2023-09-18 11:52:10 +00:00
|
|
|
func = Model(func)
|
2023-08-25 16:46:36 +00:00
|
|
|
|
2023-09-18 11:52:10 +00:00
|
|
|
if model_name in data:
|
|
|
|
parameter, _ = self._prepare(model_parameter, function_use=data[model_name], add_idx=isinstance(func, MultiModel))
|
2023-08-25 16:46:36 +00:00
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
if parameter is None:
|
|
|
|
return
|
|
|
|
|
2023-09-18 11:52:10 +00:00
|
|
|
for (data_parameter, _) in parameter['data_parameter'].values():
|
|
|
|
for pname, param in zip(func.params, data_parameter):
|
|
|
|
param.name = pname
|
|
|
|
|
|
|
|
if self._complex[model_name] is not None:
|
|
|
|
for p_k, p_v in parameter['data_parameter'].items():
|
|
|
|
p_v[1].update({'complex_mode': self._complex[model_name]})
|
|
|
|
parameter['data_parameter'][p_k] = p_v[0], p_v[1]
|
|
|
|
|
|
|
|
for pname, param_value in zip(func.params, parameter['global_parameter']):
|
|
|
|
if param_value is not None:
|
|
|
|
param_value.name = pname
|
|
|
|
func.set_global_parameter(param_value)
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
parameter['func'] = func
|
|
|
|
parameter['order'] = order
|
|
|
|
parameter['len'] = param_len
|
2023-09-18 11:52:10 +00:00
|
|
|
parameter['complex'] = self._complex[model_name]
|
2022-03-08 09:27:40 +00:00
|
|
|
|
2023-09-18 11:52:10 +00:00
|
|
|
func_dict[model_name] = parameter
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
replaceable = []
|
2023-09-18 11:52:10 +00:00
|
|
|
for model_name, v in func_dict.items():
|
2022-03-08 09:27:40 +00:00
|
|
|
for i, link_i in enumerate(v['links']):
|
|
|
|
if link_i is None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
rep_model, rep_func, rep_pos = link_i
|
|
|
|
try:
|
|
|
|
f = func_dict[rep_model]
|
|
|
|
except KeyError:
|
|
|
|
QtWidgets.QMessageBox().warning(self, 'Invalid value',
|
|
|
|
'Parameter cannot be linked: Model is unused',
|
|
|
|
QtWidgets.QMessageBox.Ok)
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
f_idx = f['order'].index(rep_func)
|
|
|
|
except ValueError:
|
|
|
|
QtWidgets.QMessageBox().warning(self, 'Invalid value',
|
|
|
|
'Parameter cannot be linked: '
|
|
|
|
'Function is probably not checked or deleted',
|
|
|
|
QtWidgets.QMessageBox.Ok)
|
|
|
|
return
|
|
|
|
|
|
|
|
repl_idx = sum(f['len'][:f_idx])+rep_pos
|
|
|
|
if repl_idx not in f['glob']['idx']:
|
|
|
|
_ = QtWidgets.QMessageBox().warning(self, 'Invalid value',
|
|
|
|
'Parameter cannot be linked: '
|
|
|
|
'Destination is not a global parameter.',
|
|
|
|
QtWidgets.QMessageBox.Ok)
|
|
|
|
return
|
|
|
|
|
2023-09-18 11:52:10 +00:00
|
|
|
replaceable.append((model_name, i, rep_model, repl_idx))
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
replace_value = None
|
|
|
|
for p_k in f['parameter'].values():
|
|
|
|
replace_value = p_k[0][repl_idx]
|
|
|
|
break
|
|
|
|
|
|
|
|
if replace_value is not None:
|
|
|
|
for p_k in v['parameter'].values():
|
|
|
|
p_k[0][i] = replace_value
|
|
|
|
|
|
|
|
weight = ['None', 'y', 'y2', 'Deltay'][self.weight_combobox.currentIndex()]
|
|
|
|
|
|
|
|
fit_args = {'we': weight}
|
|
|
|
|
|
|
|
if func_dict:
|
|
|
|
self.fitStartSig.emit(func_dict, replaceable, fit_args)
|
|
|
|
|
|
|
|
return func_dict
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(int, name='on_preview_checkbox_stateChanged')
|
|
|
|
def show_preview(self, state: int):
|
|
|
|
if state:
|
|
|
|
self.preview_button.show()
|
|
|
|
self.preview_checkbox.setText('')
|
|
|
|
|
|
|
|
self._prepare_preview()
|
|
|
|
|
|
|
|
else:
|
|
|
|
self.preview_emit.emit({}, -1, False)
|
|
|
|
self.preview_lines = []
|
|
|
|
self.preview_button.hide()
|
|
|
|
self.preview_checkbox.setText('Preview')
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(name='on_preview_button_clicked')
|
|
|
|
def _prepare_preview(self):
|
|
|
|
self.get_functions()
|
|
|
|
|
|
|
|
default_model = self.default_combobox.currentData()
|
|
|
|
data = self.data_table.collect_data(default=default_model)
|
|
|
|
|
|
|
|
func_dict = {}
|
|
|
|
for k, mod in self.models.items():
|
|
|
|
func, order, param_len = ModelFactory.create_from_list(mod)
|
|
|
|
multiple_funcs = isinstance(func, MultiModel)
|
|
|
|
|
|
|
|
if k in data:
|
|
|
|
parameter, _ = self._prepare(mod, function_use=data[k], add_idx=multiple_funcs)
|
|
|
|
parameter['func'] = func
|
|
|
|
parameter['order'] = order
|
|
|
|
parameter['len'] = param_len
|
|
|
|
|
|
|
|
func_dict[k] = parameter
|
|
|
|
|
|
|
|
for v in func_dict.values():
|
|
|
|
for i, link_i in enumerate(v['links']):
|
|
|
|
if link_i is None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
rep_model, rep_func, rep_pos = link_i
|
|
|
|
f = func_dict[rep_model]
|
|
|
|
f_idx = f['order'].index(rep_func)
|
|
|
|
repl_idx = sum(f['len'][:f_idx]) + rep_pos
|
|
|
|
|
|
|
|
replace_value = None
|
|
|
|
for p_k in f['parameter'].values():
|
|
|
|
replace_value = p_k[0][repl_idx]
|
|
|
|
break
|
|
|
|
|
|
|
|
if replace_value is not None:
|
|
|
|
for p_k in v['parameter'].values():
|
|
|
|
p_k[0][i] = replace_value
|
|
|
|
|
|
|
|
self.preview_emit.emit(func_dict, QFitDialog.preview_num, True)
|
|
|
|
|
|
|
|
def make_previews(self, x, models_parameters: dict):
|
|
|
|
self.preview_lines = []
|
|
|
|
|
|
|
|
for k, model in models_parameters.items():
|
|
|
|
f = model['func']
|
|
|
|
is_complex = self._complex[k]
|
|
|
|
|
|
|
|
parameters = model['parameter']
|
|
|
|
color = model['color']
|
|
|
|
|
2022-10-30 17:45:43 +00:00
|
|
|
seen_parameter = []
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
for p, kwargs in parameters.values():
|
2022-10-30 17:45:43 +00:00
|
|
|
if (p, kwargs) in seen_parameter:
|
|
|
|
# plot only previews with different parameter
|
|
|
|
continue
|
|
|
|
|
|
|
|
seen_parameter.append((p, kwargs))
|
|
|
|
|
2022-03-30 15:27:02 +00:00
|
|
|
if is_complex is not None:
|
|
|
|
y = f.func(x, *p, complex_mode=is_complex, **kwargs)
|
|
|
|
if np.iscomplexobj(y):
|
|
|
|
self.preview_lines.append(PlotItem(x=x, y=y.real, pen=mkPen(width=3)))
|
|
|
|
self.preview_lines.append(PlotItem(x=x, y=y.imag, pen=mkPen(width=3)))
|
|
|
|
else:
|
|
|
|
self.preview_lines.append(PlotItem(x=x, y=y, pen=mkPen(width=3)))
|
|
|
|
else:
|
|
|
|
y = f.func(x, *p, **kwargs)
|
2022-03-08 09:27:40 +00:00
|
|
|
self.preview_lines.append(PlotItem(x=x, y=y, pen=mkPen(width=3)))
|
|
|
|
|
|
|
|
if isinstance(f, MultiModel):
|
2022-03-30 15:27:02 +00:00
|
|
|
sub_kwargs = kwargs.copy()
|
|
|
|
if is_complex is not None:
|
|
|
|
sub_kwargs.update({'complex_mode': is_complex})
|
|
|
|
|
|
|
|
for i, s in enumerate(f.subs(x, *p, **sub_kwargs)):
|
2022-03-08 09:27:40 +00:00
|
|
|
pen_i = mkPen(QtGui.QColor.fromRgbF(*color[i]))
|
2022-03-30 15:27:02 +00:00
|
|
|
if np.iscomplexobj(s):
|
2022-03-08 09:27:40 +00:00
|
|
|
self.preview_lines.append(PlotItem(x=x, y=s.real, pen=pen_i))
|
|
|
|
self.preview_lines.append(PlotItem(x=x, y=s.imag, pen=pen_i))
|
2022-03-30 15:27:02 +00:00
|
|
|
else:
|
|
|
|
self.preview_lines.append(PlotItem(x=x, y=s, pen=pen_i))
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
return self.preview_lines
|
|
|
|
|
2023-03-01 18:26:12 +00:00
|
|
|
def set_parameter(self, parameter: dict[str, FitResult]):
|
2022-03-28 14:26:10 +00:00
|
|
|
# which data uses which model
|
|
|
|
data = self.data_table.collect_data(default=self.default_combobox.currentData())
|
|
|
|
|
|
|
|
for fitted_model, fitted_data in data.items():
|
2023-09-03 18:17:07 +00:00
|
|
|
glob_fit_parameter = []
|
|
|
|
|
2022-03-28 14:26:10 +00:00
|
|
|
for fit_id, fit_curve in parameter.items():
|
|
|
|
if fit_id in fitted_data:
|
|
|
|
fit_parameter = list(fit_curve.parameter.values())
|
|
|
|
glob_fit_parameter.append(fit_parameter)
|
|
|
|
|
|
|
|
self.set_parameter_iter(fit_id, [p.value for p in fit_parameter], self.models[fitted_model])
|
|
|
|
|
2022-03-29 07:16:02 +00:00
|
|
|
mean_parameter = [reduce(add, p, 0)/len(p) for p in zip(*glob_fit_parameter)]
|
2022-03-28 14:26:10 +00:00
|
|
|
|
|
|
|
self.set_parameter_iter(None, mean_parameter, self.models[fitted_model])
|
|
|
|
|
2023-03-01 18:26:12 +00:00
|
|
|
def set_parameter_iter(self, fit_id: str | None, param: list[float], functions: list, cnt: int = 0):
|
2022-03-28 14:26:10 +00:00
|
|
|
for model_p in functions:
|
2022-07-28 18:20:49 +00:00
|
|
|
if model_p['active']:
|
|
|
|
cnt += self.param_widgets[model_p['cnt']].set_parameter(fit_id, param[cnt:])
|
|
|
|
if model_p['children']:
|
|
|
|
cnt += self.set_parameter_iter(fit_id, param, model_p['children'], cnt=cnt)
|
2022-03-28 14:26:10 +00:00
|
|
|
|
|
|
|
return cnt
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
def closeEvent(self, evt: QtGui.QCloseEvent):
|
|
|
|
self.preview_emit.emit({}, -1, False)
|
|
|
|
self.preview_lines = []
|
|
|
|
|
|
|
|
super().closeEvent(evt)
|