Merge branch 'main' into dsc

# Conflicts:
#	src/gui_qt/main/mainwindow.py
This commit is contained in:
Dominik Demuth 2023-06-20 18:07:52 +02:00
commit 032ffb72b1
34 changed files with 646 additions and 389 deletions

View File

@ -41,6 +41,7 @@ AppDir:
# - zsync # - zsync
# - hicolor-icon-theme # - hicolor-icon-theme
- libatlas3-base - libatlas3-base
- gnuplot-nox
- python3.9-minimal - python3.9-minimal
- python3-numpy - python3-numpy
- python3-scipy - python3-scipy
@ -70,7 +71,7 @@ AppDir:
- usr/share/doc/*/README.* - usr/share/doc/*/README.*
- usr/share/doc/*/changelog.* - usr/share/doc/*/changelog.*
- usr/share/doc/*/NEWS.* - usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.}* - usr/share/doc/*/TODO.*
runtime: runtime:
# if needed, apparently replaces hardcoded location with APPDIR location # if needed, apparently replaces hardcoded location with APPDIR location
# path_mappings: # path_mappings:

View File

@ -1,13 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'resources/_ui/bdsdialog.ui' # Form implementation generated from reading ui file 'src/resources/_ui/bdsdialog.ui'
# #
# Created by: PyQt5 UI code generator 5.9.2 # 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 from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object): class Ui_Dialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
Dialog.setObjectName("Dialog") Dialog.setObjectName("Dialog")
@ -16,12 +19,13 @@ class Ui_Dialog(object):
self.gridLayout.setContentsMargins(3, 3, 3, 3) self.gridLayout.setContentsMargins(3, 3, 3, 3)
self.gridLayout.setSpacing(3) self.gridLayout.setSpacing(3)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.listWidget = QtWidgets.QListWidget(Dialog) self.listWidget = QListWidgetSelect(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
self.listWidget.setSizePolicy(sizePolicy) self.listWidget.setSizePolicy(sizePolicy)
self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.listWidget.setObjectName("listWidget") self.listWidget.setObjectName("listWidget")
self.gridLayout.addWidget(self.listWidget, 1, 0, 2, 1) self.gridLayout.addWidget(self.listWidget, 1, 0, 2, 1)
self.groupBox_2 = QtWidgets.QGroupBox(Dialog) self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
@ -93,8 +97,8 @@ class Ui_Dialog(object):
self.gridLayout.addWidget(self.label, 0, 0, 1, 2) self.gridLayout.addWidget(self.label, 0, 0, 1, 2)
self.retranslateUi(Dialog) self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.freq_button, self.temp_button) Dialog.setTabOrder(self.freq_button, self.temp_button)
Dialog.setTabOrder(self.temp_button, self.eps_checkBox) Dialog.setTabOrder(self.temp_button, self.eps_checkBox)
@ -117,4 +121,4 @@ class Ui_Dialog(object):
self.temp_checkBox.setText(_translate("Dialog", "Meas. temperature")) self.temp_checkBox.setText(_translate("Dialog", "Meas. temperature"))
self.time_checkBox.setText(_translate("Dialog", "Meas. time")) self.time_checkBox.setText(_translate("Dialog", "Meas. time"))
self.label.setText(_translate("Dialog", "Found entries")) self.label.setText(_translate("Dialog", "Found entries"))
from ..lib.listwidget import QListWidgetSelect

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'src/resources/_ui/fitresult.ui' # Form implementation generated from reading ui file 'src/resources/_ui/fitresult.ui'
# #
# Created by: PyQt5 UI code generator 5.15.2 # Created by: PyQt5 UI code generator 5.15.9
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # 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. # run again. Do not edit this file unless you know what you are doing.
@ -14,37 +14,28 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object): class Ui_Dialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
Dialog.setObjectName("Dialog") Dialog.setObjectName("Dialog")
Dialog.resize(864, 649) Dialog.resize(969, 974)
self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.sets_comboBox = ElideComboBox(Dialog) self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) self.horizontalLayout_2.setSpacing(3)
sizePolicy.setHorizontalStretch(0) self.horizontalLayout_2.setObjectName("horizontalLayout_2")
sizePolicy.setVerticalStretch(0) self.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog)
sizePolicy.setHeightForWidth(self.sets_comboBox.sizePolicy().hasHeightForWidth()) self.reject_fit_checkBox.setObjectName("reject_fit_checkBox")
self.sets_comboBox.setSizePolicy(sizePolicy) self.horizontalLayout_2.addWidget(self.reject_fit_checkBox)
self.sets_comboBox.setMaximumSize(QtCore.QSize(400, 16777215)) self.del_prev_checkBox = QtWidgets.QCheckBox(Dialog)
self.sets_comboBox.setBaseSize(QtCore.QSize(200, 0)) self.del_prev_checkBox.setObjectName("del_prev_checkBox")
self.sets_comboBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength) self.horizontalLayout_2.addWidget(self.del_prev_checkBox)
self.sets_comboBox.setObjectName("sets_comboBox") self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 2)
self.gridLayout.addWidget(self.sets_comboBox, 0, 0, 1, 1) self.line = QtWidgets.QFrame(Dialog)
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line.setObjectName("line")
self.gridLayout.addWidget(self.line, 3, 0, 1, 2)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Retry) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Retry)
self.buttonBox.setObjectName("buttonBox") self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 6, 0, 1, 2) self.gridLayout.addWidget(self.buttonBox, 6, 0, 1, 2)
self.param_tableWidget = QtWidgets.QTableWidget(Dialog)
self.param_tableWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.param_tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
self.param_tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.param_tableWidget.setAlternatingRowColors(True)
self.param_tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.param_tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectColumns)
self.param_tableWidget.setShowGrid(False)
self.param_tableWidget.setColumnCount(0)
self.param_tableWidget.setObjectName("param_tableWidget")
self.param_tableWidget.setRowCount(0)
self.param_tableWidget.horizontalHeader().setStretchLastSection(False)
self.gridLayout.addWidget(self.param_tableWidget, 1, 0, 1, 1)
self.groupBox = QtWidgets.QGroupBox(Dialog) self.groupBox = QtWidgets.QGroupBox(Dialog)
self.groupBox.setObjectName("groupBox") self.groupBox.setObjectName("groupBox")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox) self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox)
@ -113,21 +104,34 @@ class Ui_Dialog(object):
self.horizontalLayout.addWidget(self.partial_checkBox) self.horizontalLayout.addWidget(self.partial_checkBox)
self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 4) self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 4)
self.gridLayout.addWidget(self.groupBox, 5, 0, 1, 2) self.gridLayout.addWidget(self.groupBox, 5, 0, 1, 2)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.param_tableWidget = QtWidgets.QTableWidget(Dialog)
self.horizontalLayout_2.setSpacing(3) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
self.horizontalLayout_2.setObjectName("horizontalLayout_2") sizePolicy.setHorizontalStretch(0)
self.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog) sizePolicy.setVerticalStretch(0)
self.reject_fit_checkBox.setObjectName("reject_fit_checkBox") sizePolicy.setHeightForWidth(self.param_tableWidget.sizePolicy().hasHeightForWidth())
self.horizontalLayout_2.addWidget(self.reject_fit_checkBox) self.param_tableWidget.setSizePolicy(sizePolicy)
self.del_prev_checkBox = QtWidgets.QCheckBox(Dialog) self.param_tableWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.del_prev_checkBox.setObjectName("del_prev_checkBox") self.param_tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
self.horizontalLayout_2.addWidget(self.del_prev_checkBox) self.param_tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 1) self.param_tableWidget.setAlternatingRowColors(True)
self.line = QtWidgets.QFrame(Dialog) self.param_tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.line.setFrameShape(QtWidgets.QFrame.HLine) self.param_tableWidget.setColumnCount(1)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.param_tableWidget.setObjectName("param_tableWidget")
self.line.setObjectName("line") self.param_tableWidget.setRowCount(0)
self.gridLayout.addWidget(self.line, 3, 0, 1, 2) self.param_tableWidget.horizontalHeader().setVisible(False)
self.param_tableWidget.horizontalHeader().setStretchLastSection(True)
self.gridLayout.addWidget(self.param_tableWidget, 1, 0, 1, 1)
self.sets_comboBox = ElideComboBox(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.sets_comboBox.sizePolicy().hasHeightForWidth())
self.sets_comboBox.setSizePolicy(sizePolicy)
self.sets_comboBox.setMaximumSize(QtCore.QSize(400, 16777215))
self.sets_comboBox.setBaseSize(QtCore.QSize(200, 0))
self.sets_comboBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
self.sets_comboBox.setObjectName("sets_comboBox")
self.gridLayout.addWidget(self.sets_comboBox, 0, 0, 1, 1)
self.stack = QtWidgets.QTabWidget(Dialog) self.stack = QtWidgets.QTabWidget(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -194,7 +198,7 @@ class Ui_Dialog(object):
self.corr_tableWidget.verticalHeader().setVisible(False) self.corr_tableWidget.verticalHeader().setVisible(False)
self.verticalLayout_3.addWidget(self.corr_tableWidget) self.verticalLayout_3.addWidget(self.corr_tableWidget)
self.stack.addTab(self.stackPage3, "") self.stack.addTab(self.stackPage3, "")
self.gridLayout.addWidget(self.stack, 0, 1, 3, 1) self.gridLayout.addWidget(self.stack, 0, 1, 2, 1)
self.retranslateUi(Dialog) self.retranslateUi(Dialog)
self.stack.setCurrentIndex(0) self.stack.setCurrentIndex(0)
@ -203,6 +207,8 @@ class Ui_Dialog(object):
def retranslateUi(self, Dialog): def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Fit results")) Dialog.setWindowTitle(_translate("Dialog", "Fit results"))
self.reject_fit_checkBox.setText(_translate("Dialog", "Reject this fit"))
self.del_prev_checkBox.setText(_translate("Dialog", "Delete previous fits"))
self.groupBox.setTitle(_translate("Dialog", "Output")) self.groupBox.setTitle(_translate("Dialog", "Output"))
self.extrapolate_box.setToolTip(_translate("Dialog", "Extrapolates only main function")) self.extrapolate_box.setToolTip(_translate("Dialog", "Extrapolates only main function"))
self.extrapolate_box.setText(_translate("Dialog", "Extrapolate curves")) self.extrapolate_box.setText(_translate("Dialog", "Extrapolate curves"))
@ -215,8 +221,6 @@ class Ui_Dialog(object):
self.numx_line.setPlaceholderText(_translate("Dialog", "# pts")) self.numx_line.setPlaceholderText(_translate("Dialog", "# pts"))
self.curve_checkbox.setText(_translate("Dialog", "Plot fit curve")) self.curve_checkbox.setText(_translate("Dialog", "Plot fit curve"))
self.partial_checkBox.setText(_translate("Dialog", "Plot partial functions")) self.partial_checkBox.setText(_translate("Dialog", "Plot partial functions"))
self.reject_fit_checkBox.setText(_translate("Dialog", "Reject this fit"))
self.del_prev_checkBox.setText(_translate("Dialog", "Delete previous fits"))
self.logy_box.setText(_translate("Dialog", "logarithmic y axis")) self.logy_box.setText(_translate("Dialog", "logarithmic y axis"))
self.logx_box.setText(_translate("Dialog", "logarithmic x axis")) self.logx_box.setText(_translate("Dialog", "logarithmic x axis"))
self.stack.setTabText(self.stack.indexOf(self.stackPage1), _translate("Dialog", "Plot")) self.stack.setTabText(self.stack.indexOf(self.stackPage1), _translate("Dialog", "Plot"))

View File

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'resources/_ui/graph.ui' # Form implementation generated from reading ui file 'src/resources/_ui/graph.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 from PyQt5 import QtCore, QtGui, QtWidgets
@ -196,12 +197,13 @@ class Ui_GraphWindow(object):
self.gridLayout.setHorizontalSpacing(3) self.gridLayout.setHorizontalSpacing(3)
self.gridLayout.setVerticalSpacing(0) self.gridLayout.setVerticalSpacing(0)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.listWidget = QtWidgets.QListWidget(GraphWindow) self.listWidget = QListWidgetSelect(GraphWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.MinimumExpanding) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
self.listWidget.setSizePolicy(sizePolicy) self.listWidget.setSizePolicy(sizePolicy)
self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.listWidget.setObjectName("listWidget") self.listWidget.setObjectName("listWidget")
self.gridLayout.addWidget(self.listWidget, 1, 1, 1, 1) self.gridLayout.addWidget(self.listWidget, 1, 1, 1, 1)
self.checkBox = QtWidgets.QCheckBox(GraphWindow) self.checkBox = QtWidgets.QCheckBox(GraphWindow)
@ -272,4 +274,5 @@ class Ui_GraphWindow(object):
self.label_6.setText(_translate("GraphWindow", "X Axis")) self.label_6.setText(_translate("GraphWindow", "X Axis"))
self.label_7.setText(_translate("GraphWindow", "Y Axis")) self.label_7.setText(_translate("GraphWindow", "Y Axis"))
self.checkBox.setText(_translate("GraphWindow", "Show legend")) self.checkBox.setText(_translate("GraphWindow", "Show legend"))
from ..lib.listwidget import QListWidgetSelect
from pyqtgraph import PlotWidget from pyqtgraph import PlotWidget

View File

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'resources/_ui/interpol_dialog.ui' # Form implementation generated from reading ui file 'src/resources/_ui/interpol_dialog.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 from PyQt5 import QtCore, QtGui, QtWidgets
@ -65,12 +66,13 @@ class Ui_Dialog(object):
self.label_2 = QtWidgets.QLabel(Dialog) self.label_2 = QtWidgets.QLabel(Dialog)
self.label_2.setObjectName("label_2") self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 6, 0, 1, 1) self.gridLayout.addWidget(self.label_2, 6, 0, 1, 1)
self.listWidget = QtWidgets.QListWidget(Dialog) self.listWidget = QListWidgetSelect(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
self.listWidget.setSizePolicy(sizePolicy) self.listWidget.setSizePolicy(sizePolicy)
self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.listWidget.setObjectName("listWidget") self.listWidget.setObjectName("listWidget")
self.gridLayout.addWidget(self.listWidget, 1, 0, 1, 2) self.gridLayout.addWidget(self.listWidget, 1, 0, 1, 2)
self.sampling_widget = QtWidgets.QWidget(Dialog) self.sampling_widget = QtWidgets.QWidget(Dialog)
@ -130,8 +132,8 @@ class Ui_Dialog(object):
self.label_8.setBuddy(self.dest_combobox) self.label_8.setBuddy(self.dest_combobox)
self.retranslateUi(Dialog) self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.listWidget, self.ylog_checkBox) Dialog.setTabOrder(self.listWidget, self.ylog_checkBox)
Dialog.setTabOrder(self.ylog_checkBox, self.interp_comboBox) Dialog.setTabOrder(self.ylog_checkBox, self.interp_comboBox)
@ -164,3 +166,4 @@ class Ui_Dialog(object):
self.xaxis_comboBox.setItemText(1, _translate("Dialog", "from data")) self.xaxis_comboBox.setItemText(1, _translate("Dialog", "from data"))
self.label_8.setText(_translate("Dialog", "Add interpolated data to")) self.label_8.setText(_translate("Dialog", "Add interpolated data to"))
self.xlog_checkBox.setText(_translate("Dialog", "use log(x)")) self.xlog_checkBox.setText(_translate("Dialog", "use log(x)"))
from ..lib.listwidget import QListWidgetSelect

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'resources/_ui/valueeditor.ui' # Form implementation generated from reading ui file 'src/resources/_ui/valueeditor.ui'
# #
# Created by: PyQt5 UI code generator 5.15.4 # Created by: PyQt5 UI code generator 5.15.9
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # 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. # run again. Do not edit this file unless you know what you are doing.

