From 58e86f4abc2fe6c09d14d7548b3eb4a7e988bb17 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Tue, 2 Jan 2024 10:10:49 +0000 Subject: [PATCH] bugfixes-01012024 (#197) Co-authored-by: Dominik Demuth Reviewed-on: https://gitea.pkm.physik.tu-darmstadt.de/IPKM/nmreval/pulls/197 --- src/gui_qt/_py/fitresult.py | 97 +++++++++++------ src/gui_qt/_py/graph.py | 7 +- src/gui_qt/fit/result.py | 64 ++++++++--- src/gui_qt/graphs/graphwindow.py | 53 ++++++--- src/gui_qt/io/fcbatchreader.py | 4 +- src/gui_qt/lib/spinboxes.py | 4 +- src/nmreval/models/bds.py | 41 +++++-- src/resources/_ui/fitresult.ui | 181 ++++++++++++++++++++----------- src/resources/_ui/graph.ui | 18 ++- 9 files changed, 315 insertions(+), 154 deletions(-) diff --git a/src/gui_qt/_py/fitresult.py b/src/gui_qt/_py/fitresult.py index 1e62a66..54becc9 100644 --- a/src/gui_qt/_py/fitresult.py +++ b/src/gui_qt/_py/fitresult.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'src/resources/_ui/fitresult.ui' +# Form implementation generated from reading ui file 'resources/_ui/fitresult.ui' # # Created by: PyQt5 UI code generator 5.15.10 # @@ -27,25 +27,48 @@ class Ui_Dialog(object): self.stackPage1 = QtWidgets.QWidget() self.stackPage1.setObjectName("stackPage1") self.gridLayout_3 = QtWidgets.QGridLayout(self.stackPage1) - self.gridLayout_3.setContentsMargins(3, 3, 3, 3) + self.gridLayout_3.setContentsMargins(6, 3, 6, 3) self.gridLayout_3.setSpacing(3) self.gridLayout_3.setObjectName("gridLayout_3") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem, 2, 3, 1, 1) self.autoscale_box = QtWidgets.QToolButton(self.stackPage1) self.autoscale_box.setObjectName("autoscale_box") - self.gridLayout_3.addWidget(self.autoscale_box, 2, 0, 1, 1) - self.logy_box = QtWidgets.QCheckBox(self.stackPage1) - self.logy_box.setLayoutDirection(QtCore.Qt.LeftToRight) - self.logy_box.setObjectName("logy_box") - self.gridLayout_3.addWidget(self.logy_box, 2, 3, 1, 1) - self.graphicsView = GraphicsLayoutWidget(self.stackPage1) - self.graphicsView.setObjectName("graphicsView") - self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 4) - self.logx_box = QtWidgets.QCheckBox(self.stackPage1) + self.gridLayout_3.addWidget(self.autoscale_box, 2, 4, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem1, 2, 1, 1, 1) + self.verticalGroupBox_2 = QtWidgets.QGroupBox(self.stackPage1) + self.verticalGroupBox_2.setObjectName("verticalGroupBox_2") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.verticalGroupBox_2) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.logx_box = QtWidgets.QCheckBox(self.verticalGroupBox_2) self.logx_box.setLayoutDirection(QtCore.Qt.LeftToRight) self.logx_box.setObjectName("logx_box") - self.gridLayout_3.addWidget(self.logx_box, 2, 2, 1, 1) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.gridLayout_3.addItem(spacerItem, 2, 1, 1, 1) + self.verticalLayout_4.addWidget(self.logx_box) + self.logy_box = QtWidgets.QCheckBox(self.verticalGroupBox_2) + self.logy_box.setLayoutDirection(QtCore.Qt.LeftToRight) + self.logy_box.setObjectName("logy_box") + self.verticalLayout_4.addWidget(self.logy_box) + self.gridLayout_3.addWidget(self.verticalGroupBox_2, 2, 2, 1, 1) + self.verticalGroupBox = QtWidgets.QGroupBox(self.stackPage1) + self.verticalGroupBox.setObjectName("verticalGroupBox") + self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalGroupBox) + self.verticalLayout.setObjectName("verticalLayout") + self.rel_dev_button = QtWidgets.QRadioButton(self.verticalGroupBox) + self.rel_dev_button.setObjectName("rel_dev_button") + self.buttonGroup = QtWidgets.QButtonGroup(Dialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.rel_dev_button) + self.verticalLayout.addWidget(self.rel_dev_button) + self.abs_dev_button = QtWidgets.QRadioButton(self.verticalGroupBox) + self.abs_dev_button.setChecked(True) + self.abs_dev_button.setObjectName("abs_dev_button") + self.buttonGroup.addButton(self.abs_dev_button) + self.verticalLayout.addWidget(self.abs_dev_button) + self.gridLayout_3.addWidget(self.verticalGroupBox, 2, 0, 1, 1) + self.graphicsView = GraphicsLayoutWidget(self.stackPage1) + self.graphicsView.setObjectName("graphicsView") + self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 5) self.stack.addTab(self.stackPage1, "") self.stackPage2 = QtWidgets.QWidget() self.stackPage2.setObjectName("stackPage2") @@ -89,10 +112,6 @@ class Ui_Dialog(object): self.verticalLayout_3.addWidget(self.corr_tableWidget) self.stack.addTab(self.stackPage3, "") self.gridLayout.addWidget(self.stack, 0, 1, 5, 1) - 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, 8, 0, 1, 2) self.param_tableWidget = QtWidgets.QTableWidget(Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -118,6 +137,20 @@ class Ui_Dialog(object): self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.line.setObjectName("line") self.gridLayout.addWidget(self.line, 5, 0, 1, 2) + 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.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog) + self.reject_fit_checkBox.setObjectName("reject_fit_checkBox") + self.gridLayout.addWidget(self.reject_fit_checkBox, 2, 0, 1, 1) self.groupBox = QtWidgets.QGroupBox(Dialog) self.groupBox.setObjectName("groupBox") self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox) @@ -186,20 +219,10 @@ 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, 7, 0, 1, 2) - 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.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog) - self.reject_fit_checkBox.setObjectName("reject_fit_checkBox") - self.gridLayout.addWidget(self.reject_fit_checkBox, 2, 0, 1, 1) + 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, 8, 0, 1, 2) self.retranslateUi(Dialog) self.stack.setCurrentIndex(0) @@ -210,8 +233,12 @@ class Ui_Dialog(object): Dialog.setWindowTitle(_translate("Dialog", "Fit results")) self.autoscale_box.setToolTip(_translate("Dialog", "Auto-scale graph for all sets")) self.autoscale_box.setText(_translate("Dialog", "Autoscale all sets")) - self.logy_box.setText(_translate("Dialog", "logarithmic y axis")) - self.logx_box.setText(_translate("Dialog", "logarithmic x axis")) + self.verticalGroupBox_2.setTitle(_translate("Dialog", "Logarithmic axes")) + self.logx_box.setText(_translate("Dialog", "x axis")) + self.logy_box.setText(_translate("Dialog", "y axis")) + self.verticalGroupBox.setTitle(_translate("Dialog", "Residuals")) + self.rel_dev_button.setText(_translate("Dialog", "relative deviation")) + self.abs_dev_button.setText(_translate("Dialog", "absolute deviation")) self.stack.setTabText(self.stack.indexOf(self.stackPage1), _translate("Dialog", "Plot")) self.stack.setTabText(self.stack.indexOf(self.stackPage2), _translate("Dialog", "Statistics")) item = self.corr_tableWidget.horizontalHeaderItem(0) @@ -224,6 +251,7 @@ class Ui_Dialog(object): item.setText(_translate("Dialog", "Partial Corr.")) self.stack.setTabText(self.stack.indexOf(self.stackPage3), _translate("Dialog", "Correlations")) self.del_prev_checkBox.setText(_translate("Dialog", "Delete previous fits of this set")) + self.reject_fit_checkBox.setText(_translate("Dialog", "Reject this fit")) self.groupBox.setTitle(_translate("Dialog", "Output")) self.extrapolate_box.setToolTip(_translate("Dialog", "Extrapolates only main function")) self.extrapolate_box.setText(_translate("Dialog", "Extrapolate curves")) @@ -236,6 +264,5 @@ 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")) from ..lib.forms import ElideComboBox from pyqtgraph import GraphicsLayoutWidget diff --git a/src/gui_qt/_py/graph.py b/src/gui_qt/_py/graph.py index 62feba0..b54a751 100644 --- a/src/gui_qt/_py/graph.py +++ b/src/gui_qt/_py/graph.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'src/resources/_ui/graph.ui' +# Form implementation generated from reading ui file 'resources/_ui/graph.ui' # -# Created by: PyQt5 UI code generator 5.15.9 +# Created by: PyQt5 UI code generator 5.15.10 # # 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. @@ -271,8 +271,11 @@ class Ui_GraphWindow(object): self.label_4.setText(_translate("GraphWindow", "---")) self.apply_button.setText(_translate("GraphWindow", "Apply")) self.label_5.setText(_translate("GraphWindow", "Title")) + self.title_lineedit.setToolTip(_translate("GraphWindow", "

Uses simple latex syntax, does not support italic/math environment. Sub-/superscripts need curly brackets.

Example: \\alpha^{123}

")) self.label_6.setText(_translate("GraphWindow", "X Axis")) + self.xaxis_linedit.setToolTip(_translate("GraphWindow", "

Uses simple latex syntax, does not support italic/math environment. Sub-/superscripts need curly brackets.

Example: \\alpha^{123}

")) self.label_7.setText(_translate("GraphWindow", "Y Axis")) + self.yaxis_linedit.setToolTip(_translate("GraphWindow", "

Uses simple latex syntax, does not support italic/math environment. Sub-/superscripts need curly brackets.

Example: \\alpha^{123}

")) self.checkBox.setText(_translate("GraphWindow", "Show legend")) from ..lib.graph_items import NMRPlotWidget from ..lib.listwidget import QListWidgetSelect diff --git a/src/gui_qt/fit/result.py b/src/gui_qt/fit/result.py index 7c4b85c..01f44ee 100644 --- a/src/gui_qt/fit/result.py +++ b/src/gui_qt/fit/result.py @@ -1,6 +1,7 @@ from math import isnan from pyqtgraph import mkBrush, mkPen +from numpy import abs as np_abs, isfinite as np_isfinite from nmreval.utils.text import convert from ..lib.graph_items import logTickValues @@ -69,12 +70,16 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): self.cmap = RdBuCMap(vmin=-1, vmax=1) - 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.CheckState.Unchecked) + ) 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.buttonGroup.buttonToggled.connect(self._plot_residuals) + self.set_results(results) def __call__(self, results: list): @@ -112,7 +117,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): @QtCore.pyqtSlot(int, name='on_sets_comboBox_currentIndexChanged') def set_parameter(self, idx: int): - set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.UserRole) + set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.ItemDataRole.UserRole) res = self._results[set_id] self.param_tableWidget.setRowCount(len(res.parameter)) @@ -138,11 +143,11 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): def change_opts(self, _): idx = self.sets_comboBox.currentIndex() - self._opts[idx] = (self.reject_fit_checkBox.checkState() == QtCore.Qt.Checked, - self.del_prev_checkBox.checkState() == QtCore.Qt.Checked) + self._opts[idx] = (self.reject_fit_checkBox.checkState() == QtCore.Qt.CheckState.Checked, + self.del_prev_checkBox.checkState() == QtCore.Qt.CheckState.Checked) def show_results(self, idx): - set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.UserRole) + set_id = self.sets_comboBox.itemData(idx, QtCore.Qt.ItemDataRole.UserRole) self.set_plot(set_id) self.set_correlation(set_id) self.set_statistics(set_id) @@ -184,8 +189,6 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): self.data_graph_imag.setData(x=res.x_data, y=res.y_data.imag) self.fit_graph.setData(x=res.x, y=res.y.real) self.fit_graph_imag.setData(x=res.x, y=res.y.imag) - 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 i, f in enumerate(sub_funcs): item = PlotItem(x=f.x, y=f.y.real, pen=mkPen({'color': i, 'style': 2})) @@ -194,8 +197,6 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): self.fit_plot.addItem(item) else: - self.resid_graph.setData(x=res.x_data, y=res.residual) - self.resid_graph_imag.setData(x=[], y=[]) self.data_graph.setData(x=res.x_data, y=res.y_data) self.data_graph_imag.setData(x=[], y=[]) self.fit_graph.setData(x=res.x, y=res.y) @@ -205,6 +206,8 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): item = PlotItem(x=f.x, y=f.y, pen=mkPen({'color': i, 'style': 2})) self.fit_plot.addItem(item) + self._plot_residuals(idx) + self.logx_box.blockSignals(True) self.logx_box.setChecked(res.islog) self.logx_box.blockSignals(False) @@ -225,6 +228,31 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): else: self.fit_plot.enableAutoRange() + def _plot_residuals(self, idx: str = None): + print(idx) + if idx is None or isinstance(idx, QtWidgets.QAbstractButton): + idx = self.sets_comboBox.currentData(QtCore.Qt.ItemDataRole.UserRole) + + res = self._results[idx] + if res.iscomplex: + if self.rel_dev_button.isChecked(): + print('rel') + self.resid_graph.setData(x=res.x_data, y=res.residual.real/np_abs(res.y_data.real)) + print(res.y_data.imag) + if all(np_isfinite(res.y_data.imag)): + self.resid_graph_imag.setData(x=res.x_data, y=res.residual.imag/np_abs(res.y_data.imag)) + else: + print('abs') + 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) + + else: + if self.rel_dev_button.isChecked(): + self.resid_graph.setData(x=res.x_data, y=res.residual / np_abs(res.y_data)) + else: + self.resid_graph.setData(x=res.x_data, y=res.residual) + self.resid_graph_imag.setData(x=[], y=[]) + def set_correlation(self, idx: str): while self.corr_tableWidget.rowCount(): self.corr_tableWidget.removeRow(0) @@ -258,20 +286,20 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): self.stats_tableWidget.setRowCount(len(res.statistics)+3) it = QtWidgets.QTableWidgetItem(f'{res.dof}') - it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + it.setFlags(it.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) self.stats_tableWidget.setVerticalHeaderItem(0, QtWidgets.QTableWidgetItem('DoF')) self.stats_tableWidget.setItem(0, 0, it) 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) + it.setFlags(it.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) self.stats_tableWidget.setItem(0, col, it) for row, (k, v) in enumerate(res.statistics.items(), start=1): self.stats_tableWidget.setVerticalHeaderItem(row, QtWidgets.QTableWidgetItem(k)) it = QtWidgets.QTableWidgetItem(f'{v:.4f}') - it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + it.setFlags(it.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) self.stats_tableWidget.setItem(row, 0, it) best_idx = -1 @@ -282,7 +310,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): else: best_idx = col if best_val > stats[k] else max(0, best_idx) it = QtWidgets.QTableWidgetItem(f'{stats[k]:.4f}') - it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + it.setFlags(it.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) self.stats_tableWidget.setItem(row, col, it) if best_idx > -1: @@ -299,11 +327,11 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): 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) + it.setFlags(it.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) self.corr_tableWidget.setItem(row, col, it) it = QtWidgets.QTableWidgetItem(f'{prob_f:.4g}') - it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + it.setFlags(it.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) if prob_f < 0.05: it.setBackground(QtGui.QColor('green')) it.setForeground(QtGui.QColor('white')) @@ -319,14 +347,14 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): elif button_type == self.buttonBox.Ok: graph = '-1' if self.parameter_checkbox.isChecked(): - if self.graph_checkBox.checkState() == QtCore.Qt.Checked: + if self.graph_checkBox.checkState() == QtCore.Qt.CheckState.Checked: graph = '' else: graph = self.graph_comboBox.currentData() plot_fits = self.curve_checkbox.isChecked() - parts = self.partial_checkBox.checkState() == QtCore.Qt.Checked + parts = self.partial_checkBox.checkState() == QtCore.Qt.CheckState.Checked extrapolate = [None, None, None] error = [] @@ -382,7 +410,7 @@ class FitExtension(QtWidgets.QDialog): gridLayout.addWidget(self.num_pts, 2, 1, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox() - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok) gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2) diff --git a/src/gui_qt/graphs/graphwindow.py b/src/gui_qt/graphs/graphwindow.py index 2d8c67f..9369bf3 100644 --- a/src/gui_qt/graphs/graphwindow.py +++ b/src/gui_qt/graphs/graphwindow.py @@ -73,7 +73,7 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow): self.scene = self.plotItem.scene() self.scene.sigMouseMoved.connect(self.move_mouse) - self.checkBox.stateChanged.connect(lambda x: self.legend.setVisible(x == QtCore.Qt.Checked)) + self.checkBox.stateChanged.connect(lambda x: self.legend.setVisible(x == QtCore.Qt.CheckState.Checked)) self.label_button.toggled.connect(lambda x: self.label_widget.setVisible(x)) self.limit_button.toggled.connect(lambda x: self.limit_widget.setVisible(x)) self.gridbutton.toggled.connect(lambda x: self.graphic.showGrid(x=x, y=x)) @@ -237,9 +237,13 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow): self.error_plots[n] = err_plot list_item = QtWidgets.QListWidgetItem(real_plot.opts.get('name', '')) - list_item.setData(QtCore.Qt.UserRole, n) - list_item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable) - list_item.setCheckState(QtCore.Qt.Checked) + list_item.setData(QtCore.Qt.ItemDataRole.UserRole, n) + list_item.setFlags( + QtCore.Qt.ItemFlag.ItemIsEnabled | + QtCore.Qt.ItemFlag.ItemIsSelectable | + QtCore.Qt.ItemFlag.ItemIsUserCheckable + ) + list_item.setCheckState(QtCore.Qt.CheckState.Checked) self.listWidget.addItem(list_item) toplevel += 1 @@ -271,7 +275,7 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow): for i in range(self.listWidget.count()-1, 0, -1): item = self.listWidget.item(i) - if item.data(QtCore.Qt.UserRole) in name: + if item.data(QtCore.Qt.ItemDataRole.UserRole) in name: self.listWidget.takeItem(i) self.listWidget.blockSignals(False) @@ -465,24 +469,37 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow): _y = pos.y() self.mousePositionChanged.emit(_x, _y) - @QtCore.pyqtSlot(name='on_title_lineedit_returnPressed') - @QtCore.pyqtSlot(name='on_xaxis_linedit_returnPressed') - @QtCore.pyqtSlot(name='on_yaxis_linedit_returnPressed') - def labels_changed(self): - label = {self.title_lineedit: 'title', self.xaxis_linedit: 'x', self.yaxis_linedit: 'y'}[self.sender()] - self.set_label(**{label: self.sender().text()}) + @QtCore.pyqtSlot(str, name='on_title_lineedit_textChanged') + @QtCore.pyqtSlot(str, name='on_xaxis_linedit_textChanged') + @QtCore.pyqtSlot(str, name='on_yaxis_linedit_textChanged') + def labels_changed(self, text: str): + label = { + self.title_lineedit: 'title', + self.xaxis_linedit: 'x', + self.yaxis_linedit: 'y', + }[self.sender()] + self.set_label(**{label: text}) - def set_label(self, x=None, y=None, title=None): + def set_label(self, x: str = None, y: str = None, title: str = None): if title is not None: - self.plotItem.setTitle(convert(title, old='tex', new='html'), **{'size': '10pt', 'color': self._fgcolor}) + self.plotItem.setTitle( + convert(title, old='tex', new='html'), + **{'size': '10pt', 'color': self._fgcolor}, + ) if x is not None: - self.plotItem.setLabel('bottom', convert(x, old='tex', new='html'), - **{'font-size': '10pt', 'color': self._fgcolor.name()}) + self.plotItem.setLabel( + 'bottom', + convert(x, old='tex', new='html'), + **{'font-size': '10pt', 'color': self._fgcolor.name()}, + ) if y is not None: - self.plotItem.setLabel('left', convert(y, old='tex', new='html'), - **{'font-size': '10pt', 'color': self._fgcolor.name()}) + self.plotItem.setLabel( + 'left', + convert(y, old='tex', new='html'), + **{'font-size': '10pt', 'color': self._fgcolor.name()}, + ) def set_logmode(self, xmode: bool = None, ymode: bool = None): r = self.ranges @@ -588,7 +605,7 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow): for i in range(self.listWidget.count()): item = self.listWidget.item(i) - if item.data(QtCore.Qt.UserRole) == sid: + if item.data(QtCore.Qt.ItemDataRole.UserRole) == sid: item.setText(convert(name, old='tex', new='html')) self.listWidget.blockSignals(False) diff --git a/src/gui_qt/io/fcbatchreader.py b/src/gui_qt/io/fcbatchreader.py index 124e2a6..4f678b5 100644 --- a/src/gui_qt/io/fcbatchreader.py +++ b/src/gui_qt/io/fcbatchreader.py @@ -84,11 +84,11 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog): if self.region_box.isChecked(): start = None if self.start_lineedit.text(): - start = float(self.start_lineedit.text()) + start = float(self.start_lineedit.text())*1e-6 stop = None if self.stop_lineedit.text(): - stop = float(self.stop_lineedit.text()) + stop = float(self.stop_lineedit.text())*1e-6 region = (start, stop) fc_eval = FCReader(items) diff --git a/src/gui_qt/lib/spinboxes.py b/src/gui_qt/lib/spinboxes.py index dfaced2..5ba041d 100644 --- a/src/gui_qt/lib/spinboxes.py +++ b/src/gui_qt/lib/spinboxes.py @@ -34,9 +34,9 @@ class SciSpinBox(QtWidgets.QDoubleSpinBox): new_value = self._prev_value if new_value != 0.0: - new_value *= 10**(step/19.) + new_value *= 10**(step/99.) else: - new_value = 0.001 + new_value = 0.00001 self.setValue(new_value) self.lineEdit().setText(f'{new_value:.3e}') diff --git a/src/nmreval/models/bds.py b/src/nmreval/models/bds.py index 9ccb922..9f6321d 100644 --- a/src/nmreval/models/bds.py +++ b/src/nmreval/models/bds.py @@ -1,5 +1,6 @@ import numpy as np +from . import PowerLaw from ..distributions import Debye, ColeCole, ColeDavidson, KWW, HavriliakNegami from ..utils.constants import epsilon0 @@ -232,8 +233,8 @@ class DCCondBDS: class DerivativeHavriliakNegami: - name = 'Derivative HN' - type = 'Dielectric Spectroscopy' + name = 'Havriliak-Negami (der.)' + type = 'Dielectric Spectroscopy (derivative)' params = [r'\Delta\epsilon', r'\tau', r'\alpha', r'\gamma'] choices = [ ('x axis', 'xaxis', {'Frequency': 'freq', 'Omega': 'omega'}) @@ -254,8 +255,8 @@ class DerivativeHavriliakNegami: class DerivativeColeCole: - name = 'Derivative CC' - type = 'Dielectric Spectroscopy' + name = 'Cole-Cole (der.)' + type = 'Dielectric Spectroscopy (derivative)' params = [r'\Delta\epsilon', r'\tau', r'\alpha'] bounds = [(0, None), (0, None), (0, 1)] choices = [ @@ -276,8 +277,8 @@ class DerivativeColeCole: class DerivativeColeDavidson: - name = 'Derivative CD' - type = 'Dielectric Spectroscopy' + name = 'Cole-Davidson (der.)' + type = 'Dielectric Spectroscopy (derivative)' params = [r'\Delta\epsilon', r'\tau', r'\gamma'] bounds = [(0, None), (0, None), (0, 1)] choices = [ @@ -295,8 +296,8 @@ class DerivativeColeDavidson: class _DerivativeHNWithHF: - name = 'Derivative (HN + HF wing)' - type = 'Dielectric Spectroscopy' + name = 'HN + HF wing (der.)' + type = 'Dielectric Spectroscopy (derivative)' params = [r'\Delta\epsilon', r'\tau', r'\alpha', r'\gamma', r'\tau_{c}', r'\delta'] bounds = [(0, None), (0, None), (0, 1), (0, 1), (0, None), (0, 1)] choices = [ @@ -325,8 +326,8 @@ class _DerivativeHNWithHF: class DerivativeCCWithHF: - name = 'Derivative (CC + HF wing)' - type = 'Dielectric Spectroscopy' + name = 'CC + HF wing (der.)' + type = 'Dielectric Spectroscopy (derivative)' params = [r'\Delta\epsilon', r'\tau', r'\alpha', r'\tau_{c}', r'\delta'] bounds = [(0, None), (0, None), (0, 1), (0, None), (0, 1)] choices = [ @@ -339,8 +340,8 @@ class DerivativeCCWithHF: class DerivativeCDWithHF: - name = 'Derivative (CD + HF wing)' - type = 'Dielectric Spectroscopy' + name = 'CD + HF wing (der.)' + type = 'Dielectric Spectroscopy (derivative)' params = [r'\Delta\epsilon', r'\tau', r'\gamma', r'\tau_{c}', r'\delta'] bounds = [(0, None), (0, None), (0, 1), (0, None), (0, 1)] choices = [ @@ -352,6 +353,22 @@ class DerivativeCDWithHF: return _DerivativeHNWithHF.func(x, deps, tau, 1, gamma, tauc, delta, xaxis=xaxis) +class PowerLawBDSDer: + name = 'Power Law' + type = 'Dielectric Spectroscopy (derivative)' + equation = r'A * \omega^{n}' + params = ['A', 'n'] + bounds = [(None, None), (None, None)] + choices = [ + ('x axis', 'xaxis', {'Frequency': 'freq', 'Omega': 'omega'}) + ] + + @staticmethod + def func(x, a, n, xaxis: str = 'freq'): + _w = _convert_x_to_omega(x, xaxis=xaxis) + return a * _w ** n + + def _convert_x_to_omega(x, xaxis: str = 'freq'): if xaxis not in ['freq', 'omega']: raise ValueError(f'Argument `xaxis` is `freq` or `omega`, given is {xaxis!r}') diff --git a/src/resources/_ui/fitresult.ui b/src/resources/_ui/fitresult.ui index d821e3c..142a794 100644 --- a/src/resources/_ui/fitresult.ui +++ b/src/resources/_ui/fitresult.ui @@ -31,13 +31,13 @@ - 3 + 6 3 - 3 + 6 3 @@ -45,7 +45,20 @@ 3 - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + Auto-scale graph for all sets @@ -55,29 +68,6 @@ - - - - Qt::LeftToRight - - - logarithmic y axis - - - - - - - - - - Qt::LeftToRight - - - logarithmic x axis - - - @@ -91,6 +81,70 @@ + + + + Logarithmic axes + + + + + + Qt::LeftToRight + + + x axis + + + + + + + Qt::LeftToRight + + + y axis + + + + + + + + + + Residuals + + + + + + relative deviation + + + buttonGroup + + + + + + + absolute deviation + + + true + + + buttonGroup + + + + + + + + + @@ -198,13 +252,6 @@ - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Retry - - - @@ -254,6 +301,38 @@ + + + + + 0 + 0 + + + + + 400 + 16777215 + + + + + 200 + 0 + + + + QComboBox::AdjustToMinimumContentsLength + + + + + + + Reject this fit + + + @@ -400,35 +479,10 @@ - - - - - 0 - 0 - - - - - 400 - 16777215 - - - - - 200 - 0 - - - - QComboBox::AdjustToMinimumContentsLength - - - - - - - Reject this fit + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Retry @@ -448,4 +502,7 @@ + + + diff --git a/src/resources/_ui/graph.ui b/src/resources/_ui/graph.ui index a433365..d99e4fc 100644 --- a/src/resources/_ui/graph.ui +++ b/src/resources/_ui/graph.ui @@ -449,7 +449,11 @@ - + + + <html><head/><body><p>Uses simple latex syntax, does not support italic/math environment. Sub-/superscripts need curly brackets.<br/></p><p>Example: \alpha^{123}</p></body></html> + + @@ -475,7 +479,11 @@ - + + + <html><head/><body><p>Uses simple latex syntax, does not support italic/math environment. Sub-/superscripts need curly brackets.<br/></p><p>Example: \alpha^{123}</p></body></html> + + @@ -501,7 +509,11 @@ - + + + <html><head/><body><p>Uses simple latex syntax, does not support italic/math environment. Sub-/superscripts need curly brackets.<br/></p><p>Example: \alpha^{123}</p></body></html> + +