1
0
forked from IPKM/nmreval

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)
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)

View File

@ -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')

View File

@ -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']

View File

@ -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