1
0
forked from IPKM/nmreval

Merge branch 'fit_constraints'

# Conflicts:
#	src/gui_qt/main/management.py
This commit is contained in:
Dominik Demuth
2023-09-19 12:39:32 +02:00
18 changed files with 574 additions and 619 deletions

View File

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'resources/_ui/fitmodelwidget.ui'
# Form implementation generated from reading ui file 'src/resources/_ui/fitmodelwidget.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -13,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_FitParameter(object):
def setupUi(self, FitParameter):
FitParameter.setObjectName("FitParameter")
FitParameter.resize(365, 78)
FitParameter.resize(365, 66)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@ -36,7 +37,7 @@ class Ui_FitParameter(object):
self.parametername.setObjectName("parametername")
self.horizontalLayout_2.addWidget(self.parametername)
self.parameter_line = LineEdit(FitParameter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.parameter_line.sizePolicy().hasHeightForWidth())
@ -44,20 +45,12 @@ class Ui_FitParameter(object):
self.parameter_line.setText("")
self.parameter_line.setObjectName("parameter_line")
self.horizontalLayout_2.addWidget(self.parameter_line)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.fixed_check = QtWidgets.QCheckBox(FitParameter)
self.fixed_check.setObjectName("fixed_check")
self.horizontalLayout_2.addWidget(self.fixed_check)
self.global_checkbox = QtWidgets.QCheckBox(FitParameter)
self.global_checkbox.setObjectName("global_checkbox")
self.horizontalLayout_2.addWidget(self.global_checkbox)
self.toolButton = QtWidgets.QToolButton(FitParameter)
self.toolButton.setText("")
self.toolButton.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.toolButton.setArrowType(QtCore.Qt.RightArrow)
self.toolButton.setObjectName("toolButton")
self.horizontalLayout_2.addWidget(self.toolButton)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.frame = QtWidgets.QFrame(FitParameter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)

View File

@ -8,6 +8,7 @@ from pyqtgraph import mkPen
from nmreval.data.points import Points
from nmreval.data.signals import Signal
from nmreval.lib.logger import logger
from nmreval.utils.text import convert
from nmreval.data.bds import BDS
from nmreval.data.dsc import DSC
@ -356,7 +357,7 @@ class ExperimentContainer(QtCore.QObject):
elif mode in ['imag', 'all'] and self.plot_imag is not None:
self.plot_imag.set_symbol(symbol=symbol, size=size, color=color)
else:
print('Updating symbol failed for ' + str(self.id))
logger.warning(f'Updating symbol failed for {self.id}')
def setLine(self, *, width=None, style=None, color=None, mode='real'):
if mode in ['real', 'all']:
@ -368,7 +369,7 @@ class ExperimentContainer(QtCore.QObject):
elif mode in ['imag', 'all'] and self.plot_imag is not None:
self.plot_imag.set_line(width=width, style=style, color=color)
else:
print('Updating line failed for ' + str(self.id))
logger.warning(f'Updating line failed for {self.id}')
def update_property(self, key1: str, key2: str, value: Any):
keykey = key2.split()

View File

@ -1,3 +1,4 @@
from nmreval.lib.logger import logger
from nmreval.math import apodization
from nmreval.lib.importer import find_models
from nmreval.utils.text import convert
@ -67,7 +68,7 @@ class EditSignalWidget(QtWidgets.QWidget, Ui_Form):
self.do_something.emit(sender, (ph0, ph1, pvt))
else:
print('You should never reach this by accident.')
logger.warning(f'You should never reach this by accident, invalid sender {sender!r}')
@QtCore.pyqtSlot(int, name='on_apodcombobox_currentIndexChanged')
def change_apodization(self, index):

View File

