From 03d172bade234d2d28d1017bd62ba93dc84ae7f6 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Mon, 18 Sep 2023 11:43:28 +0200 Subject: [PATCH] use Parameter when collecting fit values --- src/gui_qt/fit/fit_forms.py | 10 ++--- src/gui_qt/fit/fit_parameter.py | 67 ++++++++++++++++----------------- src/gui_qt/fit/fitwindow.py | 22 ++++++----- src/nmreval/fit/parameter.py | 15 +++++--- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/src/gui_qt/fit/fit_forms.py b/src/gui_qt/fit/fit_forms.py index 2d5f85c..13e225b 100644 --- a/src/gui_qt/fit/fit_forms.py +++ b/src/gui_qt/fit/fit_forms.py @@ -19,14 +19,16 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter): super().__init__(parent) self.setupUi(self) - self.parametername.setText(label + ' ') + self.name = label + + self.parametername.setText(convert(label) + ' ') self.parameter_line.setText('1') self.parameter_line.setMaximumWidth(160) self.lineEdit.setMaximumWidth(100) self.lineEdit_2.setMaximumWidth(100) - self.label_3.setText(f'< {label} <') + self.label_3.setText(f'< {convert(label)} <') self.checkBox.stateChanged.connect(self.enableBounds) self.global_checkbox.stateChanged.connect(lambda: self.state_changed.emit()) @@ -46,10 +48,6 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter): self.menu = QtWidgets.QMenu(self) - @property - def name(self): - return convert(self.parametername.text().strip(), old='html', new='str') - def set_parameter_string(self, p: str): self.parameter_line.setText(p) self.parameter_line.setToolTip(p) diff --git a/src/gui_qt/fit/fit_parameter.py b/src/gui_qt/fit/fit_parameter.py index f4894f0..47b6ae0 100644 --- a/src/gui_qt/fit/fit_parameter.py +++ b/src/gui_qt/fit/fit_parameter.py @@ -1,5 +1,8 @@ from __future__ import annotations +from typing import Optional + +from nmreval.fit.parameter import Parameter from nmreval.utils.text import convert from ..Qt import QtWidgets, QtCore, QtGui @@ -62,8 +65,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit): self.glob_values = [1] * len(func.params) for k, v in enumerate(func.params): - name = convert(v) - widgt = FitModelWidget(label=name, parent=self.scrollwidget) + widgt = FitModelWidget(label=v, parent=self.scrollwidget) widgt.parameter_pos = k widgt.func_idx = idx try: @@ -83,7 +85,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit): self.global_parameter.append(widgt) self.scrollwidget.layout().addWidget(widgt) - widgt2 = ParameterSingleWidget(name=name, parent=self.scrollwidget2) + widgt2 = ParameterSingleWidget(name=v, parent=self.scrollwidget2) widgt2.valueChanged.connect(self.change_single_parameter) widgt2.removeSingleValue.connect(self.change_single_parameter) widgt2.installEventFilter(self) @@ -206,62 +208,51 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit): if sid not in self.data_values: self.data_values[sid] = [None] * len(self.data_parameter) - def get_parameter(self, use_func=None): + def get_parameter(self, use_func=None) -> tuple[dict[str, list[Parameter]], list[Optional[Parameter]]]: bds = [] is_global = [] is_fixed = [] - globs = [] + + param_general = [] for g in self.global_parameter: if isinstance(g, FitModelWidget): p_i, bds_i, fixed_i, global_i = g.get_parameter() + parameter_i = Parameter(name=g.name, value=p_i, lb=bds_i[0], ub=bds_i[1], var=fixed_i) + param_general.append(parameter_i) - globs.append(p_i) bds.append(bds_i) is_fixed.append(fixed_i) is_global.append(global_i) - lb, ub = list(zip(*bds)) - data_parameter = {} if use_func is None: use_func = list(self.data_values.keys()) - global_p = None for sid, parameter in self.data_values.items(): if sid not in use_func: continue kw_p = {} p = [] - if global_p is None: - global_p = {'value': [], 'idx': [], 'var': [], 'ub': [], 'lb': []} for i, (p_i, g) in enumerate(zip(parameter, self.global_parameter)): if isinstance(g, FitModelWidget): - if (p_i is None) or is_global[i]: - p.append(globs[i]) - if is_global[i]: - if i not in global_p['idx']: - global_p['value'].append(globs[i]) - global_p['idx'].append(i) - global_p['var'].append(is_fixed[i]) - global_p['ub'].append(ub[i]) - global_p['lb'].append(lb[i]) + if p_i is None: + # set has no oen value + p.append(param_general[i].copy()) else: - p.append(p_i) + lb, ub = bds[i] + try: + if not (lb < p[i] < ub): + raise ValueError(f'Parameter {g.name} is outside bounds ({lb}, {ub})') + except TypeError: + pass - try: - if p[i] > ub[i]: - raise ValueError(f'Parameter {g.name} is outside bounds ({lb[i]}, {ub[i]})') - except TypeError: - pass - - try: - if p[i] < lb[i]: - raise ValueError(f'Parameter {g.name} is outside bounds ({lb[i]}, {ub[i]})') - except TypeError: - pass + # create Parameter + p.append( + Parameter(name=g.name, value=p_i, lb=lb, ub=ub, var=is_fixed[i]) + ) else: if p_i is None: @@ -271,9 +262,17 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit): else: kw_p[g.argname] = p_i + global_parameter = [] + for param, global_flag in zip(param_general, is_global): + if global_flag: + global_parameter.append(param) + else: + global_parameter.append(None) + + data_parameter[sid] = (p, kw_p) - return data_parameter, lb, ub, is_fixed, global_p + return data_parameter, global_parameter def set_parameter(self, set_id: str | None, parameter: list[float]) -> int: num_parameter = list(filter(lambda g: not isinstance(g, SelectionWidget), self.global_parameter)) @@ -304,7 +303,7 @@ class ParameterSingleWidget(QtWidgets.QWidget): self._init_ui() - self._name = name + self.name = name self.label.setText(convert(name)) self.label.setToolTip('If this is bold then this parameter is only for this data. ' 'Otherwise, the general parameter is used and displayed') diff --git a/src/gui_qt/fit/fitwindow.py b/src/gui_qt/fit/fitwindow.py index d0b88be..e3b708f 100644 --- a/src/gui_qt/fit/fitwindow.py +++ b/src/gui_qt/fit/fitwindow.py @@ -220,27 +220,31 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog): def _prepare(self, model: list, function_use: list = None, parameter: dict = None, add_idx: bool = False, cnt: int = 0) -> tuple[dict, int]: if parameter is None: - parameter = {'parameter': {}, 'lb': (), 'ub': (), 'var': [], - 'glob': {'idx': [], 'value': [], 'var': [], 'lb': [], 'ub': []}, - 'links': [], 'color': []} + parameter = { + 'parameter': {}, + 'glob': [], + 'links': [], + 'color': [], + } for i, f in enumerate(model): + print(i, f) if not f['active']: continue try: - p, lb, ub, var, glob = self.param_widgets[f['cnt']].get_parameter(function_use) + p, glob = self.param_widgets[f['cnt']].get_parameter(function_use) except ValueError as e: _ = QtWidgets.QMessageBox().warning(self, 'Invalid value', str(e), QtWidgets.QMessageBox.Ok) return {}, -1 - p_len = len(parameter['lb']) + print(p) + print(glob) + p_len = len(p) + parameter['color'].append(f['color']) - parameter['lb'] += lb - parameter['ub'] += ub - parameter['var'] += var - parameter['color'] += [f['color']] + print(parameter) cnt = f['cnt'] diff --git a/src/nmreval/fit/parameter.py b/src/nmreval/fit/parameter.py index 6d5457e..bc79daa 100644 --- a/src/nmreval/fit/parameter.py +++ b/src/nmreval/fit/parameter.py @@ -190,20 +190,23 @@ class Parameter: self._value = value * self.scale @property - def value(self) -> float: + def value(self) -> float | None: # TODO first _value, then _expr + if self._value is not None: + return self._value + if self._expr is not None and self.eval_allowed: return eval(self._expr, {}, self.namespace) - elif self._value is not None: - return self._value + + return @property def scaled_error(self) -> None | float: - if self.error is None: - return self.error - else: + if self.error is not None: return self.error / self.scale + return + @scaled_error.setter def scaled_error(self, value) -> None: self.error = value * self.scale