View File

@ -10,6 +10,7 @@ from nmreval.data.points import Points
from nmreval.data.signals import Signal from nmreval.data.signals import Signal
from nmreval.utils.text import convert from nmreval.utils.text import convert
from nmreval.data.bds import BDS from nmreval.data.bds import BDS
from nmreval.data.dsc import DSC
from nmreval.lib.colors import BaseColor, TUColors from nmreval.lib.colors import BaseColor, TUColors
from nmreval.lib.lines import LineStyle from nmreval.lib.lines import LineStyle
from nmreval.lib.symbols import SymbolStyle, symbolcycle from nmreval.lib.symbols import SymbolStyle, symbolcycle
@ -44,6 +45,7 @@ class ExperimentContainer(QtCore.QObject):
self.actions = {} self.actions = {}
self._update_actions() self._update_actions()
@plot_update
def _init_plot(self): def _init_plot(self):
raise NotImplementedError raise NotImplementedError
@ -312,10 +314,8 @@ class ExperimentContainer(QtCore.QObject):
err_pen.setColor(QtGui.QColor(*self.plot_real.symbolcolor.rgb())) err_pen.setColor(QtGui.QColor(*self.plot_real.symbolcolor.rgb()))
self.plot_error.setData(pen=err_pen) self.plot_error.setData(pen=err_pen)
elif mode == 'imag' and self.plot_imag is not None: if mode in ['imag', 'all'] and self.plot_imag is not None:
self.plot_imag.set_color(color, symbol=symbol, line=line) self.plot_imag.set_color(color, symbol=symbol, line=line)
else:
print('Updating color failed for ' + str(self.id))
def setSymbol(self, symbol=None, color=None, size=None, mode='real'): def setSymbol(self, symbol=None, color=None, size=None, mode='real'):
if mode in ['real', 'all']: if mode in ['real', 'all']:
@ -460,7 +460,7 @@ class ExperimentContainer(QtCore.QObject):
return namespace return namespace
def eval_expression(self, cmds, namespace): def eval_expression(self, cmds, namespace):
namespace.update({'x': self.x, 'y': self.y, 'y_err': self.y_err, 'value': self.value}) namespace.update({'x': self._data.x, 'y': self._data.y, 'y_err': self._data.y_err, 'value': self.value})
if len(self._fits) == 1: if len(self._fits) == 1:
namespace.update({"fit['%s']" % (convert(pname, old='tex', new='str')): pvalue.value namespace.update({"fit['%s']" % (convert(pname, old='tex', new='str')): pvalue.value
@ -475,7 +475,7 @@ class ExperimentContainer(QtCore.QObject):
if c: if c:
exec(c, globals(), namespace) exec(c, globals(), namespace)
new_data.set_data(x=namespace['x'], y=namespace['y'], y_err=namespace['y_err']) new_data.set_data(x=namespace['x'], y=namespace['y'], y_err=namespace['y_err'], replace_mask=False)
new_data.value = namespace['value'] new_data.value = namespace['value']
return new_data return new_data
@ -496,6 +496,9 @@ class PointContainer(ExperimentContainer):
self.mode = 'pts' self.mode = 'pts'
self._init_plot(**kwargs) self._init_plot(**kwargs)
if isinstance(self._data, DSC):
self.mode = 'dsc'
def _init_plot(self, **kwargs): def _init_plot(self, **kwargs):
self.plot_imag = None self.plot_imag = None
@ -532,17 +535,17 @@ class PointContainer(ExperimentContainer):
line_kwargs['style'] = LineStyle.No line_kwargs['style'] = LineStyle.No
sym_kwargs['symbol'] = next(PointContainer.symbols) sym_kwargs['symbol'] = next(PointContainer.symbols)
self.plot_real = PlotItem(x=self._data.x, y=self._data.y, name=self.name, self.plot_real = PlotItem(x=self.x, y=self.y, name=self.name,
symbol=None, pen=None, connect='finite') symbol=None, pen=None, connect='finite')
self.setSymbol(mode='real', **sym_kwargs) self.setSymbol(mode='real', **sym_kwargs)
self.setLine(mode='real', **line_kwargs) self.setLine(mode='real', **line_kwargs)
if sym_kwargs['symbol'] != SymbolStyle.No: if sym_kwargs['symbol'] != SymbolStyle.No:
self.plot_error = ErrorBars(x=self._data.x, y=self._data.y, top=self._data.y_err, bottom=self._data.y_err, self.plot_error = ErrorBars(x=self.x, y=self.y, top=self.y_err, bottom=self.y_err,
pen=mkPen({'color': self.plot_real.symbolcolor.rgb()})) pen=mkPen({'color': self.plot_real.symbolcolor.rgb()}))
else: else:
self.plot_error = ErrorBars(x=self._data.x, y=self._data.y, top=self._data.y_err, bottom=self._data.y_err, self.plot_error = ErrorBars(x=self.x, y=self.y, top=self.y_err, bottom=self.y_err,
pen=mkPen({'color': self.plot_real.linecolor.rgb()})) pen=mkPen({'color': self.plot_real.linecolor.rgb()}))
@ -565,12 +568,12 @@ class FitContainer(ExperimentContainer):
if isinstance(color, BaseColor): if isinstance(color, BaseColor):
color = color.rgb() color = color.rgb()
self.plot_real = PlotItem(x=self._data.x, y=self._data.y.real, name=self.name, self.plot_real = PlotItem(x=self.x, y=self.y.real, name=self.name,
pen=mkPen({'color': color}), pen=mkPen({'color': color}),
connect='finite', symbol=None) connect='finite', symbol=None)
if np.iscomplexobj(self._data.y): if np.iscomplexobj(self._data.y):
self.plot_imag = PlotItem(x=self._data.x, y=self._data.y.imag, name=self.name, self.plot_imag = PlotItem(x=self.x, y=self.y.imag, name=self.name,
pen=mkPen({'color': color}), pen=mkPen({'color': color}),
connect='finite', symbol=None) connect='finite', symbol=None)
@ -603,9 +606,9 @@ class SignalContainer(ExperimentContainer):
self._init_plot(symbol=symbol, **kwargs) self._init_plot(symbol=symbol, **kwargs)
def _init_plot(self, **kwargs): def _init_plot(self, **kwargs):
self.plot_real = PlotItem(x=self._data.x, y=self._data.y.real, name=self.name, self.plot_real = PlotItem(x=self.x, y=self.y.real, name=self.name,
symbol=None, pen=None, connect='finite') symbol=None, pen=None, connect='finite')
self.plot_imag = PlotItem(x=self._data.x, y=self._data.y.imag, name=self.name, self.plot_imag = PlotItem(x=self.x, y=self.y.imag, name=self.name,
symbol=None, pen=None, connect='finite') symbol=None, pen=None, connect='finite')
color = kwargs.get('color', None) color = kwargs.get('color', None)

View File

@ -187,9 +187,15 @@ class PointSelectWidget(QtWidgets.QWidget, Ui_Form):
self.peaktable.blockSignals(False) self.peaktable.blockSignals(False)
def set_graphs(self, graphs: list): def set_graphs(self, graphs: list):
last_graph = self.graph_combobox.currentData()
self.graph_combobox.clear() self.graph_combobox.clear()
for g in graphs: idx = 0
for i, g in enumerate(graphs):
self.graph_combobox.addItem(g[1], userData=g[0]) self.graph_combobox.addItem(g[1], userData=g[0])
if g[0] == last_graph:
idx = i
self.graph_combobox.setCurrentIndex(idx)
@QtCore.pyqtSlot(int, name='on_graph_checkbox_stateChanged') @QtCore.pyqtSlot(int, name='on_graph_checkbox_stateChanged')
def changed_state(self, checked): def changed_state(self, checked):

View File

@ -188,7 +188,15 @@ class ValueEditWidget(QtWidgets.QWidget, Ui_MaskDialog):
new_value = complex(val) new_value = complex(val)
new_value = new_value.real if new_value.imag == 0 else new_value new_value = new_value.real if new_value.imag == 0 else new_value
# table view loses focus when itemChanged is emitted
# if edit of item is cause of change resume editing at next item
prev_state = self.tableView.state()
idx = self.tableView.currentIndex()
idx = idx.sibling((col+1)//3+row, (col+1) % 3)
self.itemChanged.emit(sid, (col, row), new_value) self.itemChanged.emit(sid, (col, row), new_value)
if prev_state == self.tableView.State.EditingState:
self.tableView.setCurrentIndex(idx)
self.tableView.edit(idx)
@QtCore.pyqtSlot(QtCore.QItemSelection, QtCore.QItemSelection) @QtCore.pyqtSlot(QtCore.QItemSelection, QtCore.QItemSelection)
def show_position(self, *_): def show_position(self, *_):
@ -259,10 +267,7 @@ class ValueModel(QtCore.QAbstractTableModel):
row = idx.row() row = idx.row()
if role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]: if role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]:
val = self._data[row][idx.column()] val = self._data[row][idx.column()]
if isinstance(val, complex): return self.as_string(val)
return f'{val.real:.8g}{val.imag:+.8g}j'
else:
return f'{val:.8g}'
elif role == QtCore.Qt.BackgroundRole: elif role == QtCore.Qt.BackgroundRole:
pal = QtGui.QGuiApplication.palette() pal = QtGui.QGuiApplication.palette()
@ -295,11 +300,16 @@ class ValueModel(QtCore.QAbstractTableModel):
if value: if value:
if role == QtCore.Qt.EditRole: if role == QtCore.Qt.EditRole:
if value == self.as_string(self._data[row][col]):
return True
try: try:
value = complex(value) value = complex(value)
except ValueError: except ValueError:
# not a number # not a number
return False return False
value = value.real if value.imag == 0 else value
self._data[row][col] = value.real if value.imag == 0 else value self._data[row][col] = value.real if value.imag == 0 else value
self.itemChanged.emit(col, row, str(value)) self.itemChanged.emit(col, row, str(value))
self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [role]) self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [role])
@ -368,3 +378,10 @@ class ValueModel(QtCore.QAbstractTableModel):
def unmask(self): def unmask(self):
self.mask = [True] * self.total_rows self.mask = [True] * self.total_rows
self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [ValueModel.maskRole]) self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [ValueModel.maskRole])
@staticmethod
def as_string(value) -> str:
if isinstance(value, complex):
return f'{value.real:.8g}{value.imag:+.8g}j'
else:
return f'{value:.8g}'

