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

View File

@ -1,13 +1,16 @@
# -*- 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
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
@ -16,12 +19,13 @@ class Ui_Dialog(object):
self.gridLayout.setContentsMargins(3, 3, 3, 3)
self.gridLayout.setSpacing(3)
self.gridLayout.setObjectName("gridLayout")
self.listWidget = QtWidgets.QListWidget(Dialog)
self.listWidget = QListWidgetSelect(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
self.listWidget.setSizePolicy(sizePolicy)
self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.listWidget.setObjectName("listWidget")
self.gridLayout.addWidget(self.listWidget, 1, 0, 2, 1)
self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
@ -93,8 +97,8 @@ class Ui_Dialog(object):
self.gridLayout.addWidget(self.label, 0, 0, 1, 2)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept)
self.buttonBox.rejected.connect(Dialog.reject)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.freq_button, self.temp_button)
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.time_checkBox.setText(_translate("Dialog", "Meas. time"))
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'
#
# 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
# 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):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(864, 649)
Dialog.resize(969, 974)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
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.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setSpacing(3)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog)
self.reject_fit_checkBox.setObjectName("reject_fit_checkBox")
self.horizontalLayout_2.addWidget(self.reject_fit_checkBox)
self.del_prev_checkBox = QtWidgets.QCheckBox(Dialog)
self.del_prev_checkBox.setObjectName("del_prev_checkBox")
self.horizontalLayout_2.addWidget(self.del_prev_checkBox)
self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 2)
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.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Retry)
self.buttonBox.setObjectName("buttonBox")
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.setObjectName("groupBox")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox)
@ -113,21 +104,34 @@ class Ui_Dialog(object):
self.horizontalLayout.addWidget(self.partial_checkBox)
self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 4)
self.gridLayout.addWidget(self.groupBox, 5, 0, 1, 2)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setSpacing(3)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog)
self.reject_fit_checkBox.setObjectName("reject_fit_checkBox")
self.horizontalLayout_2.addWidget(self.reject_fit_checkBox)
self.del_prev_checkBox = QtWidgets.QCheckBox(Dialog)
self.del_prev_checkBox.setObjectName("del_prev_checkBox")
self.horizontalLayout_2.addWidget(self.del_prev_checkBox)
self.gridLayout.addLayout(self.horizontalLayout_2, 2, 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.param_tableWidget = QtWidgets.QTableWidget(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.param_tableWidget.sizePolicy().hasHeightForWidth())
self.param_tableWidget.setSizePolicy(sizePolicy)
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.NoSelection)
self.param_tableWidget.setColumnCount(1)
self.param_tableWidget.setObjectName("param_tableWidget")
self.param_tableWidget.setRowCount(0)
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)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
@ -194,7 +198,7 @@ class Ui_Dialog(object):
self.corr_tableWidget.verticalHeader().setVisible(False)
self.verticalLayout_3.addWidget(self.corr_tableWidget)
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.stack.setCurrentIndex(0)
@ -203,6 +207,8 @@ class Ui_Dialog(object):
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
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.extrapolate_box.setToolTip(_translate("Dialog", "Extrapolates only main function"))
self.extrapolate_box.setText(_translate("Dialog", "Extrapolate curves"))
@ -215,8 +221,6 @@ class Ui_Dialog(object):
self.numx_line.setPlaceholderText(_translate("Dialog", "# pts"))
self.curve_checkbox.setText(_translate("Dialog", "Plot fit curve"))
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.logx_box.setText(_translate("Dialog", "logarithmic x axis"))
self.stack.setTabText(self.stack.indexOf(self.stackPage1), _translate("Dialog", "Plot"))

View File

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

View File

