From 813e18a7440c1bf6ba39e13c3f3eccecb0df0668 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Tue, 30 Jan 2024 18:01:15 +0000 Subject: [PATCH] make log-spacing explicit option for custom fit x values (#227) closes #225 --- src/gui_qt/_py/fitresult.py | 95 +++++++++++++++--------- src/gui_qt/fit/result.py | 17 ++++- src/gui_qt/main/mainwindow.py | 3 +- src/gui_qt/main/management.py | 2 +- src/resources/_ui/fitresult.ui | 132 +++++++++++++++++++++------------ 5 files changed, 159 insertions(+), 90 deletions(-) diff --git a/src/gui_qt/_py/fitresult.py b/src/gui_qt/_py/fitresult.py index 54becc9..0f73b79 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 'resources/_ui/fitresult.ui' +# Form implementation generated from reading ui file 'src/resources/_ui/fitresult.ui' # # Created by: PyQt5 UI code generator 5.15.10 # @@ -157,67 +157,91 @@ class Ui_Dialog(object): self.gridLayout_2.setContentsMargins(3, 3, 3, 3) self.gridLayout_2.setSpacing(3) self.gridLayout_2.setObjectName("gridLayout_2") - self.extrapolate_box = QtWidgets.QCheckBox(self.groupBox) - self.extrapolate_box.setObjectName("extrapolate_box") - self.gridLayout_2.addWidget(self.extrapolate_box, 1, 0, 1, 1) - self.parameter_checkbox = QtWidgets.QCheckBox(self.groupBox) - self.parameter_checkbox.setObjectName("parameter_checkbox") - self.gridLayout_2.addWidget(self.parameter_checkbox, 0, 5, 1, 1) self.graph_comboBox = QtWidgets.QComboBox(self.groupBox) self.graph_comboBox.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.graph_comboBox.sizePolicy().hasHeightForWidth()) self.graph_comboBox.setSizePolicy(sizePolicy) self.graph_comboBox.setObjectName("graph_comboBox") - self.gridLayout_2.addWidget(self.graph_comboBox, 1, 6, 1, 1) - self.graph_checkBox = QtWidgets.QCheckBox(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.graph_checkBox.sizePolicy().hasHeightForWidth()) - self.graph_checkBox.setSizePolicy(sizePolicy) - self.graph_checkBox.setChecked(True) - self.graph_checkBox.setObjectName("graph_checkBox") - self.gridLayout_2.addWidget(self.graph_checkBox, 1, 5, 1, 1) + self.gridLayout_2.addWidget(self.graph_comboBox, 1, 7, 1, 1) self.minx_line = QtWidgets.QLineEdit(self.groupBox) self.minx_line.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.minx_line.sizePolicy().hasHeightForWidth()) self.minx_line.setSizePolicy(sizePolicy) self.minx_line.setObjectName("minx_line") self.gridLayout_2.addWidget(self.minx_line, 1, 1, 1, 1) - self.line_2 = QtWidgets.QFrame(self.groupBox) - self.line_2.setFrameShape(QtWidgets.QFrame.VLine) - self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) - self.line_2.setObjectName("line_2") - self.gridLayout_2.addWidget(self.line_2, 0, 4, 2, 1) + self.extrapolate_box = QtWidgets.QCheckBox(self.groupBox) + self.extrapolate_box.setObjectName("extrapolate_box") + self.gridLayout_2.addWidget(self.extrapolate_box, 1, 0, 1, 1) + self.numx_line = QtWidgets.QLineEdit(self.groupBox) + self.numx_line.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.numx_line.sizePolicy().hasHeightForWidth()) + self.numx_line.setSizePolicy(sizePolicy) + self.numx_line.setObjectName("numx_line") + self.gridLayout_2.addWidget(self.numx_line, 1, 3, 1, 1) + self.graph_checkBox = QtWidgets.QCheckBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graph_checkBox.sizePolicy().hasHeightForWidth()) + self.graph_checkBox.setSizePolicy(sizePolicy) + self.graph_checkBox.setChecked(True) + self.graph_checkBox.setObjectName("graph_checkBox") + self.gridLayout_2.addWidget(self.graph_checkBox, 1, 6, 1, 1) self.maxx_line = QtWidgets.QLineEdit(self.groupBox) self.maxx_line.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.maxx_line.sizePolicy().hasHeightForWidth()) self.maxx_line.setSizePolicy(sizePolicy) self.maxx_line.setObjectName("maxx_line") self.gridLayout_2.addWidget(self.maxx_line, 1, 2, 1, 1) - self.numx_line = QtWidgets.QLineEdit(self.groupBox) - self.numx_line.setEnabled(False) - self.numx_line.setObjectName("numx_line") - self.gridLayout_2.addWidget(self.numx_line, 1, 3, 1, 1) + self.line_2 = QtWidgets.QFrame(self.groupBox) + self.line_2.setFrameShape(QtWidgets.QFrame.VLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout_2.addWidget(self.line_2, 0, 5, 2, 1) + self.newx_log_checkbox = QtWidgets.QCheckBox(self.groupBox) + self.newx_log_checkbox.setEnabled(False) + self.newx_log_checkbox.setObjectName("newx_log_checkbox") + self.gridLayout_2.addWidget(self.newx_log_checkbox, 1, 4, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.curve_checkbox = QtWidgets.QCheckBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.curve_checkbox.sizePolicy().hasHeightForWidth()) + self.curve_checkbox.setSizePolicy(sizePolicy) self.curve_checkbox.setChecked(True) self.curve_checkbox.setObjectName("curve_checkbox") self.horizontalLayout.addWidget(self.curve_checkbox) self.partial_checkBox = QtWidgets.QCheckBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.partial_checkBox.sizePolicy().hasHeightForWidth()) + self.partial_checkBox.setSizePolicy(sizePolicy) self.partial_checkBox.setObjectName("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, 5) + self.parameter_checkbox = QtWidgets.QCheckBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.parameter_checkbox.sizePolicy().hasHeightForWidth()) + self.parameter_checkbox.setSizePolicy(sizePolicy) + self.parameter_checkbox.setObjectName("parameter_checkbox") + self.gridLayout_2.addWidget(self.parameter_checkbox, 0, 6, 1, 2) self.gridLayout.addWidget(self.groupBox, 7, 0, 1, 2) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Retry) @@ -253,16 +277,17 @@ class Ui_Dialog(object): 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")) - self.parameter_checkbox.setText(_translate("Dialog", "Plot parameter")) - self.graph_checkBox.setText(_translate("Dialog", "New graph for parameter")) self.minx_line.setToolTip(_translate("Dialog", "Leave empty to start at lowest point")) self.minx_line.setPlaceholderText(_translate("Dialog", "min x")) + self.extrapolate_box.setToolTip(_translate("Dialog", "Extrapolates only main function")) + self.extrapolate_box.setText(_translate("Dialog", "Extrapolate curves")) + self.numx_line.setPlaceholderText(_translate("Dialog", "# pts")) + self.graph_checkBox.setText(_translate("Dialog", "New graph for parameter")) self.maxx_line.setToolTip(_translate("Dialog", "Leave empty to start at highest point")) self.maxx_line.setPlaceholderText(_translate("Dialog", "max x")) - self.numx_line.setPlaceholderText(_translate("Dialog", "# pts")) + self.newx_log_checkbox.setText(_translate("Dialog", "log-spaced?")) self.curve_checkbox.setText(_translate("Dialog", "Plot fit curve")) self.partial_checkBox.setText(_translate("Dialog", "Plot partial functions")) + self.parameter_checkbox.setText(_translate("Dialog", "Plot parameter")) from ..lib.forms import ElideComboBox from pyqtgraph import GraphicsLayoutWidget diff --git a/src/gui_qt/fit/result.py b/src/gui_qt/fit/result.py index 17b3799..4706cbc 100644 --- a/src/gui_qt/fit/result.py +++ b/src/gui_qt/fit/result.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from math import isnan from pyqtgraph import mkBrush, mkPen @@ -28,6 +30,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): self.extrapolate_box.stateChanged.connect(lambda x: self.maxx_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.newx_log_checkbox.setEnabled(x)) self._previous_fits = {} self._opts = [] @@ -352,7 +355,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): parts = self.partial_checkBox.checkState() == QtCore.Qt.CheckState.Checked - extrapolate = [None, None, None] + extrapolate = [None, None, None, None] error = [] if self.extrapolate_box.isChecked(): try: @@ -368,6 +371,8 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog): except (TypeError, ValueError): error.append('Number of points is missing') + extrapolate[3] = self.newx_log_checkbox.isChecked() + if error: msg = QtWidgets.QMessageBox.warning(self, 'Error', 'Extrapolation failed because:\n' + '\n'.join(error)) return @@ -405,10 +410,13 @@ class FitExtension(QtWidgets.QDialog): self.num_pts.setValidator(QtGui.QIntValidator()) gridLayout.addWidget(self.num_pts, 2, 1, 1, 1) + self.logx_checkbox = QtWidgets.QCheckBox('Log-spaced?') + gridLayout.addWidget(self.logx_checkbox, 3, 0, 1, 2) + self.buttonBox = QtWidgets.QDialogButtonBox() self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok) - gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2) + gridLayout.addWidget(self.buttonBox, 4, 0, 1, 2) self.setLayout(gridLayout) @@ -416,12 +424,13 @@ class FitExtension(QtWidgets.QDialog): self.buttonBox.rejected.connect(self.reject) @property - def values(self): + def values(self) -> tuple[float, float, int, bool] | None: try: xmin = float(self.min_line.text()) xmax = float(self.max_line.text()) nums = int(self.num_pts.text()) + logx = self.logx_checkbox.isChecked() except TypeError: return None - return xmin, xmax, nums + return xmin, xmax, nums, logx diff --git a/src/gui_qt/main/mainwindow.py b/src/gui_qt/main/mainwindow.py index 8575319..80935b6 100644 --- a/src/gui_qt/main/mainwindow.py +++ b/src/gui_qt/main/mainwindow.py @@ -984,7 +984,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): res = w.exec() if res: p = w.values - x = linspace(p[0], p[1], num=p[2]) + spacefunc = geomspace if p[3] else linspace + x = spacefunc(p[0], p[1], num=p[2]) self.management.extend_fits(sets, x) @QtCore.pyqtSlot(name='on_action_create_fit_function_triggered') diff --git a/src/gui_qt/main/management.py b/src/gui_qt/main/management.py index 3185b30..b8758b2 100644 --- a/src/gui_qt/main/management.py +++ b/src/gui_qt/main/management.py @@ -613,7 +613,7 @@ class UpperManagement(QtCore.QObject): continue if not all(e is None for e in extrapolate): - spacefunc = np.geomspace if fit.islog else np.linspace + spacefunc = np.geomspace if extrapolate[3] else np.linspace xmin = fit.x.min() xmax = fit.x.max() diff --git a/src/resources/_ui/fitresult.ui b/src/resources/_ui/fitresult.ui index 142a794..9f8bd4f 100644 --- a/src/resources/_ui/fitresult.ui +++ b/src/resources/_ui/fitresult.ui @@ -354,59 +354,26 @@ 3 - - - - Extrapolates only main function - - - Extrapolate curves - - - - - - - Plot parameter - - - - + false - + 0 0 - - - - - 0 - 0 - - - - New graph for parameter - - - true - - - false - + 0 0 @@ -419,10 +386,45 @@ - - - - Qt::Vertical + + + + Extrapolates only main function + + + Extrapolate curves + + + + + + + false + + + + 0 + 0 + + + + # pts + + + + + + + + 0 + 0 + + + + New graph for parameter + + + true @@ -432,7 +434,7 @@ false - + 0 0 @@ -445,20 +447,33 @@ - - - - false - - - # pts + + + + Qt::Vertical - + + + + false + + + log-spaced? + + + + + + + 0 + 0 + + Plot fit curve @@ -469,6 +484,12 @@ + + + 0 + 0 + + Plot partial functions @@ -476,6 +497,19 @@ + + + + + 0 + 0 + + + + Plot parameter + + +