View File

@ -181,6 +181,11 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
for i, value in enumerate(self.data_values[sid]): for i, value in enumerate(self.data_values[sid]):
w = self.data_parameter[i] w = self.data_parameter[i]
w.blockSignals(True) w.blockSignals(True)
try:
w.show_as_local_parameter(value is not None)
except AttributeError:
pass
if value is None: if value is None:
w.value = self.glob_values[i] w.value = self.glob_values[i]
else: else:
@ -263,17 +268,17 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
return data_parameter, lb, ub, is_fixed, global_p, is_linked return data_parameter, lb, ub, is_fixed, global_p, is_linked
def set_parameter(self, set_id: str | None, parameter: list[float]) -> int: def set_parameter(self, set_id: str | None, parameter: list[float]) -> int:
param_len = len(list(filter(lambda g: not isinstance(g, SelectionWidget), self.global_parameter))) num_parameter = list(filter(lambda g: not isinstance(g, SelectionWidget), self.global_parameter))
param_len = len(num_parameter)
if set_id is None: if set_id is None:
for val, g in zip(parameter, self.global_parameter): for i, g in enumerate(num_parameter):
if isinstance(g, SelectionWidget): val = parameter[i]
continue
g.set_parameter(val) g.set_parameter(val)
self.glob_values[i] = val
else: else:
new_param = self.data_values[set_id] new_param = self.data_values[set_id]
min_len = min(param_len, len(new_param), len(new_param)) min_len = min(param_len, len(new_param))
for i in range(min_len): for i in range(min_len):
new_param[i] = parameter[i] new_param[i] = parameter[i]
@ -293,6 +298,7 @@ class ParameterSingleWidget(QtWidgets.QWidget):
self._name = name self._name = name
self.label.setText(convert(name)) self.label.setText(convert(name))
self.label.setToolTip('IIf 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.value_line.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0)
@ -309,10 +315,12 @@ class ParameterSingleWidget(QtWidgets.QWidget):
layout.addSpacerItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)) layout.addSpacerItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum))
self.value_line = QtWidgets.QLineEdit(self) self.value_line = QtWidgets.QLineEdit(self)
self.value_line.textEdited.connect(lambda x: self.show_as_local_parameter(True))
layout.addWidget(self.value_line) layout.addWidget(self.value_line)
self.reset_button = QtWidgets.QToolButton(self) self.reset_button = QtWidgets.QToolButton(self)
self.reset_button.setText('Use global') self.reset_button.setText('Use global')
self.reset_button.clicked.connect(lambda: self.show_as_local_parameter(False))
layout.addWidget(self.reset_button) layout.addWidget(self.reset_button)
self.setLayout(layout) self.setLayout(layout)
@ -327,3 +335,9 @@ class ParameterSingleWidget(QtWidgets.QWidget):
@value.setter @value.setter
def value(self, val): def value(self, val):
self.value_line.setText(f'{float(val):.5g}') self.value_line.setText(f'{float(val):.5g}')
def show_as_local_parameter(self, is_local):
if is_local:
self.label.setStyleSheet('font-weight: bold;')
else:
self.label.setStyleSheet('')

View File

@ -77,16 +77,11 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
w.deleteLater() w.deleteLater()
del self.param_widgets[idx] del self.param_widgets[idx]
if len(self.functionwidget) == 0: self._current_function = None
if len(self.param_widgets) == 0:
# empty model # empty model
self.newmodel_button.setEnabled(False) self.newmodel_button.setEnabled(False)
self.deletemodel_button.setEnabled(False) self.deletemodel_button.setEnabled(False)
self._current_function = None
else:
f_tree = self.functionwidget.functree
func_idx = f_tree.currentItem().data(0, f_tree.counterRole)
self._current_function = self.functionwidget.functions[func_idx]
@QtCore.pyqtSlot(int) @QtCore.pyqtSlot(int)
def show_function_parameter(self, function_id: int, function_idx: int = None): def show_function_parameter(self, function_id: int, function_idx: int = None):

View File