@ -1,10 +1,11 @@
# -*- 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
@ -65,12 +66,13 @@ class Ui_Dialog(object):
self.label_2 = QtWidgets.QLabel(Dialog)
self.label_2.setObjectName("label_2")
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.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
self.listWidget.setSizePolicy(sizePolicy)
self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.listWidget.setObjectName("listWidget")
self.gridLayout.addWidget(self.listWidget, 1, 0, 1, 2)
self.sampling_widget = QtWidgets.QWidget(Dialog)
@ -130,8 +132,8 @@ class Ui_Dialog(object):
self.label_8.setBuddy(self.dest_combobox)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept)
self.buttonBox.rejected.connect(Dialog.reject)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.listWidget, self.ylog_checkBox)
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.label_8.setText(_translate("Dialog", "Add interpolated data to"))
self.xlog_checkBox.setText(_translate("Dialog", "use log(x)"))
from ..lib.listwidget import QListWidgetSelect

View File

@ -1,8 +1,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
# 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.utils.text import convert
from nmreval.data.bds import BDS
from nmreval.data.dsc import DSC
from nmreval.lib.colors import BaseColor, TUColors
from nmreval.lib.lines import LineStyle
from nmreval.lib.symbols import SymbolStyle, symbolcycle
@ -44,6 +45,7 @@ class ExperimentContainer(QtCore.QObject):
self.actions = {}
self._update_actions()
@plot_update
def _init_plot(self):
raise NotImplementedError
@ -312,10 +314,8 @@ class ExperimentContainer(QtCore.QObject):
err_pen.setColor(QtGui.QColor(*self.plot_real.symbolcolor.rgb()))
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)
else:
print('Updating color failed for ' + str(self.id))
def setSymbol(self, symbol=None, color=None, size=None, mode='real'):
if mode in ['real', 'all']:
@ -460,7 +460,7 @@ class ExperimentContainer(QtCore.QObject):
return 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:
namespace.update({"fit['%s']" % (convert(pname, old='tex', new='str')): pvalue.value
@ -475,7 +475,7 @@ class ExperimentContainer(QtCore.QObject):
if c:
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']
return new_data
@ -496,6 +496,9 @@ class PointContainer(ExperimentContainer):
self.mode = 'pts'
self._init_plot(**kwargs)
if isinstance(self._data, DSC):
self.mode = 'dsc'
def _init_plot(self, **kwargs):
self.plot_imag = None
@ -532,17 +535,17 @@ class PointContainer(ExperimentContainer):
line_kwargs['style'] = LineStyle.No
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')
self.setSymbol(mode='real', **sym_kwargs)
self.setLine(mode='real', **line_kwargs)
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()}))
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()}))
@ -565,12 +568,12 @@ class FitContainer(ExperimentContainer):
if isinstance(color, BaseColor):
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}),
connect='finite', symbol=None)
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}),
connect='finite', symbol=None)
@ -603,9 +606,9 @@ class SignalContainer(ExperimentContainer):
self._init_plot(symbol=symbol, **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')
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')
color = kwargs.get('color', None)

View File

@ -187,9 +187,15 @@ class PointSelectWidget(QtWidgets.QWidget, Ui_Form):
self.peaktable.blockSignals(False)
def set_graphs(self, graphs: list):
last_graph = self.graph_combobox.currentData()
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])
if g[0] == last_graph:
idx = i
self.graph_combobox.setCurrentIndex(idx)
@QtCore.pyqtSlot(int, name='on_graph_checkbox_stateChanged')
def changed_state(self, checked):

View File

