1
0
forked from IPKM/nmreval

extrapolate_fit (#21)

New sets with arbitrary x range can be created from fit results

Co-authored-by: Dominik Demuth <dominik.demuth@physik.tu-darmstadt.de>
Reviewed-on: IPKM/nmreval#21
This commit is contained in:
2023-03-12 19:37:10 +00:00
parent 1601f1455c
commit 28c15ff565
10 changed files with 393 additions and 169 deletions

View File

@ -11,10 +11,10 @@ from pyqtgraph import ViewBox
from nmreval.configs import *
from .management import UpperManagement
from ..Qt import QtCore, QtGui, QtPrintSupport, QtWidgets
from ..Qt import QtGui, QtPrintSupport
from ..data.shift_graphs import QShift
from ..data.signaledit import QApodDialog, QBaselineDialog, QPhasedialog
from ..fit.result import QFitResult
from ..fit.result import FitExtension, QFitResult
from ..graphs.graphwindow import QGraphWindow
from ..graphs.movedialog import QMover
from ..io.fcbatchreader import QFCReader
@ -164,6 +164,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.datawidget.startShowProperty.connect(self.management.get_properties)
self.datawidget.propertyChanged.connect(self.management.update_property)
self.datawidget.tree.saveFits.connect(self.save_fit_parameter)
self.datawidget.tree.extendFits.connect(self.extend_fit)
self.management.newData.connect(self.show_new_data)
self.management.newGraph.connect(self.new_graph)
@ -907,10 +908,10 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
res_dialog.redoFit.connect(self.management.redo_fits)
res_dialog.show()
@QtCore.pyqtSlot(dict, list, str, bool, dict)
def accepts_fit(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: dict) -> None:
@QtCore.pyqtSlot(dict, list, str, bool, bool, list)
def accepts_fit(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: bool, extrapolate: list) -> None:
self.fit_dialog.set_parameter(res)
self.management.make_fits(res, opts, param_graph, show_fit, parts)
self.management.make_fits(res, opts, param_graph, show_fit, parts, extrapolate)
@QtCore.pyqtSlot(name='on_actionFunction_editor_triggered')
def edit_models(self):
@ -922,6 +923,16 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.editor.setWindowModality(QtCore.Qt.ApplicationModal)
self.editor.show()
@QtCore.pyqtSlot(list)
def extend_fit(self, sets: list):
w = FitExtension(self)
res = w.exec()
print(res)
if res:
p = w.values
x = linspace(p[0], p[1], num=p[2])
self.management.extend_fits(sets, x)
@QtCore.pyqtSlot(name='on_action_create_fit_function_triggered')
def open_fitmodel_wizard(self):
from ..fit.function_creation_dialog import QUserFitCreator
@ -931,7 +942,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
helper.show()
@QtCore.pyqtSlot(name='on_actionShift_triggered')
def shift_dialog(self):
s = QShift(self)

View File

@ -4,6 +4,8 @@ import pathlib
import re
import uuid
import numpy as np
from nmreval.fit import data as fit_d
from nmreval.fit.model import Model
from nmreval.fit.result import FitResult
@ -482,7 +484,7 @@ class UpperManagement(QtCore.QObject):
parameter[set_id] = (new_values, set_parameter[1])
self.start_fit(*self.__fit_options)
def make_fits(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: dict) -> None:
def make_fits(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: bool, extrapolate: list) -> None:
"""
Args:
@ -491,6 +493,7 @@ class UpperManagement(QtCore.QObject):
param_graph: None if no parameter to plot, '' for new graph, or id of existig graph
show_fit: plot fit curve?
parts: key is that of original data, value is list of subplots
extrapolate:
"""
f_id_list = []
@ -503,6 +506,26 @@ class UpperManagement(QtCore.QObject):
if reject:
continue
if not all(e is None for e in extrapolate):
spacefunc = np.geomspace if fit.islog else np.linspace
xmin = fit.x.min()
xmax = fit.x.max()
len_data = len(fit.x_data)
num_pts = 20*len_data-9 if len_data < 51 else 3*len_data
if extrapolate[0] is not None:
xmin = extrapolate[0]
if extrapolate[1] is not None:
xmax = extrapolate[1]
if extrapolate[2] is not None:
num_pts = extrapolate[2]
_x = spacefunc(xmin, xmax, num=num_pts)
fit = fit.with_new_x(_x)
data_k = self.data[k]
if delete_prev:
tobedeleted.extend([f.id for f in data_k.get_fits()])
@ -527,18 +550,16 @@ class UpperManagement(QtCore.QObject):
f_id_list.append(f_id)
data_k.set_fits(f_id)
if parts:
color_scheme = available_cycles['colorblind']
for subfunc, col in zip(fit.sub(fit.x), cycle(color_scheme)):
subfunc.value = data_k.value
subfunc.group = data_k.group
subfunc.name += data_name
sub_f_id = self.add(subfunc, color=col, linestyle=LineStyle.Dashed, symbol=SymbolStyle.No)
f_id_list.append(sub_f_id)
gid = data_k.graph
if k in parts and show_fit:
color_scheme = available_cycles['colorblind']
for subfunc, col in zip(parts[k], cycle(color_scheme)):
subfunc.value = data_k.value
subfunc.group = data_k.group
subfunc.name += data_name
sub_f_id = self.add(subfunc, color=col, linestyle=LineStyle.Dashed, symbol=SymbolStyle.No)
f_id_list.append(sub_f_id)
self.delete_sets(tobedeleted)
if accepted and (param_graph != '-1'):
@ -546,6 +567,27 @@ class UpperManagement(QtCore.QObject):
self.newData.emit(f_id_list, gid)
def extend_fits(self, set_id: list, x_range: np.ndarray):
graphs = {}
for sid in set_id:
data = self[sid]
fit = data.copy(full=True, keep_color=True)
fit.data = fit.data.with_new_x(x_range)
graph_id = data.graph
if graph_id not in graphs:
graphs[graph_id] = []
graphs[graph_id].append(self.add(fit))
color_scheme = available_cycles['colorblind']
for subfunc, col in zip(fit.data.sub(fit.x), cycle(color_scheme)):
subfunc.value = fit.value
subfunc.group = fit.group
graphs[graph_id].append(self.add(subfunc, color=col, linestyle=LineStyle.Dashed, symbol=SymbolStyle.No))
for k, v in graphs.items():
self.newData.emit(v, k)
def make_fit_parameter(self, fit_sets: list[str | FitResult], graph_id: str = None):
fit_dict = self._collect_fit_parameter(fit_sets)