@ -27,70 +27,80 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.extrapolate_box.stateChanged.connect(lambda x: self.minx_line.setEnabled(x)) self.extrapolate_box.stateChanged.connect(lambda x: self.minx_line.setEnabled(x))
self.extrapolate_box.stateChanged.connect(lambda x: self.numx_line.setEnabled(x)) self.extrapolate_box.stateChanged.connect(lambda x: self.numx_line.setEnabled(x))
self._prevs = {} self._previous_fits = {}
self._models = {} self._opts = []
self._results = {}
self.graph_opts = {}
self.last_idx = None
for res in results: self.resid_plot = self.graphicsView.addPlot(row=0, col=0, title='Residual')
idx = res.idx self.fit_plot = self.graphicsView.addPlot(row=1, col=0, title='Fit')
data_k = management.data[idx]
if res.name not in self._models: self.graphicsView.ci.layout.setRowStretchFactor(0, 1)
self._models[res.name] = [] self.graphicsView.ci.layout.setRowStretchFactor(1, 2)
self._models[res.name].append(idx)
self._prevs[idx] = []
for fit in data_k.get_fits():
self._prevs[idx].append((fit.name, fit.statistics, fit.nobs-fit.nvar))
self._results = {res.idx: res for res in results}
self._opts = [(False, False) for _ in range(len(self._results))]
self.residplot = self.graphicsView.addPlot(row=0, col=0)
self.resid_graph = PlotItem(x=[], y=[], self.resid_graph = PlotItem(x=[], y=[],
symbol='o', symbolPen=None, symbolBrush=mkBrush(color=(31, 119, 180)), symbol='o', symbolPen=None, symbolBrush=mkBrush(color=(31, 119, 180)),
pen=None) pen=None)
self.resid_graph_imag = PlotItem(x=[], y=[], self.resid_graph_imag = PlotItem(x=[], y=[],
symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)), symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)),
pen=None) pen=None)
self.residplot.addItem(self.resid_graph) self.resid_plot.addItem(self.resid_graph)
self.residplot.addItem(self.resid_graph_imag) self.resid_plot.addItem(self.resid_graph_imag)
self.residplot.setLabel('left', 'Residual')
self.fitplot = self.graphicsView.addPlot(row=1, col=0)
self.data_graph = PlotItem(x=[], y=[], self.data_graph = PlotItem(x=[], y=[],
symbol='o', symbolPen=None, symbolBrush=mkBrush(color=(31, 119, 180)), symbol='o', symbolPen=None, symbolBrush=mkBrush(color=(31, 119, 180)),
pen=None) pen=None)
self.data_graph_imag = PlotItem(x=[], y=[], self.data_graph_imag = PlotItem(x=[], y=[],
symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)), symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)),
pen=None) pen=None)
self.fitplot.addItem(self.data_graph) self.fit_plot.addItem(self.data_graph)
self.fitplot.addItem(self.data_graph_imag) self.fit_plot.addItem(self.data_graph_imag)
self.fitplot.setLabel('left', 'Function')
self.fit_graph = PlotItem(x=[], y=[]) self.fit_graph = PlotItem(x=[], y=[])
self.fit_graph_imag = PlotItem(x=[], y=[]) self.fit_graph_imag = PlotItem(x=[], y=[])
self.fitplot.addItem(self.fit_graph) self.fit_plot.addItem(self.fit_graph)
self.fitplot.addItem(self.fit_graph_imag) self.fit_plot.addItem(self.fit_graph_imag)
self.cmap = RdBuCMap(vmin=-1, vmax=1) self.cmap = RdBuCMap(vmin=-1, vmax=1)
self.sets_comboBox.blockSignals(True)
for n in self._models.keys():
self.sets_comboBox.addItem(n)
self.sets_comboBox.blockSignals(False)
self.set_parameter(0)
self.buttonBox.accepted.connect(self.accept) self.buttonBox.accepted.connect(self.accept)
self.param_tableWidget.itemClicked.connect(self.show_results)
self.param_tableWidget.horizontalHeader().sectionClicked.connect(lambda i: self.show_results(None, idx=i))
self.graph_checkBox.stateChanged.connect(lambda x: self.graph_comboBox.setEnabled(x == QtCore.Qt.Unchecked)) self.graph_checkBox.stateChanged.connect(lambda x: self.graph_comboBox.setEnabled(x == QtCore.Qt.Unchecked))
self.logy_box.stateChanged.connect(lambda x: self.fitplot.setLogMode(y=bool(x))) self.logy_box.stateChanged.connect(lambda x: self.fit_plot.setLogMode(y=bool(x)))
self.logx_box.stateChanged.connect(lambda x: self.fitplot.setLogMode(x=bool(x))) self.logx_box.stateChanged.connect(lambda x: self.fit_plot.setLogMode(x=bool(x)))
self.residplot.setXLink(self.fitplot) self.resid_plot.setXLink(self.fit_plot)
self.set_results(results)
def __call__(self, results: list):
self._previous_fits = {}
self.sets_comboBox.blockSignals(True)
self.sets_comboBox.clear()
self.sets_comboBox.blockSignals(False)
self._results = {}
self._opts = {}
self.set_results(results)
def set_results(self, results: list):
self.sets_comboBox.blockSignals(True)
for res in results:
idx = res.idx
data_k = self._management.data[idx]
self._previous_fits[idx] = []
for fit in data_k.get_fits():
self._previous_fits[idx].append((fit.name, fit.statistics, fit.nobs - fit.nvar))
self.sets_comboBox.addItem(data_k.name, userData=idx)
self.sets_comboBox.blockSignals(False)
self._results = {res.idx: res for res in results}
self._opts = [(False, False) for _ in range(len(self._results))]
self.set_parameter(0)
def add_graphs(self, graphs: list): def add_graphs(self, graphs: list):
self.graph_comboBox.clear() self.graph_comboBox.clear()
@ -99,56 +109,40 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
@QtCore.pyqtSlot(int, name='on_sets_comboBox_currentIndexChanged') @QtCore.pyqtSlot(int, name='on_sets_comboBox_currentIndexChanged')
def set_parameter(self, idx: int): def set_parameter(self, idx: int):
model_name = self.sets_comboBox.itemText(idx) set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.UserRole)
sets = self._models[model_name]
self.param_tableWidget.setColumnCount(len(sets))
r = self._results[sets[0]] res = self._results[set_id]
self.param_tableWidget.setRowCount(len(r.parameter)) self.param_tableWidget.setRowCount(len(res.parameter))
for j, (pkey, pvalue) in enumerate(res.parameter.items()):
name = pkey
p_header = QtWidgets.QTableWidgetItem(convert(name, 'tex', 'str', brackets=True))
self.param_tableWidget.setVerticalHeaderItem(j, p_header)
for i, pval in enumerate(r.parameter.values()): item_text = f'{pvalue.value:.4g}'
name = pval.full_name if pvalue.error is not None:
p_header = QtWidgets.QTableWidgetItem(convert(name, 'tex', 'html', brackets=False)) item_text += f' \u00b1 {pvalue.error:.4g}'
self.param_tableWidget.setVerticalHeaderItem(i, p_header) self.param_tableWidget.setItem(2*j+1, 0, QtWidgets.QTableWidgetItem('-'))
else:
self.param_tableWidget.setItem(2*j+1, 0, QtWidgets.QTableWidgetItem())
item = QtWidgets.QTableWidgetItem(item_text)
self.param_tableWidget.setItem(j, 0, item)
for i, set_id in enumerate(sets): self.param_tableWidget.resizeColumnToContents(0)
data_i = self._management[set_id] self.show_results(idx)
header_item = QtWidgets.QTableWidgetItem(data_i.name)
header_item.setData(QtCore.Qt.UserRole, set_id)
self.param_tableWidget.setHorizontalHeaderItem(i, header_item)
res = self._results[set_id]
for j, pvalue in enumerate(res.parameter.values()):
item_text = f'{pvalue.value:.4g}'
if pvalue.error is not None:
item_text += f' \u00b1 {pvalue.error:.4g}'
self.param_tableWidget.setItem(2*j+1, i, QtWidgets.QTableWidgetItem('-'))
else:
self.param_tableWidget.setItem(2*j+1, i, QtWidgets.QTableWidgetItem())
item = QtWidgets.QTableWidgetItem(item_text)
self.param_tableWidget.setItem(j, i, item)
self.param_tableWidget.resizeColumnsToContents()
self.param_tableWidget.selectColumn(0)
self.show_results(None, idx=0)
@QtCore.pyqtSlot(int, name='on_reject_fit_checkBox_stateChanged') @QtCore.pyqtSlot(int, name='on_reject_fit_checkBox_stateChanged')
@QtCore.pyqtSlot(int, name='on_del_prev_checkBox_stateChanged') @QtCore.pyqtSlot(int, name='on_del_prev_checkBox_stateChanged')
def change_opts(self, _): def change_opts(self, _):
idx = self.param_tableWidget.currentIndex().column() idx = self.sets_comboBox.currentIndex()
self._opts[idx] = (self.reject_fit_checkBox.checkState() == QtCore.Qt.Checked, self._opts[idx] = (self.reject_fit_checkBox.checkState() == QtCore.Qt.Checked,
self.del_prev_checkBox.checkState() == QtCore.Qt.Checked) self.del_prev_checkBox.checkState() == QtCore.Qt.Checked)
def show_results(self, item, idx=None): def show_results(self, idx):
if item is not None: set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.UserRole)
idx = self.param_tableWidget.indexFromItem(item).column()
set_id = self.param_tableWidget.horizontalHeaderItem(idx).data(QtCore.Qt.UserRole)
self.set_plot(set_id) self.set_plot(set_id)
self.set_correlation(set_id) self.set_correlation(set_id)
self.set_statistics(set_id) self.set_statistics(set_id)
self.reject_fit_checkBox.blockSignals(True) self.reject_fit_checkBox.blockSignals(True)
self.reject_fit_checkBox.setChecked(self._opts[idx][0]) self.reject_fit_checkBox.setChecked(self._opts[idx][0])
self.reject_fit_checkBox.blockSignals(False) self.reject_fit_checkBox.blockSignals(False)
@ -157,13 +151,21 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.del_prev_checkBox.blockSignals(False) self.del_prev_checkBox.blockSignals(False)
def set_plot(self, idx: str): def set_plot(self, idx: str):
if self.last_idx is not None:
self.graph_opts[self.last_idx] = (
self.fit_plot.viewRange(),
self.logx_box.isChecked(),
self.logy_box.isChecked(),
)
self.last_idx = idx
res = self._results[idx] res = self._results[idx]
iscomplex = res.iscomplex iscomplex = res.iscomplex
sub_funcs = res.sub(res.x) sub_funcs = res.sub(res.x)
for item in self.fitplot.curves[::-1]: for item in self.fit_plot.items[::-1]:
if item not in [self.data_graph, self.data_graph_imag, self.fit_graph, self.fit_graph_imag]: if item not in [self.data_graph, self.data_graph_imag, self.fit_graph, self.fit_graph_imag]:
self.fitplot.removeItem(item) self.fit_plot.removeItem(item)
if iscomplex: if iscomplex:
self.data_graph.setData(x=res.x_data, y=res.y_data.real) self.data_graph.setData(x=res.x_data, y=res.y_data.real)
@ -173,11 +175,11 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.resid_graph.setData(x=res.x_data, y=res.residual.real) self.resid_graph.setData(x=res.x_data, y=res.residual.real)
self.resid_graph_imag.setData(x=res.x_data, y=res.residual.imag) self.resid_graph_imag.setData(x=res.x_data, y=res.residual.imag)
for f in sub_funcs: for i, f in enumerate(sub_funcs):
item = PlotItem(x=f.x, y=f.y.real) item = PlotItem(x=f.x, y=f.y.real, pen=mkPen({'color': i, 'style': 2}))
self.fitplot.addItem(item) self.fit_plot.addItem(item)
item = PlotItem(x=f.x, y=f.y.imag) item = PlotItem(x=f.x, y=f.y.imag, pen=mkPen({'color': i, 'style': 2}))
self.fitplot.addItem(item) self.fit_plot.addItem(item)
else: else:
self.resid_graph.setData(x=res.x_data, y=res.residual) self.resid_graph.setData(x=res.x_data, y=res.residual)
@ -187,12 +189,27 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.fit_graph.setData(x=res.x, y=res.y) self.fit_graph.setData(x=res.x, y=res.y)
self.fit_graph_imag.setData(x=[], y=[]) self.fit_graph_imag.setData(x=[], y=[])
for f in sub_funcs: for i, f in enumerate(sub_funcs):
item = PlotItem(x=f.x, y=f.y, pen=mkPen({'style': 2})) item = PlotItem(x=f.x, y=f.y, pen=mkPen({'color': i, 'style': 2}))
self.fitplot.addItem(item) self.fit_plot.addItem(item)
self.fitplot.setLogMode(x=res.islog) self.logx_box.blockSignals(True)
self.residplot.setLogMode(x=res.islog) self.logx_box.setChecked(res.islog)
self.logx_box.blockSignals(False)
self.fit_plot.setLogMode(x=res.islog)
self.resid_plot.setLogMode(x=res.islog)
if idx in self.graph_opts:
view_range, logx, logy = self.graph_opts[idx]
self.fit_plot.setRange(xRange=view_range[0], yRange=view_range[1], padding=0)
self.fit_plot.setLogMode(x=logx, y=logy)
self.logx_box.blockSignals(True)
self.logx_box.setChecked(logx)
self.logx_box.blockSignals(False)
self.logy_box.blockSignals(True)
self.logy_box.setChecked(logy)
self.logy_box.blockSignals(False)
def set_correlation(self, idx: str): def set_correlation(self, idx: str):
while self.corr_tableWidget.rowCount(): while self.corr_tableWidget.rowCount():
@ -223,7 +240,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
res = self._results[idx] res = self._results[idx]
self.stats_tableWidget.setColumnCount(1 + len(self._prevs[idx])) self.stats_tableWidget.setColumnCount(1 + len(self._previous_fits[idx]))
self.stats_tableWidget.setRowCount(len(res.statistics)+3) self.stats_tableWidget.setRowCount(len(res.statistics)+3)
it = QtWidgets.QTableWidgetItem(f'{res.dof}') it = QtWidgets.QTableWidgetItem(f'{res.dof}')
@ -231,7 +248,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.stats_tableWidget.setVerticalHeaderItem(0, QtWidgets.QTableWidgetItem('DoF')) self.stats_tableWidget.setVerticalHeaderItem(0, QtWidgets.QTableWidgetItem('DoF'))
self.stats_tableWidget.setItem(0, 0, it) self.stats_tableWidget.setItem(0, 0, it)
for col, (name, _, dof) in enumerate(self._prevs[idx], start=1): for col, (name, _, dof) in enumerate(self._previous_fits[idx], start=1):
self.stats_tableWidget.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem(name)) self.stats_tableWidget.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem(name))
it = QtWidgets.QTableWidgetItem(f'{dof}') it = QtWidgets.QTableWidgetItem(f'{dof}')
it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable)
@ -245,7 +262,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
best_idx = -1 best_idx = -1
best_val = v best_val = v
for col, (_, stats, _) in enumerate(self._prevs[idx], start=1): for col, (_, stats, _) in enumerate(self._previous_fits[idx], start=1):
if k in ['adj. R^2', 'R^2']: if k in ['adj. R^2', 'R^2']:
best_idx = col if best_val < stats[k] else max(0, best_idx) best_idx = col if best_val < stats[k] else max(0, best_idx)
else: else:
@ -265,7 +282,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.stats_tableWidget.setVerticalHeaderItem(row+1, QtWidgets.QTableWidgetItem('Pr(>F)')) self.stats_tableWidget.setVerticalHeaderItem(row+1, QtWidgets.QTableWidgetItem('Pr(>F)'))
self.stats_tableWidget.setItem(row+1, 0, QtWidgets.QTableWidgetItem('-')) self.stats_tableWidget.setItem(row+1, 0, QtWidgets.QTableWidgetItem('-'))
for col, (_, stats, dof) in enumerate(self._prevs[idx], start=1): for col, (_, stats, dof) in enumerate(self._previous_fits[idx], start=1):
f_value, prob_f = res.f_test(stats['chi^2'], dof) f_value, prob_f = res.f_test(stats['chi^2'], dof)
it = QtWidgets.QTableWidgetItem(f'{f_value:.4g}') it = QtWidgets.QTableWidgetItem(f'{f_value:.4g}')
it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable)
@ -312,7 +329,6 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
except TypeError: except TypeError:
pass pass
self.closed.emit(self._results, self._opts, graph, plot_fits, parts, extrapolate) self.closed.emit(self._results, self._opts, graph, plot_fits, parts, extrapolate)
self.accept() self.accept()
@ -348,7 +364,7 @@ class FitExtension(QtWidgets.QDialog):
self.buttonBox = QtWidgets.QDialogButtonBox() self.buttonBox = QtWidgets.QDialogButtonBox()
self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2) gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2)
self.setLayout(gridLayout) self.setLayout(gridLayout)
@ -365,4 +381,4 @@ class FitExtension(QtWidgets.QDialog):
except TypeError: except TypeError:
return None return None
return xmin, xmax, nums return xmin, xmax, nums