@ -188,7 +188,15 @@ class ValueEditWidget(QtWidgets.QWidget, Ui_MaskDialog):
new_value = complex(val)
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)
if prev_state == self.tableView.State.EditingState:
self.tableView.setCurrentIndex(idx)
self.tableView.edit(idx)
@QtCore.pyqtSlot(QtCore.QItemSelection, QtCore.QItemSelection)
def show_position(self, *_):
@ -259,10 +267,7 @@ class ValueModel(QtCore.QAbstractTableModel):
row = idx.row()
if role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]:
val = self._data[row][idx.column()]
if isinstance(val, complex):
return f'{val.real:.8g}{val.imag:+.8g}j'
else:
return f'{val:.8g}'
return self.as_string(val)
elif role == QtCore.Qt.BackgroundRole:
pal = QtGui.QGuiApplication.palette()
@ -295,11 +300,16 @@ class ValueModel(QtCore.QAbstractTableModel):
if value:
if role == QtCore.Qt.EditRole:
if value == self.as_string(self._data[row][col]):
return True
try:
value = complex(value)
except ValueError:
# not a number
return False
value = 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.dataChanged.emit(self.index(0, 0), self.index(0, 1), [role])
@ -368,3 +378,10 @@ class ValueModel(QtCore.QAbstractTableModel):
def unmask(self):
self.mask = [True] * self.total_rows
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]):
w = self.data_parameter[i]
w.blockSignals(True)
try:
w.show_as_local_parameter(value is not None)
except AttributeError:
pass
if value is None:
w.value = self.glob_values[i]
else:
@ -263,17 +268,17 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
return data_parameter, lb, ub, is_fixed, global_p, is_linked
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:
for val, g in zip(parameter, self.global_parameter):
if isinstance(g, SelectionWidget):
continue
for i, g in enumerate(num_parameter):
val = parameter[i]
g.set_parameter(val)
self.glob_values[i] = val
else:
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):
new_param[i] = parameter[i]
@ -293,6 +298,7 @@ class ParameterSingleWidget(QtWidgets.QWidget):
self._name = 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.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))
self.value_line = QtWidgets.QLineEdit(self)
self.value_line.textEdited.connect(lambda x: self.show_as_local_parameter(True))
layout.addWidget(self.value_line)
self.reset_button = QtWidgets.QToolButton(self)
self.reset_button.setText('Use global')
self.reset_button.clicked.connect(lambda: self.show_as_local_parameter(False))
layout.addWidget(self.reset_button)
self.setLayout(layout)
@ -327,3 +335,9 @@ class ParameterSingleWidget(QtWidgets.QWidget):
@value.setter
def value(self, val):
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()
del self.param_widgets[idx]
if len(self.functionwidget) == 0:
self._current_function = None
if len(self.param_widgets) == 0:
# empty model
self.newmodel_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)
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.numx_line.setEnabled(x))
self._prevs = {}
self._models = {}
self._previous_fits = {}
self._opts = []
self._results = {}
self.graph_opts = {}
self.last_idx = None
for res in results:
idx = res.idx
data_k = management.data[idx]
self.resid_plot = self.graphicsView.addPlot(row=0, col=0, title='Residual')
self.fit_plot = self.graphicsView.addPlot(row=1, col=0, title='Fit')
if res.name not in self._models:
self._models[res.name] = []
self.graphicsView.ci.layout.setRowStretchFactor(0, 1)
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=[],
symbol='o', symbolPen=None, symbolBrush=mkBrush(color=(31, 119, 180)),
pen=None)
self.resid_graph_imag = PlotItem(x=[], y=[],
symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)),
pen=None)
self.residplot.addItem(self.resid_graph)
self.residplot.addItem(self.resid_graph_imag)
self.residplot.setLabel('left', 'Residual')
self.resid_plot.addItem(self.resid_graph)
self.resid_plot.addItem(self.resid_graph_imag)
self.fitplot = self.graphicsView.addPlot(row=1, col=0)
self.data_graph = PlotItem(x=[], y=[],
symbol='o', symbolPen=None, symbolBrush=mkBrush(color=(31, 119, 180)),
pen=None)
self.data_graph_imag = PlotItem(x=[], y=[],
symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)),
pen=None)
self.fitplot.addItem(self.data_graph)
self.fitplot.addItem(self.data_graph_imag)
self.fitplot.setLabel('left', 'Function')
self.fit_plot.addItem(self.data_graph)
self.fit_plot.addItem(self.data_graph_imag)
self.fit_graph = PlotItem(x=[], y=[])
self.fit_graph_imag = PlotItem(x=[], y=[])
self.fitplot.addItem(self.fit_graph)
self.fitplot.addItem(self.fit_graph_imag)
self.fit_plot.addItem(self.fit_graph)
self.fit_plot.addItem(self.fit_graph_imag)
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.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.logy_box.stateChanged.connect(lambda x: self.fitplot.setLogMode(y=bool(x)))
self.logx_box.stateChanged.connect(lambda x: self.fitplot.setLogMode(x=bool(x)))
self.residplot.setXLink(self.fitplot)
self.logy_box.stateChanged.connect(lambda x: self.fit_plot.setLogMode(y=bool(x)))
self.logx_box.stateChanged.connect(lambda x: self.fit_plot.setLogMode(x=bool(x)))
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):
self.graph_comboBox.clear()
@ -99,56 +109,40 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
@QtCore.pyqtSlot(int, name='on_sets_comboBox_currentIndexChanged')
def set_parameter(self, idx: int):
model_name = self.sets_comboBox.itemText(idx)
sets = self._models[model_name]
self.param_tableWidget.setColumnCount(len(sets))
set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.UserRole)
r = self._results[sets[0]]
self.param_tableWidget.setRowCount(len(r.parameter))
res = self._results[set_id]
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()):
name = pval.full_name
p_header = QtWidgets.QTableWidgetItem(convert(name, 'tex', 'html', brackets=False))
self.param_tableWidget.setVerticalHeaderItem(i, p_header)
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, 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):
data_i = self._management[set_id]
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)
self.param_tableWidget.resizeColumnToContents(0)
self.show_results(idx)
@QtCore.pyqtSlot(int, name='on_reject_fit_checkBox_stateChanged')
@QtCore.pyqtSlot(int, name='on_del_prev_checkBox_stateChanged')
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.del_prev_checkBox.checkState() == QtCore.Qt.Checked)
def show_results(self, item, idx=None):
if item is not None:
idx = self.param_tableWidget.indexFromItem(item).column()
set_id = self.param_tableWidget.horizontalHeaderItem(idx).data(QtCore.Qt.UserRole)
def show_results(self, idx):
set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.UserRole)
self.set_plot(set_id)
self.set_correlation(set_id)
self.set_statistics(set_id)
self.reject_fit_checkBox.blockSignals(True)
self.reject_fit_checkBox.setChecked(self._opts[idx][0])
self.reject_fit_checkBox.blockSignals(False)
@ -157,13 +151,21 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.del_prev_checkBox.blockSignals(False)
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]
iscomplex = res.iscomplex
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]:
self.fitplot.removeItem(item)
self.fit_plot.removeItem(item)
if iscomplex:
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_imag.setData(x=res.x_data, y=res.residual.imag)
for f in sub_funcs:
item = PlotItem(x=f.x, y=f.y.real)
self.fitplot.addItem(item)
item = PlotItem(x=f.x, y=f.y.imag)
self.fitplot.addItem(item)
for i, f in enumerate(sub_funcs):
item = PlotItem(x=f.x, y=f.y.real, pen=mkPen({'color': i, 'style': 2}))
self.fit_plot.addItem(item)
item = PlotItem(x=f.x, y=f.y.imag, pen=mkPen({'color': i, 'style': 2}))
self.fit_plot.addItem(item)
else:
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_imag.setData(x=[], y=[])
for f in sub_funcs:
item = PlotItem(x=f.x, y=f.y, pen=mkPen({'style': 2}))
self.fitplot.addItem(item)
for i, f in enumerate(sub_funcs):
item = PlotItem(x=f.x, y=f.y, pen=mkPen({'color': i, 'style': 2}))
self.fit_plot.addItem(item)
self.fitplot.setLogMode(x=res.islog)
self.residplot.setLogMode(x=res.islog)
self.logx_box.blockSignals(True)
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):
while self.corr_tableWidget.rowCount():
@ -223,7 +240,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
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)
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.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))
it = QtWidgets.QTableWidgetItem(f'{dof}')
it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable)
@ -245,7 +262,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
best_idx = -1
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']:
best_idx = col if best_val < stats[k] else max(0, best_idx)
else:
@ -265,7 +282,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
self.stats_tableWidget.setVerticalHeaderItem(row+1, QtWidgets.QTableWidgetItem('Pr(>F)'))
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)
it = QtWidgets.QTableWidgetItem(f'{f_value:.4g}')
it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable)
@ -312,7 +329,6 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
except TypeError:
pass
self.closed.emit(self._results, self._opts, graph, plot_fits, parts, extrapolate)
self.accept()
@ -348,7 +364,7 @@ class FitExtension(QtWidgets.QDialog):
self.buttonBox = QtWidgets.QDialogButtonBox()
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)
self.setLayout(gridLayout)
@ -365,4 +381,4 @@ class FitExtension(QtWidgets.QDialog):
except TypeError:
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')
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.setColumnCount(width)
self.ascii_table.setColumnCount(width + 1)
for i, line in enumerate(preview):
comment_line = comments[i]
for j, field in enumerate(line):
it = QtWidgets.QTableWidgetItem(field)
self.ascii_table.setItem(i, j, it)
it = QtWidgets.QTableWidgetItem(comment_line)
self.ascii_table.setItem(i, len(line), it)
self.ascii_table.resizeColumnsToContents()
@QtCore.pyqtSlot(int, name='on_column_checkBox_stateChanged')