@ -19,19 +19,20 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter):
super().__init__(parent)
self.setupUi(self)
self.parametername.setText(label + ' ')
self.name = label
self.parametername.setText(convert(label) + ' ')
validator = QtGui.QDoubleValidator()
self.parameter_line.setValidator(validator)
self.parameter_line.setText('1')
self.parameter_line.setMaximumWidth(240)
self.lineEdit.setMaximumWidth(60)
self.lineEdit_2.setMaximumWidth(60)
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())
self.parameter_line.editingFinished.connect(self.update_parameter)
self.parameter_line.values_requested.connect(lambda: self.value_requested.emit(self))
self.parameter_line.replace_single_values.connect(lambda: self.replace_single_value.emit(None))
self.parameter_line.editingFinished.connect(lambda: self.value_changed.emit(self.parameter_line.text()))
@ -40,18 +41,12 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter):
if fixed:
self.fixed_check.hide()
self.menu = QtWidgets.QMenu(self)
self.add_links()
self.is_linked = None
self.parameter_pos = None
self.func_idx = None
self._linetext = '1'
@property
def name(self):
return convert(self.parametername.text().strip(), old='html', new='str')
self.menu = QtWidgets.QMenu(self)
def set_parameter_string(self, p: str):
self.parameter_line.setText(p)
@ -71,38 +66,24 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter):
def set_parameter(self, p: float | None, bds: tuple[float, float, bool] = None,
fixed: bool = None, glob: bool = None):
if p is None:
# bad hack: linked parameter return (None, linked parameter)
# if p is None -> parameter is linked to argument given by bds
self.link_parameter(linkto=bds)
else:
ptext = f'{p:.4g}'
ptext = f'{p:.4g}'
self.set_parameter_string(ptext)
self.set_parameter_string(ptext)
if bds is not None:
self.set_bounds(*bds)
if bds is not None:
self.set_bounds(*bds)
if fixed is not None:
self.fixed_check.setCheckState(QtCore.Qt.Unchecked if fixed else QtCore.Qt.Checked)
if fixed is not None:
self.fixed_check.setCheckState(QtCore.Qt.Unchecked if fixed else QtCore.Qt.Checked)
if glob is not None:
self.global_checkbox.setCheckState(QtCore.Qt.Checked if glob else QtCore.Qt.Unchecked)
if glob is not None:
self.global_checkbox.setCheckState(QtCore.Qt.Checked if glob else QtCore.Qt.Unchecked)
def get_parameter(self):
if self.is_linked:
try:
p = float(self._linetext)
except ValueError:
p = 1.0
else:
try:
p = float(self.parameter_line.text().replace(',', '.'))
except ValueError:
_ = QtWidgets.QMessageBox().warning(self, 'Invalid value',
f'{self.parametername.text()} contains invalid values',
QtWidgets.QMessageBox.Cancel)
return None
try:
p = float(self.parameter_line.text().replace(',', '.'))
except ValueError:
p = self.parameter_line.text().replace(',', '.')
if self.checkBox.isChecked():
try:
@ -119,75 +100,27 @@ class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter):
bounds = (lb, rb)
return p, bounds, not self.fixed_check.isChecked(), self.global_checkbox.isChecked(), self.is_linked
return p, bounds, not self.fixed_check.isChecked(), self.global_checkbox.isChecked()
@QtCore.pyqtSlot(bool)
def set_fixed(self, state: bool):
# self.global_checkbox.setVisible(not state)
self.frame.setVisible(not state)
def add_links(self, parameter: dict = None):
if parameter is None:
parameter = {}
self.menu.clear()
ac = QtWidgets.QAction('Link to...', self)
ac.triggered.connect(self.link_parameter)
self.menu.addAction(ac)
for model_key, model_funcs in parameter.items():
m = QtWidgets.QMenu('Model ' + model_key, self)
for func_name, func_params in model_funcs.items():
m2 = QtWidgets.QMenu(func_name, m)
for p_name, idx in func_params:
ac = QtWidgets.QAction(p_name, m2)
ac.setData((model_key, *idx))
ac.triggered.connect(self.link_parameter)
m2.addAction(ac)
m.addMenu(m2)
self.menu.addMenu(m)
self.toolButton.setMenu(self.menu)
@QtCore.pyqtSlot()
def link_parameter(self, linkto=None):
if linkto is None:
action = self.sender()
else:
action = False
for m in self.menu.actions():
if m.menu():
for a in m.menu().actions():
if a.data() == linkto:
action = a
break
if action:
break
if (self.func_idx, self.parameter_pos) == action.data():
return
def update_parameter(self):
new_value = self.parameter_line.text()
if not new_value:
self.parameter_line.setText('1')
try:
new_text = f'Linked to {action.parentWidget().title()}.{action.text()}'
self._linetext = self.parameter_line.text()
self.parameter_line.setText(new_text)
self.parameter_line.setEnabled(False)
self.global_checkbox.hide()
self.global_checkbox.blockSignals(True)
self.global_checkbox.setCheckState(QtCore.Qt.Checked)
self.global_checkbox.blockSignals(False)
self.frame.hide()
self.is_linked = action.data()
float(new_value)
is_text = False
except ValueError:
is_text = True
self.global_checkbox.setCheckState(False)
except AttributeError:
self.parameter_line.setText(self._linetext)
self.parameter_line.setEnabled(True)
if self.fixed_check.isEnabled():
self.global_checkbox.show()
self.frame.show()
self.is_linked = None
self.state_changed.emit()
self.set_fixed(is_text)
class QSaveModelDialog(QtWidgets.QDialog, Ui_SaveDialog):
@ -282,8 +215,17 @@ class FitModelTree(QtWidgets.QTreeWidget):
idx = item.data(0, self.counterRole)
self.itemRemoved.emit(idx)
def add_function(self, idx: int, cnt: int, op: int, name: str, color: QtGui.QColor | str | tuple,
parent: QtWidgets.QTreeWidgetItem = None, children: list = None, active: bool = True, **kwargs):
def add_function(self,
idx: int,
cnt: int,
op: int,
name: str,
color: QtGui.QColor | str | tuple,
parent: QtWidgets.QTreeWidgetItem = None,
children: list = None,
active: bool = True,
param_names: list[str] = None,
**kwargs):
"""
Add function to tree and dictionary of functions.
"""
@ -298,6 +240,10 @@ class FitModelTree(QtWidgets.QTreeWidget):
it.setData(0, self.counterRole, cnt)
it.setData(0, self.operatorRole, op)
it.setText(0, name)
if param_names is not None:
it.setToolTip(0,
'Parameter names:\n' +
'\n'.join(f'{pn}({cnt})' for pn in param_names))
it.setForeground(0, QtGui.QBrush(color))
it.setIcon(0, get_icon(self.icons[op]))

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)
@ -115,20 +117,22 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
self.scrollwidget.layout().addStretch(1)
self.scrollwidget2.layout().addStretch(1)
def set_links(self, parameter):
for w in self.global_parameter:
if isinstance(w, FitModelWidget):
w.add_links(parameter)
# def set_links(self, parameter):
# for w in self.global_parameter:
# if isinstance(w, FitModelWidget):
# w.add_links(parameter)
@QtCore.pyqtSlot(str)
def change_global_parameter(self, value: str, idx: int = None):
if idx is None:
idx = self.global_parameter.index(self.sender())
self.glob_values[idx] = float(value)
# self.glob_values[idx] = float(value)
self.glob_values[idx] = value
if self.data_values[self.comboBox.currentData()][idx] is None:
self.data_parameter[idx].blockSignals(True)
self.data_parameter[idx].value = float(value)
# self.data_parameter[idx].value = float(value)
self.data_parameter[idx].value = value
self.data_parameter[idx].blockSignals(False)
@QtCore.pyqtSlot(str, object)
@ -171,7 +175,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
# disable single parameter if it is set global, enable if global is unset
widget = self.sender()
idx = self.global_parameter.index(widget)
enable = (widget.global_checkbox.checkState() == QtCore.Qt.Unchecked) and (widget.is_linked is None)
enable = (widget.global_checkbox.checkState() == QtCore.Qt.Unchecked)
self.data_parameter[idx].setEnabled(enable)
def select_next_preview(self, direction):
@ -204,64 +208,50 @@ 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, list]:
bds = []
is_global = []
is_fixed = []
globs = []
is_linked = []
param_general = []
for g in self.global_parameter:
if isinstance(g, FitModelWidget):
p_i, bds_i, fixed_i, global_i, link_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)
is_fixed.append(fixed_i)
is_global.append(global_i)
is_linked.append(link_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 = {'p': [], '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['p'].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])
# 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:
@ -273,7 +263,15 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
data_parameter[sid] = (p, kw_p)
return data_parameter, lb, ub, is_fixed, global_p, is_linked
global_parameter = []
for param, global_flag in zip(param_general, is_global):
if global_flag:
param.is_global = True
global_parameter.append(param)
else:
global_parameter.append(None)
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,12 +302,12 @@ 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')
self.value_line.setValidator(QtGui.QDoubleValidator())
# self.value_line.setValidator(QtGui.QDoubleValidator())
self.value_line.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0)
self.reset_button.clicked.connect(lambda x: self.removeSingleValue.emit())
@ -343,9 +341,10 @@ class ParameterSingleWidget(QtWidgets.QWidget):
@value.setter
def value(self, val):
self.value_line.setText(f'{float(val):.5g}')
# self.value_line.setText(f'{float(val):.5g}')
self.value_line.setText(f'{val}')
def show_as_local_parameter(self, is_local):
def show_as_local_parameter(self, is_local: bool):
if is_local:
self.label.setStyleSheet('font-weight: bold;')
else:

View File

@ -128,7 +128,7 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
self.newFunction.emit(idx, cnt)
self.add_function(idx, cnt, op, name, col)
self.add_function(idx, cnt, op, name, col, param_names=self.functions[idx].params)
def add_function(self, idx: int, cnt: int, op: int,
name: str, color: str | tuple[float, float, float] | BaseColor, **kwargs):
@ -141,6 +141,7 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
qcolor = QtGui.QColor.fromRgbF(*color)
else:
qcolor = QtGui.QColor(color)
self.functree.add_function(idx, cnt, op, name, qcolor, **kwargs)
f = self.functions[idx]

View File

@ -9,6 +9,9 @@ import numpy as np
from pyqtgraph import mkPen
from nmreval.fit._meta import MultiModel, ModelFactory
from nmreval.fit.data import Data
from nmreval.fit.model import Model
from nmreval.fit.parameter import Parameters
from nmreval.fit.result import FitResult
from .fit_forms import FitTableWidget
@ -116,7 +119,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
# collect parameter names etc. to allow linkage
self._func_list[self._current_model] = self.functionwidget.get_parameter_list()
dialog.set_links(self._func_list)
# dialog.set_links(self._func_list)
# show same tab (general parameter/Data parameter)
tab_idx = 0
@ -219,57 +222,49 @@ 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': [], 'p': [], 'var': [], 'lb': [], 'ub': []},
'links': [], 'color': []}
parameter = {
'data_parameter': {},
'global_parameter': [],
'links': [],
'color': [],
}
for i, f in enumerate(model):
if not f['active']:
continue
try:
p, lb, ub, var, glob, links = 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'])
parameter['lb'] += lb
parameter['ub'] += ub
parameter['var'] += var
parameter['links'] += links
parameter['color'] += [f['color']]
parameter['color'].append(f['color'])
parameter['global_parameter'].extend(glob)
cnt = f['cnt']
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]
if p_k in parameter['parameter']:
params, kw = parameter['parameter'][p_k]
if p_k in parameter['data_parameter']:
params, kw = parameter['data_parameter'][p_k]
params += v_k[0]
kw.update(kw_k)
else:
parameter['parameter'][p_k] = (v_k[0], kw_k)
for g_k, g_v in glob.items():
if g_k != 'idx':
parameter['glob'][g_k] += g_v
else:
parameter['glob']['idx'] += [idx_i + p_len for idx_i in g_v]
parameter['data_parameter'][p_k] = (v_k[0], kw_k)
if add_idx:
cnt += 1
if f['children']:
# recurse for children
child_parameter, cnt = self._prepare(f['children'], parameter=parameter, add_idx=add_idx, cnt=cnt)
_, cnt = self._prepare(f['children'], parameter=parameter, add_idx=add_idx, cnt=cnt)
return parameter, cnt
@ -280,30 +275,43 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
data = self.data_table.collect_data(default=self.default_combobox.currentData())
func_dict = {}
for k, mod in self.models.items():
func, order, param_len = ModelFactory.create_from_list(mod)
for model_name, model_parameter in self.models.items():
func, order, param_len = ModelFactory.create_from_list(model_parameter)
if func is None:
continue
if k in data:
parameter, _ = self._prepare(mod, function_use=data[k], add_idx=isinstance(func, MultiModel))
func = Model(func)
if model_name in data:
parameter, _ = self._prepare(model_parameter, function_use=data[model_name], add_idx=isinstance(func, MultiModel))
if parameter is None:
return
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)
parameter['func'] = func
parameter['order'] = order
parameter['len'] = param_len
parameter['complex'] = self._complex[k]
if self._complex[k] is not None:
for p_k, p_v in parameter['parameter'].items():
p_v[1].update({'complex_mode': self._complex[k]})
parameter['parameter'][p_k] = p_v[0], p_v[1]
parameter['complex'] = self._complex[model_name]
func_dict[k] = parameter
func_dict[model_name] = parameter
replaceable = []
for k, v in func_dict.items():
for model_name, v in func_dict.items():
for i, link_i in enumerate(v['links']):
if link_i is None:
continue
@ -334,7 +342,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
QtWidgets.QMessageBox.Ok)
return
replaceable.append((k, i, rep_model, repl_idx))
replaceable.append((model_name, i, rep_model, repl_idx))
replace_value = None
for p_k in f['parameter'].values():
@ -412,31 +420,37 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
def make_previews(self, x, models_parameters: dict):
self.preview_lines = []
# needed to create namespace
param_dict = Parameters()
cnt = 0
for model in models_parameters.values():
f = model['func']
for parameter_list in model['data_parameter'].values():
for i, p_value in enumerate(parameter_list[0]):
p_value.name = f.params[i]
param_dict.add_parameter(f'a{cnt}', p_value)
cnt += 1
for k, model in models_parameters.items():
f = model['func']
is_complex = self._complex[k]
parameters = model['parameter']
parameters = model['data_parameter']
color = model['color']
seen_parameter = []
for p, kwargs in parameters.values():
if (p, kwargs) in seen_parameter:
# plot only previews with different parameter
continue
seen_parameter.append((p, kwargs))
p_value = [pp.value for pp in p]
if is_complex is not None:
y = f.func(x, *p, complex_mode=is_complex, **kwargs)
y = f.func(x, *p_value, 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)
y = f.func(x, *p_value, **kwargs)
self.preview_lines.append(PlotItem(x=x, y=y, pen=mkPen(width=3)))
if isinstance(f, MultiModel):
@ -444,7 +458,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
if is_complex is not None:
sub_kwargs.update({'complex_mode': is_complex})
for i, s in enumerate(f.subs(x, *p, **sub_kwargs)):
for i, s in enumerate(f.subs(x, *p_value, **sub_kwargs)):
pen_i = mkPen(QtGui.QColor.fromRgbF(*color[i]))
if np.iscomplexobj(s):
self.preview_lines.append(PlotItem(x=x, y=s.real, pen=pen_i))
@ -452,15 +466,17 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
else:
self.preview_lines.append(PlotItem(x=x, y=s, pen=pen_i))
param_dict.clear()
return self.preview_lines
def set_parameter(self, parameter: dict[str, FitResult]):
# which data uses which model
data = self.data_table.collect_data(default=self.default_combobox.currentData())
glob_fit_parameter = []
for fitted_model, fitted_data in data.items():
glob_fit_parameter = []
for fit_id, fit_curve in parameter.items():
if fit_id in fitted_data:
fit_parameter = list(fit_curve.parameter.values())