View File

@ -98,15 +98,19 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
@QtCore.pyqtSlot(int, name='on_preview_spinBox_valueChanged') @QtCore.pyqtSlot(int, name='on_preview_spinBox_valueChanged')
def show_preview(self, line_no: int): def show_preview(self, line_no: int):
preview, width = self.reader.make_preview(line_no) preview, width, comments = self.reader.make_preview(line_no)
self.ascii_table.setRowCount(min(line_no, len(preview))) self.ascii_table.setRowCount(min(line_no, len(preview)))
self.ascii_table.setColumnCount(width) self.ascii_table.setColumnCount(width + 1)
for i, line in enumerate(preview): for i, line in enumerate(preview):
comment_line = comments[i]
for j, field in enumerate(line): for j, field in enumerate(line):
it = QtWidgets.QTableWidgetItem(field) it = QtWidgets.QTableWidgetItem(field)
self.ascii_table.setItem(i, j, it) self.ascii_table.setItem(i, j, it)
it = QtWidgets.QTableWidgetItem(comment_line)
self.ascii_table.setItem(i, len(line), it)
self.ascii_table.resizeColumnsToContents() self.ascii_table.resizeColumnsToContents()
@QtCore.pyqtSlot(int, name='on_column_checkBox_stateChanged') @QtCore.pyqtSlot(int, name='on_column_checkBox_stateChanged')

View File

@ -55,9 +55,9 @@ class GraceExporter:
break break
if c_num == -1: if c_num == -1:
c_num = max(colors.keys()) c_num = max(colors.keys())+1
colors[c_num + 1] = (f'color{c_num + 1}', sc) colors[c_num] = (f'color{c_num}', sc)
new_colors.append((c_num + 1, f'color{c_num + 1}', sc)) new_colors.append((c_num, f'color{c_num}', sc))
new_s.set_symbol(**{'symbol': item['symbol'].value, 'size': item['symbolsize'] / 10., 'color': c_num, new_s.set_symbol(**{'symbol': item['symbol'].value, 'size': item['symbolsize'] / 10., 'color': c_num,
'fill color': c_num, 'fill pattern': 1}) 'fill color': c_num, 'fill pattern': 1})

View File

@ -89,8 +89,11 @@ class QGraceReader(QtWidgets.QDialog, Ui_Dialog):
item = iterator.value() item = iterator.value()
key = (item.data(0, QtCore.Qt.UserRole)) key = (item.data(0, QtCore.Qt.UserRole))
s = self._reader.dataset(*key) s = self._reader.dataset(*key)
label = self._reader.get_property(*key, 'legend').replace('"', '') label = self._reader.get_property(*key, 'legend')
# label = self._reader.graphs[key[0]].sets[key[1]]['legend'].replace('"', '') if label is None:
label = ''
else:
label = label.replace('"', '')
sd = s.data sd = s.data
sd = np.atleast_2d(sd) sd = np.atleast_2d(sd)
if s.type == 'xydy': if s.type == 'xydy':

View File

@ -42,7 +42,7 @@ class PropertyDelegate(QtWidgets.QStyledItemDelegate):
painter.setPen(pen) painter.setPen(pen)
pm = make_symbol_pixmap(r) pm = make_symbol_pixmap(r)
painter.drawPixmap(options.rect.topLeft()+QtCore.QPoint(3, (options.rect.height()-pm.height())/2), pm) painter.drawPixmap(options.rect.topLeft()+QtCore.QPoint(3, int((options.rect.height()-pm.height())/2)), pm)
style = QtWidgets.QApplication.style() style = QtWidgets.QApplication.style()
text_rect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options, None) text_rect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options, None)
@ -171,7 +171,7 @@ class LineStyleEditor(QtWidgets.QComboBox):
rect = painter.style().subControlRect(QtWidgets.QStyle.CC_ComboBox, rect = painter.style().subControlRect(QtWidgets.QStyle.CC_ComboBox,
opt, QtWidgets.QStyle.SC_ComboBoxEditField, None) opt, QtWidgets.QStyle.SC_ComboBoxEditField, None)
rect.adjust(+10, 0, -10, 0) rect.adjust(+10, 0, -10, 0)
mid = (rect.bottom() + rect.top()) / 2 mid = int((rect.bottom() + rect.top()) / 2)
painter.drawLine(rect.left(), mid, rect.right(), mid) painter.drawLine(rect.left(), mid, rect.right(), mid)
painter.end() painter.end()
else: else:
@ -193,7 +193,7 @@ class LineStyleDelegate(QtWidgets.QStyledItemDelegate):
rect = option.rect rect = option.rect
rect.adjust(+10, 0, -10, 0) rect.adjust(+10, 0, -10, 0)
mid = (rect.bottom()+rect.top()) / 2 mid = int((rect.bottom()+rect.top()) / 2)
painter.drawLine(rect.left(), mid, rect.right(), mid) painter.drawLine(rect.left(), mid, rect.right(), mid)
else: else:
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)

View File

@ -58,7 +58,7 @@ class RdBuCMap:
elif val < self.min: elif val < self.min:
col = QtGui.QColor.fromRgb(*RdBuCMap._rdbu[-1]) col = QtGui.QColor.fromRgb(*RdBuCMap._rdbu[-1])
else: else:
col = QtGui.QColor.fromRgbF(*(float(self.spline[i](val)) for i in range(3))) col = QtGui.QColor.fromRgb(*(int(self.spline[i](val)) for i in range(3)))
return col return col

View File