View File

@ -55,9 +55,9 @@ class GraceExporter:
break
if c_num == -1:
c_num = max(colors.keys())
colors[c_num + 1] = (f'color{c_num + 1}', sc)
new_colors.append((c_num + 1, f'color{c_num + 1}', sc))
c_num = max(colors.keys())+1
colors[c_num] = (f'color{c_num}', 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,
'fill color': c_num, 'fill pattern': 1})

View File

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

View File

@ -42,7 +42,7 @@ class PropertyDelegate(QtWidgets.QStyledItemDelegate):
painter.setPen(pen)
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()
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,
opt, QtWidgets.QStyle.SC_ComboBoxEditField, None)
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.end()
else:
@ -193,7 +193,7 @@ class LineStyleDelegate(QtWidgets.QStyledItemDelegate):
rect = option.rect
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)
else:
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)

View File

@ -58,7 +58,7 @@ class RdBuCMap:
elif val < self.min:
col = QtGui.QColor.fromRgb(*RdBuCMap._rdbu[-1])
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

View File

@ -59,6 +59,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self._fit_plot_id = None
self.savefitdialog = None
self._tg_dialog = None
self.fitresult_dialog = None
self.eval = None
self.editor = None
@ -78,9 +79,11 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
if Updater.get_update_information(os.getenv('APPIMAGE'))[0]:
self.look_for_update()
self.check_for_backup()
self.__timer = QtCore.QTimer()
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.fit_timer = QtCore.QTimer()
@ -242,6 +245,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
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')
def open(self):
@ -376,10 +380,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
if wdgt == self.current_graph_widget:
if self.ptsselectwidget.connected_figure == gid:
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))
if self.t1tauwidget.connected_figure == gid:
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))
if self.fit_dialog.connected_figure == gid:
@ -388,6 +397,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.current_graph_widget.remove_external(item)
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.current_graph_widget.enable_picking(False)
@ -416,6 +427,12 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
if self.area.subWindowList():
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)
def set_graph(self, key: str):
w = self.management.graphs[key]
@ -932,11 +949,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.fit_timer.stop()
self.status.setText('')
if results:
res_dialog = QFitResult(results, self.management, parent=self)
res_dialog.add_graphs(self.management.graphs.list())
res_dialog.closed.connect(self.accepts_fit)
res_dialog.redoFit.connect(self.management.redo_fits)
res_dialog.show()
if self.fitresult_dialog is None:
self.fitresult_dialog = QFitResult(results, self.management, parent=self)
self.fitresult_dialog.add_graphs(self.management.graphs.list())
self.fitresult_dialog.closed.connect(self.accepts_fit)
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)
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)
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')
def create_starter(self):
make_starter(os.getenv('APPIMAGE'))

