fitresult window is reused and remembers fitplot range/log; closes #65

add color to sub-functions in fit result window
Fitresult window shows one set at a time, more space for plot; closes #66
This commit is contained in:
Dominik Demuth 2023-05-12 20:13:56 +02:00
parent edf858da29
commit 45d319834b
6 changed files with 281 additions and 237 deletions

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(864, 712)
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)
@ -149,10 +153,18 @@ class Ui_Dialog(object):
self.logx_box.setLayoutDirection(QtCore.Qt.RightToLeft) self.logx_box.setLayoutDirection(QtCore.Qt.RightToLeft)
self.logx_box.setObjectName("logx_box") self.logx_box.setObjectName("logx_box")
self.gridLayout_3.addWidget(self.logx_box, 2, 0, 1, 1) self.gridLayout_3.addWidget(self.logx_box, 2, 0, 1, 1)
self.graphicsView = GraphicsLayoutWidget(self.stackPage1) self.fit_plot = PlotWidget(self.stackPage1)
self.graphicsView.setObjectName("graphicsView") self.fit_plot.setObjectName("fit_plot")
self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 2) self.gridLayout_3.addWidget(self.fit_plot, 0, 0, 1, 2)
self.stack.addTab(self.stackPage1, "") self.stack.addTab(self.stackPage1, "")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.verticalLayout = QtWidgets.QVBoxLayout(self.tab)
self.verticalLayout.setObjectName("verticalLayout")
self.resid_plot = PlotWidget(self.tab)
self.resid_plot.setObjectName("resid_plot")
self.verticalLayout.addWidget(self.resid_plot)
self.stack.addTab(self.tab, "")
self.stackPage2 = QtWidgets.QWidget() self.stackPage2 = QtWidgets.QWidget()
self.stackPage2.setObjectName("stackPage2") self.stackPage2.setObjectName("stackPage2")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.stackPage2) self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.stackPage2)
@ -194,7 +206,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 +215,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,11 +229,10 @@ 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"))
self.stack.setTabText(self.stack.indexOf(self.tab), _translate("Dialog", "Residuals"))
self.stack.setTabText(self.stack.indexOf(self.stackPage2), _translate("Dialog", "Statistics")) self.stack.setTabText(self.stack.indexOf(self.stackPage2), _translate("Dialog", "Statistics"))
item = self.corr_tableWidget.horizontalHeaderItem(0) item = self.corr_tableWidget.horizontalHeaderItem(0)
item.setText(_translate("Dialog", "Parameter 1")) item.setText(_translate("Dialog", "Parameter 1"))
@ -231,4 +244,4 @@ class Ui_Dialog(object):
item.setText(_translate("Dialog", "Partial Corr.")) item.setText(_translate("Dialog", "Partial Corr."))
self.stack.setTabText(self.stack.indexOf(self.stackPage3), _translate("Dialog", "Correlations")) self.stack.setTabText(self.stack.indexOf(self.stackPage3), _translate("Dialog", "Correlations"))
from ..lib.forms import ElideComboBox from ..lib.forms import ElideComboBox
from pyqtgraph import GraphicsLayoutWidget from pyqtgraph import PlotWidget

View File

@ -27,70 +27,76 @@ 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:
idx = res.idx
data_k = management.data[idx]
if res.name not in self._models:
self._models[res.name] = []
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.resid_plot.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_plot.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 +105,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, pvalue in enumerate(res.parameter.values()):
name = pvalue.name
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 +147,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.getPlotItem().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.plotItem.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 +171,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 +185,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 +236,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 +244,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 +258,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 +278,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 +325,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 +360,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)

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

@ -55,7 +55,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.fitlimitvalues = [None, None] self.fitlimitvalues = [None, None]
self.fitpreview = [] self.fitpreview = []
self._fit_plot_id = None self._fit_plot_id = None
self.savefitdialog = None self.fitresult_dialog = None
self.eval = None self.eval = None
self.editor = None self.editor = None
@ -77,7 +77,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
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()
@ -920,11 +920,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,

View File

@ -230,6 +230,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:

View File

@ -7,35 +7,38 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>864</width> <width>864</width>
<height>649</height> <height>712</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>
@ -303,11 +307,21 @@
</widget> </widget>
</item> </item>
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<widget class="GraphicsLayoutWidget" name="graphicsView"/> <widget class="PlotWidget" name="fit_plot"/>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="stackPage2" native="true"> <widget class="QWidget" name="tab">
<attribute name="title">
<string>Residuals</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="PlotWidget" name="resid_plot"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="stackPage2">
<attribute name="title"> <attribute name="title">
<string>Statistics</string> <string>Statistics</string>
</attribute> </attribute>
@ -349,7 +363,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 +429,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>PlotWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>