@ -59,6 +59,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self._fit_plot_id = None self._fit_plot_id = None
self.savefitdialog = None self.savefitdialog = None
self._tg_dialog = None self._tg_dialog = None
self.fitresult_dialog = None
self.eval = None self.eval = None
self.editor = None self.editor = None
@ -78,9 +79,11 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
if Updater.get_update_information(os.getenv('APPIMAGE'))[0]: if Updater.get_update_information(os.getenv('APPIMAGE'))[0]:
self.look_for_update() self.look_for_update()
self.check_for_backup()
self.__timer = QtCore.QTimer() self.__timer = QtCore.QTimer()
self.__backup_path = config_paths() / f'{datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S")}.nmr' self.__backup_path = config_paths() / f'{datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S")}.nmr'
self.__timer.start(3*60*1000) # every three minutese self.__timer.start(3*60*1000) # every three minutes
self.__timer.timeout.connect(self._autosave) self.__timer.timeout.connect(self._autosave)
self.fit_timer = QtCore.QTimer() self.fit_timer = QtCore.QTimer()
@ -242,6 +245,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.actionConcatenate_sets.triggered.connect(lambda: self.management.cat()) self.actionConcatenate_sets.triggered.connect(lambda: self.management.cat())
self.management.graphs.valueChanged.connect(self.update_graph_list)
@QtCore.pyqtSlot(name='on_action_open_triggered') @QtCore.pyqtSlot(name='on_action_open_triggered')
def open(self): def open(self):
@ -376,10 +380,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
if wdgt == self.current_graph_widget: if wdgt == self.current_graph_widget:
if self.ptsselectwidget.connected_figure == gid: if self.ptsselectwidget.connected_figure == gid:
self.ptsselectwidget.connected_figure = None self.ptsselectwidget.connected_figure = None
for line in self.ptsselectwidget.pts_lines:
self.current_graph_widget.remove_external(line)
self.tabWidget.removeTab(self.tabWidget.indexOf(self.ptsselectwidget)) self.tabWidget.removeTab(self.tabWidget.indexOf(self.ptsselectwidget))
if self.t1tauwidget.connected_figure == gid: if self.t1tauwidget.connected_figure == gid:
self.t1tauwidget.connected_figure = None self.t1tauwidget.connected_figure = None
self.current_graph_widget.add_external(self.t1tauwidget.min_pos)
self.current_graph_widget.add_external(self.t1tauwidget.parabola)
self.tabWidget.removeTab(self.tabWidget.indexOf(self.t1tauwidget)) self.tabWidget.removeTab(self.tabWidget.indexOf(self.t1tauwidget))
if self.fit_dialog.connected_figure == gid: if self.fit_dialog.connected_figure == gid:
@ -388,6 +397,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.current_graph_widget.remove_external(item) self.current_graph_widget.remove_external(item)
if val_figure == gid: if val_figure == gid:
self.current_graph_widget.remove_external(self.valuewidget.selection_real)
self.current_graph_widget.remove_external(self.valuewidget.selection_imag)
self.tabWidget.setCurrentIndex(0) self.tabWidget.setCurrentIndex(0)
self.current_graph_widget.enable_picking(False) self.current_graph_widget.enable_picking(False)
@ -416,6 +427,12 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
if self.area.subWindowList(): if self.area.subWindowList():
self.area.activateNextSubWindow() self.area.activateNextSubWindow()
@QtCore.pyqtSlot()
def update_graph_list(self):
graph_list = self.management.graphs.list()
self.t1tauwidget.set_graphs(graph_list)
self.ptsselectwidget.set_graphs(graph_list)
@QtCore.pyqtSlot(str) @QtCore.pyqtSlot(str)
def set_graph(self, key: str): def set_graph(self, key: str):
w = self.management.graphs[key] w = self.management.graphs[key]
@ -932,11 +949,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.fit_timer.stop() self.fit_timer.stop()
self.status.setText('') self.status.setText('')
if results: if results:
res_dialog = QFitResult(results, self.management, parent=self) if self.fitresult_dialog is None:
res_dialog.add_graphs(self.management.graphs.list()) self.fitresult_dialog = QFitResult(results, self.management, parent=self)
res_dialog.closed.connect(self.accepts_fit) self.fitresult_dialog.add_graphs(self.management.graphs.list())
res_dialog.redoFit.connect(self.management.redo_fits) self.fitresult_dialog.closed.connect(self.accepts_fit)
res_dialog.show() self.fitresult_dialog.redoFit.connect(self.management.redo_fits)
else:
self.fitresult_dialog(results)
self.fitresult_dialog.add_graphs(self.management.graphs.list())
self.fitresult_dialog.show()
@QtCore.pyqtSlot(dict, list, str, bool, bool, list) @QtCore.pyqtSlot(dict, list, str, bool, bool, list)
def accepts_fit(self, res: dict, opts: list, param_graph: str, def accepts_fit(self, res: dict, opts: list, param_graph: str,
@ -1082,6 +1103,32 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
NMRWriter(self.management.graphs, self.management.data).export(self.__backup_path) NMRWriter(self.management.graphs, self.management.data).export(self.__backup_path)
self.status.setText('') self.status.setText('')
def check_for_backup(self):
backups = []
for filename in config_paths().glob('*.nmr'):
try:
backups.append((filename, datetime.datetime.strptime(filename.stem, "%Y-%m-%d_%H%M%S")))
except ValueError:
continue
if backups:
backup_by_date = sorted(backups, key=lambda x: x[1])
msg = QtWidgets.QMessageBox.information(
self, 'Backup found',
f'{len(backups)} backup files in directory {backup_by_date[-1][0].parent} found.\n\n'
f'Latest backup date: {backup_by_date[-1][1]}\n\n'
f'Press Ok to load, Cancel to delete backup, Close to do nothing.',
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Close
)
if msg == QtWidgets.QMessageBox.Ok:
self.management.load_files([str(backup_by_date[-1][0])])
backup_by_date[-1][0].unlink()
elif msg == QtWidgets.QMessageBox.Cancel:
backup_by_date[-1][0].unlink()
else:
pass
@QtCore.pyqtSlot(name='on_actionCreate_starter_triggered') @QtCore.pyqtSlot(name='on_actionCreate_starter_triggered')
def create_starter(self): def create_starter(self):
make_starter(os.getenv('APPIMAGE')) make_starter(os.getenv('APPIMAGE'))

View File

@ -343,7 +343,7 @@ class UpperManagement(QtCore.QObject):
if joined is None: if joined is None:
joined = data_i.copy() joined = data_i.copy()
else: else:
joined.append(data_i.x, data_i.y, data_i.y_err) joined.append(data_i.data.x, data_i.data.y, y_err=data_i.data.y_err, mask=data_i.data.mask)
name_set.add(data_i.name) name_set.add(data_i.name)
group_set.add(data_i.group) group_set.add(data_i.group)
@ -653,12 +653,10 @@ class UpperManagement(QtCore.QObject):
else: else:
continue continue
for key, pvalue in data.parameter.items(): for fit_key, pvalue in data.parameter.items():
name = pvalue.full_name
fit_key = key + data.model_name
if fit_key not in fit_dict: if fit_key not in fit_dict:
fit_dict[fit_key] = [[], name] fit_dict[fit_key] = [[], fit_key]
err = 0 if pvalue.error is None else pvalue.error err = 0 if pvalue.error is None else pvalue.error

View File

@ -10,23 +10,25 @@ __all__ = ['config_paths', 'check_for_config', 'read_configuration', 'write_conf
def check_for_config(make=True): def check_for_config(make=True):
try: try:
config_paths() conf_path = config_paths()
except FileNotFoundError as e: except FileNotFoundError as e:
if make: if make:
conf_path = pathlib.Path('~/.auswerten').expanduser() conf_path = pathlib.Path('~/.auswerten').expanduser()
conf_path.mkdir(parents=True) conf_path.mkdir(parents=True)
cwd = pathlib.Path(__file__).parent
copyfile(cwd / 'models' / 'usermodels.py', conf_path / 'usermodels.py')
with resource_path('resources', 'Default.agr') as fp:
copyfile(fp, conf_path / 'Default.agr')
with resource_path('resources', 'logo.png') as fp:
copyfile(fp, conf_path / 'logo.png')
else: else:
raise e raise e
for filename in ('Default.agr', 'logo.png'):
_file = conf_path / filename
if not _file.exists():
with resource_path('resources', filename) as fp:
copyfile(fp, _file)
if not (conf_path / 'usermodels.py').exists():
cwd = pathlib.Path(__file__).parent
copyfile(cwd / 'models' / 'usermodels.py', conf_path / 'usermodels.py')
def config_paths() -> pathlib.Path: def config_paths() -> pathlib.Path:
searchpaths = ['~/.config/nmreval', '~/.auswerten', '/usr/share/nmreval'] searchpaths = ['~/.config/nmreval', '~/.auswerten', '/usr/share/nmreval']

View File

@ -484,7 +484,7 @@ class Points:
return self return self
def set_data(self, x: np.ndarray = None, y: np.ndarray = None, y_err: np.ndarray = None) -> PointLike: def set_data(self, x: np.ndarray = None, y: np.ndarray = None, y_err: np.ndarray = None, replace_mask=True) -> PointLike:
if x is None: if x is None:
x = self._x x = self._x
if y is None: if y is None:
@ -492,12 +492,17 @@ class Points:
if y_err is None: if y_err is None:
y_err = self._y_err y_err = self._y_err
self._x, self._y, self._y_err, self.mask = self._prepare_xy(x, y, y_err) self._x, self._y, self._y_err, mask = self._prepare_xy(x, y, y_err)
if replace_mask:
self.mask = mask
return self return self
def append(self, x: ArrayLike, y: ArrayLike, y_err: ArrayLike = None): def append(self, x: ArrayLike, y: ArrayLike, y_err: ArrayLike = None, mask: ArrayLike = None):
x, y, y_err, mask = self._prepare_xy(x, y, y_err) if mask is None:
x, y, y_err, mask = self._prepare_xy(x, y, y_err)
else:
x, y, y_err, _ = self._prepare_xy(x, y, y_err)
self._x = np.r_[self._x, x] self._x = np.r_[self._x, x]
self._y = np.r_[self._y, y] self._y = np.r_[self._y, y]

View File

@ -68,6 +68,7 @@ class MultiModel:
self._kwargs_right = {} self._kwargs_right = {}
self._kwargs_left = {} self._kwargs_left = {}
self.fun_kwargs = {} self.fun_kwargs = {}
self.idx = (left_idx, right_idx)
# mapping kwargs to kwargs of underlying functions # mapping kwargs to kwargs of underlying functions
self._ext_int_kw = {} self._ext_int_kw = {}
@ -178,13 +179,13 @@ class MultiModel:
if isinstance(self._left, MultiModel): if isinstance(self._left, MultiModel):
yield from self._left.sub_name() yield from self._left.sub_name()
elif hasattr(self._left, 'name'): elif hasattr(self._left, 'name'):
yield self._left.name yield f'{self._left.name}({self.idx[0]})'
else: else:
yield self.name + '(lhs)' yield self.name + '(lhs)'
if isinstance(self._right, MultiModel): if isinstance(self._right, MultiModel):
yield from self._right.sub_name() yield from self._right.sub_name()
elif hasattr(self._right, 'name'): elif hasattr(self._right, 'name'):
yield self._right.name yield f'{self._right.name}({self.idx[1]})'
else: else:
yield self.name + '(rhs)' yield self.name + '(rhs)'

View File

@ -63,9 +63,23 @@ class FitResultCreator:
parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)]) parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)])
p_final = [p.value for p in parameters.values()] p_final = [p.value for p in parameters.values()]
_y = model.func(p_final, _x, **fun_kwargs)
resid = model.func(p_final, x_orig, **fun_kwargs) - y_orig resid = model.func(p_final, x_orig, **fun_kwargs) - y_orig
actual_mode = -1
if 'complex_mode' in fun_kwargs:
actual_mode = fun_kwargs['complex_mode']
fun_kwargs['complex_mode'] = 0
_y = model.func(p_final, _x, **fun_kwargs)
if not actual_mode < 0:
if actual_mode == 1:
_y.imag = 0
elif actual_mode == 2:
_y.real = 0
fun_kwargs['complex_mode'] = actual_mode
stats = FitResultCreator.calc_statistics(_y, resid, nobs, nvar) stats = FitResultCreator.calc_statistics(_y, resid, nobs, nvar)
varied = [p.var for p in parameters.values()] varied = [p.var for p in parameters.values()]
@ -230,6 +244,7 @@ class FitResult(Points):
ret_val = '' ret_val = ''
for pval in self.parameter.values(): for pval in self.parameter.values():
print(pval)
ret_val += convert(str(pval), old='tex', new='str') + '\n' ret_val += convert(str(pval), old='tex', new='str') + '\n'
if self.fun_kwargs: if self.fun_kwargs:
@ -319,7 +334,13 @@ class FitResult(Points):
f_value = 1e318 f_value = 1e318
else: else:
f_value = (chi2-self.statistics['chi^2']) / (dof-self.dof) / self.statistics['red. chi^2'] f_value = (chi2-self.statistics['chi^2']) / (dof-self.dof) / self.statistics['red. chi^2']
return f_value, 1-fdist.cdf(f_value, dof-self.dof, self.dof)
try:
prob_f = 1-fdist.cdf(f_value, dof-self.dof, self.dof)
except:
prob_f = 0
return f_value, prob_f
def get_state(self): def get_state(self):
state = super().get_state() state = super().get_state()
@ -349,20 +370,47 @@ class FitResult(Points):
def with_new_x(self, x_values): def with_new_x(self, x_values):
if self.func is None: if self.func is None:
raise ValueError('no fit function available to calcualate new y values') raise ValueError('no fit function available to calculate new y values')
actual_mode = -1
if 'complex_mode' in self.fun_kwargs:
actual_mode = self.fun_kwargs['complex_mode']
self.fun_kwargs['complex_mode'] = 0
new_fit = self.copy() new_fit = self.copy()
y_values = self.func.func(self.p_final, x_values, **self.fun_kwargs) y_values = self.func.func(self.p_final, x_values, **self.fun_kwargs)
if not actual_mode < 0:
if actual_mode == 1:
y_values.imag = 0
elif actual_mode == 2:
y_values.real = 0
self.fun_kwargs['complex_mode'] = actual_mode
new_fit.set_data(x_values, y_values) new_fit.set_data(x_values, y_values)
return new_fit return new_fit
def sub(self, x_values): def sub(self, x_values):
part_functions = [] part_functions = []
actual_mode = -1
if 'complex_mode' in self.fun_kwargs:
actual_mode = self.fun_kwargs['complex_mode']
self.fun_kwargs['complex_mode'] = 0
for sub_name, sub_y in zip(self.func.sub_name(), self.func.sub(self.p_final, x_values, **self.fun_kwargs)): for sub_name, sub_y in zip(self.func.sub_name(), self.func.sub(self.p_final, x_values, **self.fun_kwargs)):
if np.iscomplexobj(sub_y): if not actual_mode < 0:
if actual_mode == 1:
sub_y.imag = 0
elif actual_mode == 2:
sub_y.real = 0
part_functions.append(Signal(x_values, sub_y, name=sub_name)) part_functions.append(Signal(x_values, sub_y, name=sub_name))
else: else:
part_functions.append(Points(x_values, sub_y, name=sub_name)) part_functions.append(Points(x_values, sub_y, name=sub_name))
return part_functions if actual_mode < 0:
self.fun_kwargs['complex_mode'] = actual_mode
return part_functions

View File

@ -21,10 +21,8 @@ class AsciiReader:
self.fname = None self.fname = None
self.header = [] self.header = []
self.lines = [] self.lines = []
self.num_data = []
self.delays = None self.delays = None
self.width = [] self.width = []
self.num_width = []
self.line_comment = [] self.line_comment = []
self._last_read_pos = 0 self._last_read_pos = 0
@ -45,16 +43,14 @@ class AsciiReader:
def make_preview(self, num_lines: int): def make_preview(self, num_lines: int):
if num_lines <= len(self.lines): if num_lines <= len(self.lines):
return self.lines[:num_lines], max(self.width[:num_lines]) return self.lines[:num_lines], max(self.width[:num_lines]), self.line_comment
num_lines += len(self.header) num_lines += len(self.header)
with self.fname.open('r') as f: with self.fname.open('r') as f:
for i, line in enumerate(islice(f, len(self.header)+len(self.lines), num_lines)): for i, line in enumerate(islice(f, len(self.header)+len(self.lines), num_lines)):
line = line.rstrip('\n\t\r, ') line = line.rstrip('\n\t\r, ')
is_empty = len(line) == 0
line = re.split(r'[\s,;]', line) line = re.split(r'[\s,;]', line)
try: try:
comment_start = line.index('#') comment_start = line.index('#')
self.line_comment.append(' '.join(line[comment_start:])) self.line_comment.append(' '.join(line[comment_start:]))
@ -62,14 +58,15 @@ class AsciiReader:
except ValueError: except ValueError:
self.line_comment.append('') self.line_comment.append('')
if not is_empty: is_empty = len(line) == 0
self.width.append(len(line))
self.lines.append(line)
if not line[0].startswith('#'):
self.num_data.append(line)
self.num_width.append(len(line))
return self.lines, max(self.width) if not is_empty:
self.lines.append(line)
self.width.append(len(line))
else:
self.lines.append('')
return self.lines, max(self.width), self.line_comment
def look_for_delay(self, fname=None): def look_for_delay(self, fname=None):
if fname is None: if fname is None:
@ -112,7 +109,7 @@ class AsciiReader:
raise ValueError(f'x is {type(x)} not int') raise ValueError(f'x is {type(x)} not int')
if y is None: if y is None:
y = list(range(1, max(self.num_width))) y = list(range(1, max(self.width)))
cols = x + y + yerr cols = x + y + yerr
with self.fname.open('rb') as fh: with self.fname.open('rb') as fh:
@ -122,7 +119,7 @@ class AsciiReader:
if raw_data.ndim == 1: if raw_data.ndim == 1:
# only one row or column # only one row or column
if len(self.num_data) == 1: if len(self.lines) == 1:
# one row # one row
raw_data = raw_data.reshape(1, -1) raw_data = raw_data.reshape(1, -1)
else: else:
@ -161,7 +158,7 @@ class AsciiReader:
for j in range(1, num_y+1, stepsize): for j in range(1, num_y+1, stepsize):
if col_names is not None: if col_names is not None:
# predefined name # predefined name
kwargs['name'] = col_names[j] kwargs['name'] = col_names[j-1]
elif num_y > single_len: elif num_y > single_len:
# more than one axis, append column number # more than one axis, append column number
kwargs['name'] = filename + '_' + str(y[j-1]) kwargs['name'] = filename + '_' + str(y[j-1])