View File

@ -343,7 +343,7 @@ class UpperManagement(QtCore.QObject):
if joined is None:
joined = data_i.copy()
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)
group_set.add(data_i.group)
@ -653,12 +653,10 @@ class UpperManagement(QtCore.QObject):
else:
continue
for key, pvalue in data.parameter.items():
name = pvalue.full_name
fit_key = key + data.model_name
for fit_key, pvalue in data.parameter.items():
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

View File

@ -10,23 +10,25 @@ __all__ = ['config_paths', 'check_for_config', 'read_configuration', 'write_conf
def check_for_config(make=True):
try:
config_paths()
conf_path = config_paths()
except FileNotFoundError as e:
if make:
conf_path = pathlib.Path('~/.auswerten').expanduser()
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:
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:
searchpaths = ['~/.config/nmreval', '~/.auswerten', '/usr/share/nmreval']

View File

@ -484,7 +484,7 @@ class Points:
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:
x = self._x
if y is None:
@ -492,12 +492,17 @@ class Points:
if y_err is None:
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
def append(self, x: ArrayLike, y: ArrayLike, y_err: ArrayLike = None):
x, y, y_err, mask = self._prepare_xy(x, y, y_err)
def append(self, x: ArrayLike, y: ArrayLike, y_err: ArrayLike = None, mask: ArrayLike = None):
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._y = np.r_[self._y, y]

View File

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

View File

@ -63,9 +63,23 @@ class FitResultCreator:
parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)])
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
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)
varied = [p.var for p in parameters.values()]
@ -230,6 +244,7 @@ class FitResult(Points):
ret_val = ''
for pval in self.parameter.values():
print(pval)
ret_val += convert(str(pval), old='tex', new='str') + '\n'
if self.fun_kwargs:
@ -319,7 +334,13 @@ class FitResult(Points):
f_value = 1e318
else:
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):
state = super().get_state()
@ -349,20 +370,47 @@ class FitResult(Points):
def with_new_x(self, x_values):
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()
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)
return new_fit
def sub(self, x_values):
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)):
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))
else:
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.header = []
self.lines = []
self.num_data = []
self.delays = None
self.width = []
self.num_width = []
self.line_comment = []
self._last_read_pos = 0
@ -45,16 +43,14 @@ class AsciiReader:
def make_preview(self, num_lines: int):
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)
with self.fname.open('r') as f:
for i, line in enumerate(islice(f, len(self.header)+len(self.lines), num_lines)):
line = line.rstrip('\n\t\r, ')
is_empty = len(line) == 0
line = re.split(r'[\s,;]', line)
try:
comment_start = line.index('#')
self.line_comment.append(' '.join(line[comment_start:]))
@ -62,14 +58,15 @@ class AsciiReader:
except ValueError:
self.line_comment.append('')
if not is_empty:
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))
is_empty = len(line) == 0
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):
if fname is None:
@ -112,7 +109,7 @@ class AsciiReader:
raise ValueError(f'x is {type(x)} not int')
if y is None:
y = list(range(1, max(self.num_width)))
y = list(range(1, max(self.width)))
cols = x + y + yerr
with self.fname.open('rb') as fh:
@ -122,7 +119,7 @@ class AsciiReader:
if raw_data.ndim == 1:
# only one row or column
if len(self.num_data) == 1:
if len(self.lines) == 1:
# one row
raw_data = raw_data.reshape(1, -1)
else:
@ -161,7 +158,7 @@ class AsciiReader:
for j in range(1, num_y+1, stepsize):
if col_names is not None:
# predefined name
kwargs['name'] = col_names[j]
kwargs['name'] = col_names[j-1]
elif num_y > single_len:
# more than one axis, append column number
kwargs['name'] = filename + '_' + str(y[j-1])

