use Parameter when collecting fit values

This commit is contained in:
Dominik Demuth 2023-09-18 11:43:28 +02:00
parent 3af5cb0301
commit 03d172bade
4 changed files with 59 additions and 55 deletions

View File

@ -19,14 +19,16 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter):
super().__init__(parent) super().__init__(parent)
self.setupUi(self) self.setupUi(self)
self.parametername.setText(label + ' ') self.name = label
self.parametername.setText(convert(label) + ' ')
self.parameter_line.setText('1') self.parameter_line.setText('1')
self.parameter_line.setMaximumWidth(160) self.parameter_line.setMaximumWidth(160)
self.lineEdit.setMaximumWidth(100) self.lineEdit.setMaximumWidth(100)
self.lineEdit_2.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.checkBox.stateChanged.connect(self.enableBounds)
self.global_checkbox.stateChanged.connect(lambda: self.state_changed.emit()) 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) 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): def set_parameter_string(self, p: str):
self.parameter_line.setText(p) self.parameter_line.setText(p)
self.parameter_line.setToolTip(p) self.parameter_line.setToolTip(p)

View File

@ -1,5 +1,8 @@
from __future__ import annotations from __future__ import annotations
from typing import Optional
from nmreval.fit.parameter import Parameter
from nmreval.utils.text import convert from nmreval.utils.text import convert
from ..Qt import QtWidgets, QtCore, QtGui from ..Qt import QtWidgets, QtCore, QtGui
@ -62,8 +65,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
self.glob_values = [1] * len(func.params) self.glob_values = [1] * len(func.params)
for k, v in enumerate(func.params): for k, v in enumerate(func.params):
name = convert(v) widgt = FitModelWidget(label=v, parent=self.scrollwidget)
widgt = FitModelWidget(label=name, parent=self.scrollwidget)
widgt.parameter_pos = k widgt.parameter_pos = k
widgt.func_idx = idx widgt.func_idx = idx
try: try:
@ -83,7 +85,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
self.global_parameter.append(widgt) self.global_parameter.append(widgt)
self.scrollwidget.layout().addWidget(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.valueChanged.connect(self.change_single_parameter)
widgt2.removeSingleValue.connect(self.change_single_parameter) widgt2.removeSingleValue.connect(self.change_single_parameter)
widgt2.installEventFilter(self) widgt2.installEventFilter(self)
@ -206,62 +208,51 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
if sid not in self.data_values: if sid not in self.data_values:
self.data_values[sid] = [None] * len(self.data_parameter) 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 = [] bds = []
is_global = [] is_global = []
is_fixed = [] is_fixed = []
globs = []
param_general = []
for g in self.global_parameter: for g in self.global_parameter:
if isinstance(g, FitModelWidget): if isinstance(g, FitModelWidget):
p_i, bds_i, fixed_i, global_i = g.get_parameter() 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) bds.append(bds_i)
is_fixed.append(fixed_i) is_fixed.append(fixed_i)
is_global.append(global_i) is_global.append(global_i)
lb, ub = list(zip(*bds))
data_parameter = {} data_parameter = {}
if use_func is None: if use_func is None:
use_func = list(self.data_values.keys()) use_func = list(self.data_values.keys())
global_p = None
for sid, parameter in self.data_values.items(): for sid, parameter in self.data_values.items():
if sid not in use_func: if sid not in use_func:
continue continue
kw_p = {} kw_p = {}
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)): for i, (p_i, g) in enumerate(zip(parameter, self.global_parameter)):
if isinstance(g, FitModelWidget): if isinstance(g, FitModelWidget):
if (p_i is None) or is_global[i]: if p_i is None:
p.append(globs[i]) # set has no oen value
if is_global[i]: p.append(param_general[i].copy())
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])
else: else:
p.append(p_i) lb, ub = bds[i]
try: try:
if p[i] > ub[i]: if not (lb < p[i] < ub):
raise ValueError(f'Parameter {g.name} is outside bounds ({lb[i]}, {ub[i]})') raise ValueError(f'Parameter {g.name} is outside bounds ({lb}, {ub})')
except TypeError: except TypeError:
pass pass
try: # create Parameter
if p[i] < lb[i]: p.append(
raise ValueError(f'Parameter {g.name} is outside bounds ({lb[i]}, {ub[i]})') Parameter(name=g.name, value=p_i, lb=lb, ub=ub, var=is_fixed[i])
except TypeError: )
pass
else: else:
if p_i is None: if p_i is None:
@ -271,9 +262,17 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
else: else:
kw_p[g.argname] = p_i 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) 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: 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)) 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._init_ui()
self._name = name self.name = name
self.label.setText(convert(name)) self.label.setText(convert(name))
self.label.setToolTip('If this is bold then this parameter is only for this data. ' self.label.setToolTip('If this is bold then this parameter is only for this data. '
'Otherwise, the general parameter is used and displayed') 'Otherwise, the general parameter is used and displayed')

View File

@ -220,27 +220,31 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
def _prepare(self, model: list, function_use: list = None, def _prepare(self, model: list, function_use: list = None,
parameter: dict = None, add_idx: bool = False, cnt: int = 0) -> tuple[dict, int]: parameter: dict = None, add_idx: bool = False, cnt: int = 0) -> tuple[dict, int]:
if parameter is None: if parameter is None:
parameter = {'parameter': {}, 'lb': (), 'ub': (), 'var': [], parameter = {
'glob': {'idx': [], 'value': [], 'var': [], 'lb': [], 'ub': []}, 'parameter': {},
'links': [], 'color': []} 'glob': [],
'links': [],
'color': [],
}
for i, f in enumerate(model): for i, f in enumerate(model):
print(i, f)
if not f['active']: if not f['active']:
continue continue
try: 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: except ValueError as e:
_ = QtWidgets.QMessageBox().warning(self, 'Invalid value', str(e), _ = QtWidgets.QMessageBox().warning(self, 'Invalid value', str(e),
QtWidgets.QMessageBox.Ok) QtWidgets.QMessageBox.Ok)
return {}, -1 return {}, -1
p_len = len(parameter['lb']) print(p)
print(glob)
p_len = len(p)
parameter['color'].append(f['color'])
parameter['lb'] += lb print(parameter)
parameter['ub'] += ub
parameter['var'] += var
parameter['color'] += [f['color']]
cnt = f['cnt'] cnt = f['cnt']

View File

@ -190,20 +190,23 @@ class Parameter:
self._value = value * self.scale self._value = value * self.scale
@property @property
def value(self) -> float: def value(self) -> float | None:
# TODO first _value, then _expr # TODO first _value, then _expr
if self._value is not None:
return self._value
if self._expr is not None and self.eval_allowed: if self._expr is not None and self.eval_allowed:
return eval(self._expr, {}, self.namespace) return eval(self._expr, {}, self.namespace)
elif self._value is not None:
return self._value return
@property @property
def scaled_error(self) -> None | float: def scaled_error(self) -> None | float:
if self.error is None: if self.error is not None:
return self.error
else:
return self.error / self.scale return self.error / self.scale
return
@scaled_error.setter @scaled_error.setter
def scaled_error(self, value) -> None: def scaled_error(self, value) -> None:
self.error = value * self.scale self.error = value * self.scale