View File

@ -5,6 +5,7 @@ import re
from collections import namedtuple from collections import namedtuple
import numpy as np import numpy as np
from scipy.stats import linregress
try: try:
from scipy.integrate import simpson from scipy.integrate import simpson
@ -200,35 +201,24 @@ class DSCCalibrator:
high_border = np.argmin(np.abs(measurement[0] - t_high_lim)) high_border = np.argmin(np.abs(measurement[0] - t_high_lim))
ref_zoom = measurement[:, low_border:high_border] ref_zoom = measurement[:, low_border:high_border]
x_val = np.array([[ref_zoom[0, 0], 1], [ref_zoom[0, -1], 1]])
y_val = np.array([ref_zoom[1, 0], ref_zoom[1, -1]])
sol = np.linalg.solve(x_val, y_val)
ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
ref_grad = np.gradient(ref_zoom[1])
crossing = np.where(np.diff(np.sign(np.abs(ref_grad)-0.001)))[0]
almost_flat = np.sort(crossing-np.argmax(ref_zoom[1]))
integ_limit = (almost_flat[np.where((almost_flat < -20))[0][-1]]+np.argmax(ref_zoom[1]),
almost_flat[np.where((almost_flat > 20))[0][0]]+np.argmax(ref_zoom[1]))
# subtract baseline around reference peak
sol = self.solve_linear_eq(integ_limit, ref_zoom)
ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
# calculate onset slope (use points at position of maximum gradient - 100/rate (+50/rate))
ref_grad = np.gradient(ref_zoom[1])
max_grad = np.argmax(ref_grad)
grad_pos = max_grad-max(1, int(160 / rate)), max_grad
sol = self.solve_linear_eq(grad_pos, ref_zoom)
onset = sol[0] * ref_zoom[0] + sol[1]
melts.append(-sol[1] / sol[0])
if enthalpy is not None: if enthalpy is not None:
x_val = np.array([[ref_zoom[0, 0], 1], [ref_zoom[0, -1], 1]])
y_val = np.array([ref_zoom[1, 0], ref_zoom[1, -1]])
sol = np.linalg.solve(x_val, y_val)
ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
ref_grad = np.gradient(ref_zoom[1])
crossing = np.where(np.diff(np.sign(np.abs(ref_grad)-0.001)))[0]
almost_flat = np.sort(crossing-np.argmax(ref_zoom[1]))
integ_limit = (almost_flat[np.where((almost_flat < -40))[0][-1]]+np.argmax(ref_zoom[1]),
almost_flat[np.where((almost_flat > 40))[0][0]]+np.argmax(ref_zoom[1]))
# subtract baseline around reference peak
sol = self.solve_linear_eq(integ_limit, ref_zoom)
ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
# integrate over peak to calibrate y axis # integrate over peak to calibrate y axis
# delta H in J/g: Integrate Peak over time and divide by weight # delta H in J/g: Integrate Peak over time and divide by weight
area = simpson(ref_zoom[1, integ_limit[0]:integ_limit[1]], area = simpson(ref_zoom[1, integ_limit[0]:integ_limit[1]],
@ -236,6 +226,23 @@ class DSCCalibrator:
even='avg') * 1e-3 even='avg') * 1e-3
calib_y.append(enthalpy / (area / data.weight)) calib_y.append(enthalpy / (area / data.weight))
else:
ref_grad = np.gradient(ref_zoom[1])
res = linregress(ref_zoom[0, :len(ref_grad)//5], ref_zoom[1, :len(ref_grad)//5])
ref_zoom[1] -= (res.slope*ref_zoom[0] + res.intercept)
# calculate onset slope (use points at position of maximum gradient - 100/rate (+50/rate))
ref_grad = np.gradient(ref_zoom[1])
max_grad = np.argmax(ref_grad)
grad_pos = max_grad - max(1, int(160 / rate)), max_grad
sol = self.solve_linear_eq(grad_pos, ref_zoom)
onset = sol[0] * ref_zoom[0] + sol[1]
melts.append(-sol[1] / sol[0])
results.append([ref_zoom, onset, ref_zoom[:, grad_pos]]) results.append([ref_zoom, onset, ref_zoom[:, grad_pos]])
if len(melts) > 1: if len(melts) > 1:

View File

@ -1,6 +1,8 @@
from __future__ import annotations from __future__ import annotations
import pathlib import pathlib
import subprocess
import tempfile
# import matplotlib.pyplot as plt # import matplotlib.pyplot as plt
from scipy.optimize import curve_fit from scipy.optimize import curve_fit
@ -9,6 +11,7 @@ import numpy as np
from nmreval.data.points import Points from nmreval.data.points import Points
from nmreval.io.asciireader import AsciiReader from nmreval.io.asciireader import AsciiReader
from nmreval.io.hdfreader import HdfReader from nmreval.io.hdfreader import HdfReader
from nmreval.lib.logger import logger
from nmreval.utils.utils import get_temperature, roundrobin from nmreval.utils.utils import get_temperature, roundrobin
@ -54,7 +57,7 @@ class FCReader:
_temp = self._read_from_dir(filename) _temp = self._read_from_dir(filename)
else: else:
raise TypeError raise TypeError(f'{filename} is of unknown type')
if not _temp: if not _temp:
raise OSError(-666, f'No magnetization found for {filename.name}.', filename.name) raise OSError(-666, f'No magnetization found for {filename.name}.', filename.name)
@ -130,7 +133,7 @@ class FCReader:
no_bevo = True no_bevo = True
break break
if str(k.parent) != 'ACC_ABS_FID_sig (group)': if str(k.parent) != 'ABS_ACC_FID_sig (group)':
continue continue
tevo = k.parameter['tevo'] tevo = k.parameter['tevo']
@ -141,14 +144,14 @@ class FCReader:
if bevo not in _temp: if bevo not in _temp:
_temp[bevo] = [] _temp[bevo] = []
_temp[bevo].append((tevo, *[pp[1] for pp in pts])) _temp[bevo].append((tevo, *[np.real(pp[1]) for pp in pts]))
if no_bevo: if no_bevo:
break break
if no_bevo: if no_bevo:
# hopefully only for old scripts # hopefully only for old scripts
sig = reader.get_selected('/data/B=*/ACC_ABS_FID*', dtype='signal') sig = reader.get_selected('/data/B=*/ABS_ACC_FID*', dtype='signal')
_temp = {} _temp = {}
for s in sig: for s in sig:
pts = s.points([region]) pts = s.points([region])
@ -156,7 +159,7 @@ class FCReader:
if b not in _temp: if b not in _temp:
_temp[b] = [] _temp[b] = []
_temp[b].append([s.value, *[pp[1] for pp in pts]]) _temp[b].append([s.value, *[np.real(pp[1]) for pp in pts]])
for b, m in sorted(_temp.items()): for b, m in sorted(_temp.items()):
m = np.array(m) m = np.array(m)
@ -178,6 +181,7 @@ class FCReader:
fit_path.mkdir(parents=True, exist_ok=True) fit_path.mkdir(parents=True, exist_ok=True)
if save_fig: if save_fig:
data_path = fname_no_ext.joinpath('data')
image_path = fname_no_ext.joinpath('png') image_path = fname_no_ext.joinpath('png')
image_path.mkdir(parents=True, exist_ok=True) image_path.mkdir(parents=True, exist_ok=True)
@ -188,15 +192,16 @@ class FCReader:
freqs = [] freqs = []
for k, v in sorted(self.data[temperature].items()): for k, v in sorted(self.data[temperature].items()):
freqs.append(k)
# fit # fit
p0 = [v.y[0], v.y[-1]-v.y[0], v.x[int(0.5*len(v.x) - 0.5)], 1] p0 = [v.y[0], v.y[-1]-v.y[0], v.x[int(0.5*len(v.x) - 0.5)], 1]
try: try:
p0, pcov = curve_fit(FCReader.kww, v.x, v.y, p0=p0, bounds=bounds, max_nfev=500*len(v)) p0, pcov = curve_fit(FCReader.kww, v.x, v.y, p0=p0, bounds=bounds, max_nfev=500*len(v))
except RuntimeError: except Exception as e:
logger.error(f'Fit of field {k} failed with exception', exc_info=e)
continue continue
freqs.append(k)
perr = np.sqrt(np.diag(pcov)) perr = np.sqrt(np.diag(pcov))
params.append(p0) params.append(p0)
errors.append(perr) errors.append(perr)
@ -218,16 +223,34 @@ class FCReader:
np.savetxt(fit_path.joinpath(save_name), np.c_[xplot, yplot], np.savetxt(fit_path.joinpath(save_name), np.c_[xplot, yplot],
header=header+'\t'.join([f'{p}+/-{err}' for p, err in zip(p0, perr)])) header=header+'\t'.join([f'{p}+/-{err}' for p, err in zip(p0, perr)]))
# if save_fig: if save_fig:
# fig, ax = plt.subplots() img_file = image_path.joinpath(save_name).with_suffix(".png")
# ax.set_xlabel('t / s')
# ax.set_ylabel('M') gnuplot_args = [
# axheader = f'T1: {p0[2]:.4g}(+/-{perr[2]:.4g}) beta: {p0[3]:.4g}(+/-{perr[3]:.4g})' 'set terminal png;',
# ax.set_title(f'f = {k:.4g} Hz\n{axheader}') f'set output "{img_file}";',
# ax.semilogx(v.x, v.y, 'o') f'set title "f = {k:.4g} Hz\\n{p0[2]:.4g}(+/-{perr[2]:.4g}) beta: {p0[3]:.4g}(+/-{perr[3]:.4g})";',
# ax.semilogx(xplot, yplot, '-') 'set xlabel "t / s";',
# fig.savefig(image_path.joinpath(save_name).with_suffix('.png')) 'set logscale x;',
# plt.close(fig) 'set format x "10^{{%L}}";',
'set ylabel "M";',
'set key off;',
f'plot "{data_path.joinpath(save_name)}" with points pointtype 5, "{fit_path.joinpath(save_name)}" with lines;',
]
try:
proc = subprocess.Popen(
['gnuplot', '-p'],
shell=True,
stdin=subprocess.PIPE,
encoding='utf8',
)
for args in gnuplot_args:
proc.stdin.write(args)
proc.stdin.write('quit\n')
proc.stdin.flush()
except Exception as e:
logger.error(f'saving image {save_name} failed', e)
freqs = np.asanyarray(freqs) freqs = np.asanyarray(freqs)
params = np.asanyarray(params) params = np.asanyarray(params)

View File

@ -1,9 +1,7 @@
from __future__ import annotations from __future__ import annotations
import codecs
import pathlib import pathlib
import re import re
import warnings
from io import StringIO from io import StringIO
from typing import Optional, Tuple from typing import Optional, Tuple
@ -46,6 +44,22 @@ class GraceEditor:
if filename is not None: if filename is not None:
self.parse(filename) self.parse(filename)
def _fix_tuda_colors(self):
# 2023-05-11: Default.agr had wrong TUDa colors (4a, 7b, 9b, 9d), so set the values given in colors.py
color_mapping = [
('tuda4a', (175, 204, 80)),
('tuda7b', (245, 163, 0)),
('tuda9b', (230, 0, 26)),
('tuda9d', (156, 28, 38)),
]
for i, line in enumerate(self.header):
m = self._RE_COLOR.match(line)
if m:
for name, right_color in color_mapping:
if m['disp'].lower() == name:
self.header[i] = f'@map color {m["id"]} to {right_color}, "{m["disp"]}"\n'
def __call__(self, filename: str): def __call__(self, filename: str):
self.clear() self.clear()
self.parse(filename) self.parse(filename)
@ -193,6 +207,8 @@ class GraceEditor:
self.graphs[-1].append(line) self.graphs[-1].append(line)
self._fix_tuda_colors()
def _make_graph(self, line: str): def _make_graph(self, line: str):
m = self._RE_GRAPH_START.match(line) m = self._RE_GRAPH_START.match(line)
g_idx = int(m.group(1)) g_idx = int(m.group(1))
@ -212,7 +228,6 @@ class GraceEditor:
m = self._RE_COLOR.match(line) m = self._RE_COLOR.match(line)
if m: if m:
_colors[int(m['id'])] = (m['disp'], (int(m['red']), int(m['green']), int(m['blue']))) _colors[int(m['id'])] = (m['disp'], (int(m['red']), int(m['green']), int(m['blue'])))
return _colors return _colors
def get_color(self, color_num): def get_color(self, color_num):

View File

@ -5,6 +5,8 @@ from collections import OrderedDict
from .read_old_nmr import HAS_BSDDB3, _read_file_v1 from .read_old_nmr import HAS_BSDDB3, _read_file_v1
from ..data.nmr import FID, Spectrum from ..data.nmr import FID, Spectrum
from ..data.bds import BDS
from ..data.dsc import DSC
from ..data.points import Points from ..data.points import Points
from ..fit.result import FitResult, FitResultCreator from ..fit.result import FitResult, FitResultCreator
from ..lib.colors import Colors from ..lib.colors import Colors
@ -51,11 +53,17 @@ class NMRReader:
states = pickle.load(fp) states = pickle.load(fp)
datalist = OrderedDict() datalist = OrderedDict()
_dtypes = {'pts': Points, 'fit': FitResult, 'fid': FID} _dtypes = {'pts': Points,
'fit': FitResult,
'fid': FID,
'bds': BDS,
'dsc': DSC,
'spectrum': Spectrum
}
for s in states['sets']: for s in states['sets']:
set_id = s.pop('id') set_id = s.pop('id')
dtype = _dtypes[s.pop('mode')] dtype = _dtypes.get(s.pop('mode'), FID)
data = dtype.set_state(s.pop('data')) data = dtype.set_state(s.pop('data'))
datalist[set_id] = (data, s) datalist[set_id] = (data, s)

View File

@ -247,6 +247,7 @@ class Tab10(BaseColor):
TabChartreuse = TUColorsC.TUDa5c.value TabChartreuse = TUColorsC.TUDa5c.value
TabTurquoise = TUColorsA.TUDa2a.value TabTurquoise = TUColorsA.TUDa2a.value
class Tab20(BaseColor): class Tab20(BaseColor):
TabBlue = (31, 119, 180) TabBlue = (31, 119, 180)
TabBlue2 = (174, 199, 232) TabBlue2 = (174, 199, 232)

View File

@ -64,7 +64,7 @@
@map color 2 to (93, 133, 195), "TUDa1a" @map color 2 to (93, 133, 195), "TUDa1a"
@map color 3 to (0, 156, 218), "TUDa2a" @map color 3 to (0, 156, 218), "TUDa2a"
@map color 4 to (80, 182, 149), "TUDa3a" @map color 4 to (80, 182, 149), "TUDa3a"
@map color 5 to (176, 204, 80), "TUDa4a" @map color 5 to (175, 204, 80), "TUDa4a"
@map color 6 to (221, 223, 72), "TUDa5a" @map color 6 to (221, 223, 72), "TUDa5a"
@map color 7 to (255, 224, 92), "TUDa6a" @map color 7 to (255, 224, 92), "TUDa6a"
@map color 8 to (248, 186, 60), "TUDa7a" @map color 8 to (248, 186, 60), "TUDa7a"
@ -78,9 +78,9 @@
@map color 16 to (153, 192, 0), "TUDa4b" @map color 16 to (153, 192, 0), "TUDa4b"
@map color 17 to (201, 212, 0), "TUDa5b" @map color 17 to (201, 212, 0), "TUDa5b"
@map color 18 to (253, 202, 0), "TUDa6b" @map color 18 to (253, 202, 0), "TUDa6b"
@map color 19 to (248, 163, 0), "TUDa7b" @map color 19 to (245, 163, 0), "TUDa7b"
@map color 20 to (236, 101, 0), "TUDa8b" @map color 20 to (236, 101, 0), "TUDa8b"
@map color 21 to (239, 0, 26), "TUDa9b" @map color 21 to (230, 0, 26), "TUDa9b"
@map color 22 to (166, 0, 132), "TUDa10b" @map color 22 to (166, 0, 132), "TUDa10b"
@map color 23 to (114, 16, 133), "TUDa11b" @map color 23 to (114, 16, 133), "TUDa11b"
@map color 24 to (0, 78, 138), "TUDa1c" @map color 24 to (0, 78, 138), "TUDa1c"
@ -102,7 +102,7 @@
@map color 40 to (174, 142, 0), "TUDa6d" @map color 40 to (174, 142, 0), "TUDa6d"
@map color 41 to (190, 111, 0), "TUDa7d" @map color 41 to (190, 111, 0), "TUDa7d"
@map color 42 to (169, 73, 19), "TUDa8d" @map color 42 to (169, 73, 19), "TUDa8d"
@map color 43 to (188, 28, 38), "TUDa9d" @map color 43 to (156, 28, 38), "TUDa9d"
@map color 44 to (115, 32, 84), "TUDa10d" @map color 44 to (115, 32, 84), "TUDa10d"
@map color 45 to (76, 34, 106), "TUDa11d" @map color 45 to (76, 34, 106), "TUDa11d"
@map color 46 to (220, 220, 220), "TUDa0a" @map color 46 to (220, 220, 220), "TUDa0a"

View File

@ -30,13 +30,16 @@
<number>3</number> <number>3</number>
</property> </property>
<item row="1" column="0" rowspan="2"> <item row="1" column="0" rowspan="2">
<widget class="QListWidget" name="listWidget"> <widget class="QListWidgetSelect" name="listWidget">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
@ -207,6 +210,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>QListWidgetSelect</class>
<extends>QListWidget</extends>
<header>..lib.listwidget</header>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>freq_button</tabstop> <tabstop>freq_button</tabstop>
<tabstop>temp_button</tabstop> <tabstop>temp_button</tabstop>

View File

@ -6,36 +6,39 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>864</width> <width>969</width>
<height>649</height> <height>974</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Fit results</string> <string>Fit results</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="2" column="0" colspan="2">
<widget class="ElideComboBox" name="sets_comboBox"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizePolicy"> <property name="spacing">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <number>3</number>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="maximumSize"> <item>
<size> <widget class="QCheckBox" name="reject_fit_checkBox">
<width>400</width> <property name="text">
<height>16777215</height> <string>Reject this fit</string>
</size> </property>
</property> </widget>
<property name="baseSize"> </item>
<size> <item>
<width>200</width> <widget class="QCheckBox" name="del_prev_checkBox">
<height>0</height> <property name="text">
</size> <string>Delete previous fits</string>
</property> </property>
<property name="sizeAdjustPolicy"> </widget>
<enum>QComboBox::AdjustToMinimumContentsLength</enum> </item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
@ -46,37 +49,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QTableWidget" name="param_tableWidget">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectColumns</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="columnCount">
<number>0</number>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="5" column="0" colspan="2"> <item row="5" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
@ -223,35 +195,67 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <widget class="QTableWidget" name="param_tableWidget">
<property name="spacing"> <property name="sizePolicy">
<number>3</number> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<item> <property name="horizontalScrollBarPolicy">
<widget class="QCheckBox" name="reject_fit_checkBox"> <enum>Qt::ScrollBarAsNeeded</enum>
<property name="text"> </property>
<string>Reject this fit</string> <property name="sizeAdjustPolicy">
</property> <enum>QAbstractScrollArea::AdjustIgnored</enum>
</widget> </property>
</item> <property name="editTriggers">
<item> <set>QAbstractItemView::NoEditTriggers</set>
<widget class="QCheckBox" name="del_prev_checkBox"> </property>
<property name="text"> <property name="alternatingRowColors">
<string>Delete previous fits</string> <bool>true</bool>
</property> </property>
</widget> <property name="selectionMode">
</item> <enum>QAbstractItemView::NoSelection</enum>
</layout> </property>
<property name="columnCount">
<number>1</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column/>
</widget>
</item> </item>
<item row="3" column="0" colspan="2"> <item row="0" column="0">
<widget class="Line" name="line"> <widget class="ElideComboBox" name="sets_comboBox">
<property name="orientation"> <property name="sizePolicy">
<enum>Qt::Horizontal</enum> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" rowspan="3"> <item row="0" column="1" rowspan="2">
<widget class="QTabWidget" name="stack"> <widget class="QTabWidget" name="stack">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
@ -262,7 +266,7 @@
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="stackPage1" native="true"> <widget class="QWidget" name="stackPage1">
<attribute name="title"> <attribute name="title">
<string>Plot</string> <string>Plot</string>
</attribute> </attribute>
@ -307,7 +311,7 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="stackPage2" native="true"> <widget class="QWidget" name="stackPage2">
<attribute name="title"> <attribute name="title">
<string>Statistics</string> <string>Statistics</string>
</attribute> </attribute>
@ -349,7 +353,7 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="stackPage3" native="true"> <widget class="QWidget" name="stackPage3">
<attribute name="title"> <attribute name="title">
<string>Correlations</string> <string>Correlations</string>
</attribute> </attribute>
@ -415,16 +419,16 @@
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget>
<class>GraphicsLayoutWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
<customwidget> <customwidget>
<class>ElideComboBox</class> <class>ElideComboBox</class>
<extends>QComboBox</extends> <extends>QComboBox</extends>
<header>..lib.forms</header> <header>..lib.forms</header>
</customwidget> </customwidget>
<customwidget>
<class>GraphicsLayoutWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -515,13 +515,16 @@
<number>0</number> <number>0</number>
</property> </property>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QListWidget" name="listWidget"> <widget class="QListWidgetSelect" name="listWidget">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="Maximum" vsizetype="MinimumExpanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
@ -554,6 +557,11 @@
<extends>QGraphicsView</extends> <extends>QGraphicsView</extends>
<header>pyqtgraph</header> <header>pyqtgraph</header>
</customwidget> </customwidget>
<customwidget>
<class>QListWidgetSelect</class>
<extends>QListWidget</extends>
<header>..lib.listwidget</header>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>logx_button</tabstop> <tabstop>logx_button</tabstop>

View File

@ -141,7 +141,7 @@
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QListWidget" name="listWidget"> <widget class="QListWidgetSelect" name="listWidget">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -151,6 +151,9 @@
<property name="toolTip"> <property name="toolTip">
<string>Select sets that shall be interpolated. No selection will create interpolations of all visible sets.</string> <string>Select sets that shall be interpolated. No selection will create interpolations of all visible sets.</string>
</property> </property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget> </widget>
</item> </item>
<item row="7" column="0" colspan="2"> <item row="7" column="0" colspan="2">
@ -276,6 +279,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>QListWidgetSelect</class>
<extends>QListWidget</extends>
<header>..lib.listwidget</header>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>listWidget</tabstop> <tabstop>listWidget</tabstop>
<tabstop>ylog_checkBox</tabstop> <tabstop>ylog_checkBox</tabstop>