View File

@ -5,6 +5,7 @@ import re
from collections import namedtuple
import numpy as np
from scipy.stats import linregress
try:
from scipy.integrate import simpson
@ -200,35 +201,24 @@ class DSCCalibrator:
high_border = np.argmin(np.abs(measurement[0] - t_high_lim))
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:
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
# delta H in J/g: Integrate Peak over time and divide by weight
area = simpson(ref_zoom[1, integ_limit[0]:integ_limit[1]],
@ -236,6 +226,23 @@ class DSCCalibrator:
even='avg') * 1e-3
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]])
if len(melts) > 1:

View File

@ -1,6 +1,8 @@
from __future__ import annotations
import pathlib
import subprocess
import tempfile
# import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
@ -9,6 +11,7 @@ import numpy as np
from nmreval.data.points import Points
from nmreval.io.asciireader import AsciiReader
from nmreval.io.hdfreader import HdfReader
from nmreval.lib.logger import logger
from nmreval.utils.utils import get_temperature, roundrobin
@ -54,7 +57,7 @@ class FCReader:
_temp = self._read_from_dir(filename)
else:
raise TypeError
raise TypeError(f'{filename} is of unknown type')
if not _temp:
raise OSError(-666, f'No magnetization found for {filename.name}.', filename.name)
@ -130,7 +133,7 @@ class FCReader:
no_bevo = True
break
if str(k.parent) != 'ACC_ABS_FID_sig (group)':
if str(k.parent) != 'ABS_ACC_FID_sig (group)':
continue
tevo = k.parameter['tevo']
@ -141,14 +144,14 @@ class FCReader:
if bevo not in _temp:
_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:
break
if no_bevo:
# 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 = {}
for s in sig:
pts = s.points([region])
@ -156,7 +159,7 @@ class FCReader:
if b not in _temp:
_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()):
m = np.array(m)
@ -178,6 +181,7 @@ class FCReader:
fit_path.mkdir(parents=True, exist_ok=True)
if save_fig:
data_path = fname_no_ext.joinpath('data')
image_path = fname_no_ext.joinpath('png')
image_path.mkdir(parents=True, exist_ok=True)
@ -188,15 +192,16 @@ class FCReader:
freqs = []
for k, v in sorted(self.data[temperature].items()):
freqs.append(k)
# fit
p0 = [v.y[0], v.y[-1]-v.y[0], v.x[int(0.5*len(v.x) - 0.5)], 1]
try:
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
freqs.append(k)
perr = np.sqrt(np.diag(pcov))
params.append(p0)
errors.append(perr)
@ -218,16 +223,34 @@ class FCReader:
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)]))
# if save_fig:
# fig, ax = plt.subplots()
# ax.set_xlabel('t / s')
# ax.set_ylabel('M')
# axheader = f'T1: {p0[2]:.4g}(+/-{perr[2]:.4g}) beta: {p0[3]:.4g}(+/-{perr[3]:.4g})'
# ax.set_title(f'f = {k:.4g} Hz\n{axheader}')
# ax.semilogx(v.x, v.y, 'o')
# ax.semilogx(xplot, yplot, '-')
# fig.savefig(image_path.joinpath(save_name).with_suffix('.png'))
# plt.close(fig)
if save_fig:
img_file = image_path.joinpath(save_name).with_suffix(".png")
gnuplot_args = [
'set terminal png;',
f'set output "{img_file}";',
f'set title "f = {k:.4g} Hz\\n{p0[2]:.4g}(+/-{perr[2]:.4g}) beta: {p0[3]:.4g}(+/-{perr[3]:.4g})";',
'set xlabel "t / s";',
'set logscale x;',
'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)
params = np.asanyarray(params)

View File

@ -1,9 +1,7 @@
from __future__ import annotations
import codecs
import pathlib
import re
import warnings
from io import StringIO
from typing import Optional, Tuple
@ -46,6 +44,22 @@ class GraceEditor:
if filename is not None:
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):
self.clear()
self.parse(filename)
@ -193,6 +207,8 @@ class GraceEditor:
self.graphs[-1].append(line)
self._fix_tuda_colors()
def _make_graph(self, line: str):
m = self._RE_GRAPH_START.match(line)
g_idx = int(m.group(1))
@ -212,7 +228,6 @@ class GraceEditor:
m = self._RE_COLOR.match(line)
if m:
_colors[int(m['id'])] = (m['disp'], (int(m['red']), int(m['green']), int(m['blue'])))
return _colors
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 ..data.nmr import FID, Spectrum
from ..data.bds import BDS
from ..data.dsc import DSC
from ..data.points import Points
from ..fit.result import FitResult, FitResultCreator
from ..lib.colors import Colors
@ -51,11 +53,17 @@ class NMRReader:
states = pickle.load(fp)
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']:
set_id = s.pop('id')
dtype = _dtypes[s.pop('mode')]
dtype = _dtypes.get(s.pop('mode'), FID)
data = dtype.set_state(s.pop('data'))
datalist[set_id] = (data, s)

