dialog to create fit functions

This commit is contained in:
Dominik Demuth 2023-01-08 19:30:15 +01:00
parent f05d28f6e6
commit 71f8871445
5 changed files with 60 additions and 16 deletions

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'src/resources/_ui/basewindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
# Created by: PyQt5 UI code generator 5.15.2
#
# 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.
@ -75,7 +75,7 @@ class Ui_BaseWindow(object):
self.horizontalLayout.addWidget(self.splitter)
BaseWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(BaseWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1386, 20))
self.menubar.setGeometry(QtCore.QRect(0, 0, 1386, 24))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@ -413,7 +413,6 @@ class Ui_BaseWindow(object):
self.menuFit.addAction(self.action_create_fit_function)
self.menuFit.addAction(self.actionFunction_editor)
self.menuFit.addSeparator()
self.menuFit.addAction(self.actionShow_fit_parameter)
self.menuFit.addAction(self.menuMethod.menuAction())
self.menuFit.addAction(self.menuLimits.menuAction())
self.menuOptions.addAction(self.actionMouse_behaviour)
@ -480,7 +479,7 @@ class Ui_BaseWindow(object):
self.retranslateUi(BaseWindow)
self.tabWidget.setCurrentIndex(0)
self.action_close.triggered.connect(BaseWindow.close) # type: ignore
self.action_close.triggered.connect(BaseWindow.close)
QtCore.QMetaObject.connectSlotsByName(BaseWindow)
def retranslateUi(self, BaseWindow):

View File

@ -2,7 +2,8 @@ from __future__ import annotations
import inspect
import numbers
import textwrap
import pathlib
import re
from typing import Any
import numpy as np
@ -14,15 +15,18 @@ from gui_qt.lib.namespace import QNamespaceWidget
__all__ = ['QUserFitCreator']
validator = QtGui.QRegExpValidator(QtCore.QRegExp('[A-Za-z]\S*'))
pattern = re.compile(r'def func\(.*\):', flags=re.MULTILINE)
class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
classCreated = QtCore.pyqtSignal(object)
classCreated = QtCore.pyqtSignal()
def __init__(self, parent=None):
def __init__(self, filepath: str|pathlib.Path, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.filepath = pathlib.Path(filepath)
self.description_widget = DescWidget(self)
self.args_widget = ArgWidget(self)
self.kwargs_widget = KwargsWidget(self)
@ -44,10 +48,23 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
self.update_function()
def __call__(self, *args, **kwargs):
def __call__(self, filepath: str|pathlib.Path):
self.filepath = pathlib.Path(filepath)
return self
def update_function(self):
prev_text = self.plainTextEdit.toPlainText().split('\n')
func_body = ''
in_body = False
for line in prev_text:
if in_body:
func_body += line
continue
if pattern.search(line) is not None:
in_body = True
try:
var = self.args_widget.get_parameter()
var += self.kwargs_widget.get_parameter()
@ -67,7 +84,12 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
k += self.kwargs_widget.get_strings()
k += '\n @staticmethod\n'
k += f" def func(x, {', '.join(var)}):\n"
if var:
k += f" def func(x, {', '.join(var)}):\n"
else:
k += f' def func(x):\n'
k += func_body
self.plainTextEdit.setPlainText(k)
except Exception as e:
@ -85,6 +107,7 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
ns = self.namespace_widget.namespace.namespace
func_value = ns[invalue][0]
ret_func = ''
import_name = ''
if func_value is None:
ret_func = invalue
@ -99,15 +122,28 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
else:
f_string = ns[invalue][-1]
args = f_string[f_string.find('('):]
if inspect.ismethod(func_value):
ret_func = func_value.__self__.__name__ + '.func'+args
import_name = func_value.__self__.__name__
elif hasattr(func_value, '__qualname__'):
ret_func = func_value.__qualname__.split('.')[0]
self._imports.add((inspect.getmodule(func_value).__name__, ret_func))
import_name = func_value.__qualname__.split('.')[0]
ret_func = func_value.__qualname__ + args
self._imports.add((inspect.getmodule(func_value).__name__, import_name))
self.plainTextEdit.insertPlainText(ret_func)
self.update_function()
def accept(self):
# maybe add a check for correctness
with self.filepath.open('a') as f:
f.write('\n\n')
f.write(self.plainTextEdit.toPlainText())
self.classCreated.emit()
super().accept()
class KwargsWidget(QtWidgets.QWidget):
Changed = QtCore.pyqtSignal()
@ -363,7 +399,7 @@ class ArgWidget(QtWidgets.QWidget):
return var
def get_strings(self):
def get_strings(self) -> str:
args = []
bnds = []
for row in range(self.table.rowCount()):
@ -434,7 +470,7 @@ class DescWidget(QtWidgets.QWidget):
raise ValueError('Class name is empty')
stringi = f'class {self.klass_lineedit.text()}:\n' \
f' name = {self.name_lineedit.text()!r}\n' \
f' group = {self.group_lineedit.text()!r}\n' \
f' type = {self.group_lineedit.text()!r}\n' \
f' equation = {self.eq_lineedit.text()!r}\n'
return stringi

View File

@ -13,7 +13,7 @@ import requests
from numpy import linspace
from scipy.interpolate import interp1d
from gui_qt.Qt import QtGui, QtWidgets, QtCore
from ..Qt import QtGui, QtWidgets, QtCore
@contextmanager

View File

@ -917,6 +917,16 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.editor.setWindowModality(QtCore.Qt.ApplicationModal)
self.editor.show()
@QtCore.pyqtSlot(name='on_action_create_fit_function_triggered')
def open_fitmodel_wizard(self):
from ..fit.function_creation_dialog import QUserFitCreator
helper = QUserFitCreator(config_paths() / 'usermodels.py', parent=self)
helper.classCreated.connect(lambda: self.fit_dialog.read_and_load_functions())
helper.show()
@QtCore.pyqtSlot(name='on_actionShift_triggered')
def shift_dialog(self):
s = QShift(self)

View File

@ -136,7 +136,7 @@
<x>0</x>
<y>0</y>
<width>1386</width>
<height>20</height>
<height>24</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -251,7 +251,6 @@
<addaction name="action_create_fit_function"/>
<addaction name="actionFunction_editor"/>
<addaction name="separator"/>
<addaction name="actionShow_fit_parameter"/>
<addaction name="menuMethod"/>
<addaction name="menuLimits"/>
</widget>