View File

@ -138,9 +138,7 @@ class DrawingsWidget(QtWidgets.QWidget, Ui_Form):
graph_id = self.graph_comboBox.currentData()
current_lines = self.lines[graph_id]
print(remove_rows)
for i in reversed(remove_rows):
print(i)
self.tableWidget.removeRow(i)
self.line_deleted.emit(current_lines[i], graph_id)

View File

@ -27,7 +27,6 @@ class MdiAreaTile(QtWidgets.QMdiArea):
pos = QtCore.QPoint(0, 0)
for win in window_list:
print(win.minimumSize())
win.setGeometry(rect)
win.move(pos)

View File

@ -1,110 +0,0 @@
import os.path
import json
import urllib.request
import webbrowser
import random
from ..Qt import QtGui, QtCore, QtWidgets
from .._py.pokemon import Ui_Dialog
random.seed()
class QPokemon(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, number=None, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self._js = json.load(open(os.path.join(path_to_module, 'utils', 'pokemon.json'), 'r'), encoding='UTF-8')
self._id = 0
if number is not None and number in range(1, len(self._js)+1):
poke_nr = f'{number:03d}'
self._id = number
else:
poke_nr = f'{random.randint(1, len(self._js)):03d}'
self._id = int(poke_nr)
self._pokemon = None
self.show_pokemon(poke_nr)
self.label_15.linkActivated.connect(lambda x: webbrowser.open(x))
self.buttonBox.clicked.connect(self.randomize)
self.next_button.clicked.connect(self.show_next)
self.prev_button.clicked.connect(self.show_prev)
def show_pokemon(self, nr):
self._pokemon = self._js[nr]
self.setWindowTitle('Pokémon: ' + self._pokemon['Deutsch'])
for i in range(self.tabWidget.count(), -1, -1):
print('i', self.tabWidget.count(), i)
try:
self.tabWidget.widget(i).deleteLater()
except AttributeError:
pass
for n, img in self._pokemon['Bilder']:
w = QtWidgets.QWidget()
vl = QtWidgets.QVBoxLayout()
l = QtWidgets.QLabel(self)
l.setAlignment(QtCore.Qt.AlignHCenter)
pixmap = QtGui.QPixmap()
try:
pixmap.loadFromData(urllib.request.urlopen(img, timeout=0.5).read())
except IOError:
l.setText(n)
else:
sc_pixmap = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio)
l.setPixmap(sc_pixmap)
vl.addWidget(l)
w.setLayout(vl)
self.tabWidget.addTab(w, n)
if len(self._pokemon['Bilder']) <= 1:
self.tabWidget.tabBar().setVisible(False)
else:
self.tabWidget.tabBar().setVisible(True)
self.tabWidget.adjustSize()
self.name.clear()
keys = ['National-Dex', 'Kategorie', 'Typ', 'Größe', 'Gewicht', 'Farbe', 'Link']
label_list = [self.pokedex_nr, self.category, self.poketype, self.weight, self.height, self.color, self.info]
for (k, label) in zip(keys, label_list):
v = self._pokemon[k]
if isinstance(v, list):
v = os.path.join('', *v)
if k == 'Link':
v = '<a href={}>{}</a>'.format(v, v)
label.setText(v)
for k in ['Deutsch', 'Japanisch', 'Englisch', 'Französisch']:
v = self._pokemon[k]
self.name.addItem(k + ': ' + v)
self.adjustSize()
def randomize(self, idd):
if idd.text() == 'Retry':
new_number = f'{random.randint(1, len(self._js)):03d}'
self._id = int(new_number)
self.show_pokemon(new_number)
else:
self.close()
def show_next(self):
new_number = self._id + 1
if new_number > len(self._js):
new_number = 1
self._id = new_number
self.show_pokemon(f'{new_number:03d}')
def show_prev(self):
new_number = self._id - 1
if new_number == 0:
new_number = len(self._js)
self._id = new_number
self.show_pokemon(f'{new_number:03d}')