View File

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

View File

@ -64,7 +64,7 @@
@map color 2 to (93, 133, 195), "TUDa1a"
@map color 3 to (0, 156, 218), "TUDa2a"
@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 7 to (255, 224, 92), "TUDa6a"
@map color 8 to (248, 186, 60), "TUDa7a"
@ -78,9 +78,9 @@
@map color 16 to (153, 192, 0), "TUDa4b"
@map color 17 to (201, 212, 0), "TUDa5b"
@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 21 to (239, 0, 26), "TUDa9b"
@map color 21 to (230, 0, 26), "TUDa9b"
@map color 22 to (166, 0, 132), "TUDa10b"
@map color 23 to (114, 16, 133), "TUDa11b"
@map color 24 to (0, 78, 138), "TUDa1c"
@ -102,7 +102,7 @@
@map color 40 to (174, 142, 0), "TUDa6d"
@map color 41 to (190, 111, 0), "TUDa7d"
@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 45 to (76, 34, 106), "TUDa11d"
@map color 46 to (220, 220, 220), "TUDa0a"

View File

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

View File

@ -6,36 +6,39 @@
<rect>
<x>0</x>
<y>0</y>
<width>864</width>
<height>649</height>
<width>969</width>
<height>974</height>
</rect>
</property>
<property name="windowTitle">
<string>Fit results</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="ElideComboBox" name="sets_comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>3</number>
</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>
<item>
<widget class="QCheckBox" name="reject_fit_checkBox">
<property name="text">
<string>Reject this fit</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="del_prev_checkBox">
<property name="text">
<string>Delete previous fits</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
@ -46,37 +49,6 @@
</property>
</widget>
</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">
<widget class="QGroupBox" name="groupBox">
<property name="title">
@ -223,35 +195,67 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>3</number>
<item row="1" column="0">
<widget class="QTableWidget" name="param_tableWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<widget class="QCheckBox" name="reject_fit_checkBox">
<property name="text">
<string>Reject this fit</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="del_prev_checkBox">
<property name="text">
<string>Delete previous fits</string>
</property>
</widget>
</item>
</layout>
<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::NoSelection</enum>
</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 row="3" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="0" column="0">
<widget class="ElideComboBox" name="sets_comboBox">
<property name="sizePolicy">
<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>
</widget>
</item>
<item row="0" column="1" rowspan="3">
<item row="0" column="1" rowspan="2">
<widget class="QTabWidget" name="stack">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
@ -262,7 +266,7 @@
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="stackPage1" native="true">
<widget class="QWidget" name="stackPage1">
<attribute name="title">
<string>Plot</string>
</attribute>
@ -307,7 +311,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="stackPage2" native="true">
<widget class="QWidget" name="stackPage2">
<attribute name="title">
<string>Statistics</string>
</attribute>
@ -349,7 +353,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="stackPage3" native="true">
<widget class="QWidget" name="stackPage3">
<attribute name="title">
<string>Correlations</string>
</attribute>
@ -415,16 +419,16 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GraphicsLayoutWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
<customwidget>
<class>ElideComboBox</class>
<extends>QComboBox</extends>
<header>..lib.forms</header>
</customwidget>
<customwidget>
<class>GraphicsLayoutWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

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

View File

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