View File

@ -441,7 +441,7 @@ class UpperManagement(QtCore.QObject):
# all-encompassing error catch
try:
for model_id, model_p in parameter.items():
m = Model(model_p['func'])
m = model_p['func']
models[model_id] = m
m_complex = model_p['complex']
@ -450,13 +450,16 @@ class UpperManagement(QtCore.QObject):
# iterate over order of set id in active order and access parameter inside loop
# instead of directly looping
try:
list_ids = list(model_p['parameter'].keys())
list_ids = list(model_p['data_parameter'].keys())
set_order = [self.active_id.index(i) for i in list_ids]
except ValueError as e:
raise Exception('Getting order failed') from e
for pos in set_order:
set_id = list_ids[pos]
data_i = self.data[set_id]
set_params = model_p['data_parameter'][set_id]
try:
data_i = self.data[set_id]
except KeyError as e:
@ -488,7 +491,7 @@ class UpperManagement(QtCore.QObject):
inside = np.where((_x >= x_lim[0]) & (_x <= x_lim[1]))
else:
inside = np.where((_x >= fit_limits[0]) & (_x <= fit_limits[1]))
try:
if isinstance(we, str):
d = fit_d.Data(_x[inside], _y[inside], we=we, idx=set_id)
@ -499,18 +502,12 @@ class UpperManagement(QtCore.QObject):
d.set_model(m)
try:
d.set_parameter(set_params[0], var=model_p['var'],
lb=model_p['lb'], ub=model_p['ub'],
fun_kwargs=set_params[1])
d.set_parameter(set_params[0], fun_kwargs=set_params[1])
except Exception as e:
raise Exception('Setting parameter failed') from e
self.fitter.add_data(d)
model_globs = model_p['glob']
if model_globs:
m.set_global_parameter(**model_p['glob'])
for links_i in links:
self.fitter.set_link_parameter((models[links_i[0]], links_i[1]),
(models[links_i[2]], links_i[3]))
@ -1170,7 +1167,6 @@ class UpperManagement(QtCore.QObject):
@QtCore.pyqtSlot(dict)
def calc_relaxation(self, opts: dict):
params = opts['pts']
if len(params) == 4:
if params[3]: