forked from IPKM/nmreval
Merge remote-tracking branch 'origin/master' into gga_relaxation
This commit is contained in:
commit
f30ff3b758
@ -17,7 +17,7 @@ body:
|
||||
description: For which version have you observed this behavior?
|
||||
placeholder: You find the program version in "Help/About"
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
|
@ -29,10 +29,10 @@ jobs:
|
||||
env:
|
||||
GPG_KEYGRIP: ${{ vars.GPG_KEYGRIP }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
GO_PIPELINE_LABEL: ${{ env.YEAR }}.${{ gitea.run_number }}_${{ env.SHA_SHORT }}_bookworm
|
||||
GO_PIPELINE_LABEL: ${{ env.YEAR }}.${{ gitea.run_number }}_${{ env.SHA_SHORT }}
|
||||
- name: Upload AppImage
|
||||
run: ./tools/upload_gitea.sh
|
||||
env:
|
||||
GO_PIPELINE_LABEL: ${{ env.YEAR }}.${{ gitea.run_number }}_${{ env.SHA_SHORT }}_bookworm
|
||||
GO_PIPELINE_LABEL: ${{ env.YEAR }}.${{ gitea.run_number }}_${{ env.SHA_SHORT }}
|
||||
UPLOAD_TOKEN: ${{ secrets.UPLOAD_TOKEN }}
|
||||
UPLOAD_USER: ${{ vars.UPLOAD_USER }}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'resources/_ui/basewindow.ui'
|
||||
# Form implementation generated from reading ui file './nmreval/src/resources/_ui/basewindow.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
@ -87,6 +87,8 @@ class Ui_BaseWindow(object):
|
||||
self.menuSave.setObjectName("menuSave")
|
||||
self.menuData = QtWidgets.QMenu(self.menubar)
|
||||
self.menuData.setObjectName("menuData")
|
||||
self.menuCut_to_visible_range = QtWidgets.QMenu(self.menuData)
|
||||
self.menuCut_to_visible_range.setObjectName("menuCut_to_visible_range")
|
||||
self.menuHelp = QtWidgets.QMenu(self.menubar)
|
||||
self.menuHelp.setObjectName("menuHelp")
|
||||
self.menuExtra = QtWidgets.QMenu(self.menubar)
|
||||
@ -153,15 +155,6 @@ class Ui_BaseWindow(object):
|
||||
self.toolBar_nmr.setIconSize(QtCore.QSize(24, 24))
|
||||
self.toolBar_nmr.setObjectName("toolBar_nmr")
|
||||
BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar_nmr)
|
||||
self.toolBar_fit = QtWidgets.QToolBar(BaseWindow)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.toolBar_fit.sizePolicy().hasHeightForWidth())
|
||||
self.toolBar_fit.setSizePolicy(sizePolicy)
|
||||
self.toolBar_fit.setIconSize(QtCore.QSize(24, 24))
|
||||
self.toolBar_fit.setObjectName("toolBar_fit")
|
||||
BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar_fit)
|
||||
self.toolBar_spectrum = QtWidgets.QToolBar(BaseWindow)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@ -313,8 +306,6 @@ class Ui_BaseWindow(object):
|
||||
self.actionDerivation.setObjectName("actionDerivation")
|
||||
self.actionIntegration = QtWidgets.QAction(BaseWindow)
|
||||
self.actionIntegration.setObjectName("actionIntegration")
|
||||
self.action_cut = QtWidgets.QAction(BaseWindow)
|
||||
self.action_cut.setObjectName("action_cut")
|
||||
self.actionMove_between_plots = QtWidgets.QAction(BaseWindow)
|
||||
self.actionMove_between_plots.setObjectName("actionMove_between_plots")
|
||||
self.actionBaseline = QtWidgets.QAction(BaseWindow)
|
||||
@ -374,6 +365,13 @@ class Ui_BaseWindow(object):
|
||||
self.actionBinning.setObjectName("actionBinning")
|
||||
self.actionTNMH = QtWidgets.QAction(BaseWindow)
|
||||
self.actionTNMH.setObjectName("actionTNMH")
|
||||
self.actionExclude_region = QtWidgets.QAction(BaseWindow)
|
||||
self.actionExclude_region.setCheckable(True)
|
||||
self.actionExclude_region.setObjectName("actionExclude_region")
|
||||
self.action_cut_xaxis = QtWidgets.QAction(BaseWindow)
|
||||
self.action_cut_xaxis.setObjectName("action_cut_xaxis")
|
||||
self.action_cut_yaxis = QtWidgets.QAction(BaseWindow)
|
||||
self.action_cut_yaxis.setObjectName("action_cut_yaxis")
|
||||
self.menuSave.addAction(self.actionSave)
|
||||
self.menuSave.addAction(self.actionExportGraphic)
|
||||
self.menuSave.addAction(self.action_save_fit_parameter)
|
||||
@ -386,6 +384,9 @@ class Ui_BaseWindow(object):
|
||||
self.menuFile.addSeparator()
|
||||
self.menuFile.addAction(self.action_close)
|
||||
self.menuFile.addSeparator()
|
||||
self.menuCut_to_visible_range.addSeparator()
|
||||
self.menuCut_to_visible_range.addAction(self.action_cut_xaxis)
|
||||
self.menuCut_to_visible_range.addAction(self.action_cut_yaxis)
|
||||
self.menuData.addAction(self.action_new_set)
|
||||
self.menuData.addAction(self.action_delete_sets)
|
||||
self.menuData.addAction(self.actionMove_between_plots)
|
||||
@ -395,7 +396,7 @@ class Ui_BaseWindow(object):
|
||||
self.menuData.addAction(self.action_sort_pts)
|
||||
self.menuData.addAction(self.actionSkip_points)
|
||||
self.menuData.addSeparator()
|
||||
self.menuData.addAction(self.action_cut)
|
||||
self.menuData.addAction(self.menuCut_to_visible_range.menuAction())
|
||||
self.menuData.addSeparator()
|
||||
self.menuData.addAction(self.actionChange_datatypes)
|
||||
self.menuHelp.addAction(self.actionShow_error_log)
|
||||
@ -428,6 +429,7 @@ class Ui_BaseWindow(object):
|
||||
self.menuLimits.addAction(self.action_no_range)
|
||||
self.menuLimits.addAction(self.action_x_range)
|
||||
self.menuLimits.addAction(self.action_custom_range)
|
||||
self.menuLimits.addAction(self.actionExclude_region)
|
||||
self.menuFit.addAction(self.action_FitWidget)
|
||||
self.menuFit.addSeparator()
|
||||
self.menuFit.addAction(self.action_create_fit_function)
|
||||
@ -496,7 +498,6 @@ class Ui_BaseWindow(object):
|
||||
self.toolbar_edit.addAction(self.actionShift)
|
||||
self.toolBar_nmr.addAction(self.t1action)
|
||||
self.toolBar_nmr.addAction(self.actionCalculateT1)
|
||||
self.toolBar_fit.addAction(self.action_FitWidget)
|
||||
self.toolBar_spectrum.addAction(self.action_edit)
|
||||
self.toolBar_spectrum.addAction(self.actionPick_position)
|
||||
self.toolBar_data.addAction(self.actionConcatenate_sets)
|
||||
@ -521,6 +522,7 @@ class Ui_BaseWindow(object):
|
||||
self.menuFile.setTitle(_translate("BaseWindow", "&File"))
|
||||
self.menuSave.setTitle(_translate("BaseWindow", "&Save..."))
|
||||
self.menuData.setTitle(_translate("BaseWindow", "&Data"))
|
||||
self.menuCut_to_visible_range.setTitle(_translate("BaseWindow", "Cut to visible range"))
|
||||
self.menuHelp.setTitle(_translate("BaseWindow", "&Help"))
|
||||
self.menuExtra.setTitle(_translate("BaseWindow", "Math"))
|
||||
self.menuNormalize.setTitle(_translate("BaseWindow", "&Normalize"))
|
||||
@ -537,7 +539,6 @@ class Ui_BaseWindow(object):
|
||||
self.toolBar.setWindowTitle(_translate("BaseWindow", "Main"))
|
||||
self.toolbar_edit.setWindowTitle(_translate("BaseWindow", "Math"))
|
||||
self.toolBar_nmr.setWindowTitle(_translate("BaseWindow", "NMR"))
|
||||
self.toolBar_fit.setWindowTitle(_translate("BaseWindow", "Fit"))
|
||||
self.toolBar_spectrum.setWindowTitle(_translate("BaseWindow", "Spectrum"))
|
||||
self.toolBar_data.setWindowTitle(_translate("BaseWindow", "Data"))
|
||||
self.action_close.setText(_translate("BaseWindow", "&Quit"))
|
||||
@ -615,7 +616,6 @@ class Ui_BaseWindow(object):
|
||||
self.actionIntegrate.setText(_translate("BaseWindow", "Integrate"))
|
||||
self.actionDerivation.setText(_translate("BaseWindow", "Differentiation..."))
|
||||
self.actionIntegration.setText(_translate("BaseWindow", "Integration..."))
|
||||
self.action_cut.setText(_translate("BaseWindow", "Cut to visible range"))
|
||||
self.actionMove_between_plots.setText(_translate("BaseWindow", "Move sets..."))
|
||||
self.actionBaseline.setText(_translate("BaseWindow", "Baseline..."))
|
||||
self.actionCalculateT1.setText(_translate("BaseWindow", "Calculate relaxation..."))
|
||||
@ -642,6 +642,11 @@ class Ui_BaseWindow(object):
|
||||
self.actionTNMH_model.setText(_translate("BaseWindow", "Tg , Hodge, TNMH,,,"))
|
||||
self.actionBinning.setText(_translate("BaseWindow", "Binning..."))
|
||||
self.actionTNMH.setText(_translate("BaseWindow", "TNMH..."))
|
||||
self.actionExclude_region.setText(_translate("BaseWindow", "Exclude region"))
|
||||
self.action_cut_xaxis.setText(_translate("BaseWindow", "x axis"))
|
||||
self.action_cut_xaxis.setToolTip(_translate("BaseWindow", "Remove data points outside visible x range."))
|
||||
self.action_cut_yaxis.setText(_translate("BaseWindow", "y axis"))
|
||||
self.action_cut_yaxis.setToolTip(_translate("BaseWindow", "Remove data points outside visible y range. Uses real part of points."))
|
||||
from ..data.datawidget.datawidget import DataWidget
|
||||
from ..data.integral_widget import IntegralWidget
|
||||
from ..data.point_select import PointSelectWidget
|
||||
|
@ -1,10 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'resources/_ui/fcreader.ui'
|
||||
# Form implementation generated from reading ui file 'src/resources/_ui/fcreader.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.12.3
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# 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
|
||||
@ -47,6 +48,7 @@ class Ui_FCEval_dialog(object):
|
||||
self.verticalLayout.addWidget(self.input_box)
|
||||
self.region_box = QtWidgets.QGroupBox(FCEval_dialog)
|
||||
self.region_box.setCheckable(True)
|
||||
self.region_box.setChecked(False)
|
||||
self.region_box.setObjectName("region_box")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.region_box)
|
||||
self.horizontalLayout.setContentsMargins(3, 3, 3, 3)
|
||||
@ -139,6 +141,7 @@ class Ui_FCEval_dialog(object):
|
||||
self.line.setObjectName("line")
|
||||
self.gridLayout.addWidget(self.line, 2, 0, 1, 2)
|
||||
self.graph_comboBox = QtWidgets.QComboBox(self.out_box)
|
||||
self.graph_comboBox.setEnabled(False)
|
||||
self.graph_comboBox.setObjectName("graph_comboBox")
|
||||
self.gridLayout.addWidget(self.graph_comboBox, 3, 1, 1, 1)
|
||||
self.graph_checkbox = QtWidgets.QCheckBox(self.out_box)
|
||||
@ -167,8 +170,8 @@ class Ui_FCEval_dialog(object):
|
||||
self.label_6.setBuddy(self.m0_cb)
|
||||
|
||||
self.retranslateUi(FCEval_dialog)
|
||||
self.buttonBox.accepted.connect(FCEval_dialog.accept)
|
||||
self.buttonBox.rejected.connect(FCEval_dialog.reject)
|
||||
self.buttonBox.accepted.connect(FCEval_dialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(FCEval_dialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(FCEval_dialog)
|
||||
|
||||
def retranslateUi(self, FCEval_dialog):
|
||||
@ -178,7 +181,7 @@ class Ui_FCEval_dialog(object):
|
||||
self.file_pushbutton.setText(_translate("FCEval_dialog", "Add HDF files..."))
|
||||
self.dir_pushbutton.setText(_translate("FCEval_dialog", "Add directory..."))
|
||||
self.overwrite_cb.setText(_translate("FCEval_dialog", "Overwrite prev. data"))
|
||||
self.region_box.setTitle(_translate("FCEval_dialog", "Evaluate region (empty values default to start/end)"))
|
||||
self.region_box.setTitle(_translate("FCEval_dialog", "Evaluate region (empty values default to values of the script)"))
|
||||
self.start_lineedit.setPlaceholderText(_translate("FCEval_dialog", "start pos in µs"))
|
||||
self.stop_lineedit.setPlaceholderText(_translate("FCEval_dialog", "end pos in µs"))
|
||||
self.fit_box.setTitle(_translate("FCEval_dialog", "Fit equation"))
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'src/resources/_ui/fitmodelwidget.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.
|
||||
@ -42,6 +42,7 @@ class Ui_FitParameter(object):
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.parameter_line.sizePolicy().hasHeightForWidth())
|
||||
self.parameter_line.setSizePolicy(sizePolicy)
|
||||
self.parameter_line.setMaximumSize(QtCore.QSize(160, 16777215))
|
||||
self.parameter_line.setText("")
|
||||
self.parameter_line.setObjectName("parameter_line")
|
||||
self.horizontalLayout_2.addWidget(self.parameter_line)
|
||||
@ -51,6 +52,9 @@ class Ui_FitParameter(object):
|
||||
self.global_checkbox = QtWidgets.QCheckBox(FitParameter)
|
||||
self.global_checkbox.setObjectName("global_checkbox")
|
||||
self.horizontalLayout_2.addWidget(self.global_checkbox)
|
||||
self.reset_button = QtWidgets.QPushButton(FitParameter)
|
||||
self.reset_button.setObjectName("reset_button")
|
||||
self.horizontalLayout_2.addWidget(self.reset_button)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.frame = QtWidgets.QFrame(FitParameter)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
|
||||
@ -82,6 +86,7 @@ class Ui_FitParameter(object):
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
|
||||
self.lineEdit.setSizePolicy(sizePolicy)
|
||||
self.lineEdit.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||
self.lineEdit.setText("")
|
||||
self.lineEdit.setFrame(True)
|
||||
self.lineEdit.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
@ -100,6 +105,7 @@ class Ui_FitParameter(object):
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.lineEdit_2.sizePolicy().hasHeightForWidth())
|
||||
self.lineEdit_2.setSizePolicy(sizePolicy)
|
||||
self.lineEdit_2.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||
self.lineEdit_2.setText("")
|
||||
self.lineEdit_2.setFrame(True)
|
||||
self.lineEdit_2.setObjectName("lineEdit_2")
|
||||
@ -122,6 +128,7 @@ class Ui_FitParameter(object):
|
||||
self.parameter_line.setPlaceholderText(_translate("FitParameter", "0"))
|
||||
self.fixed_check.setText(_translate("FitParameter", "Fix"))
|
||||
self.global_checkbox.setText(_translate("FitParameter", "Global"))
|
||||
self.reset_button.setText(_translate("FitParameter", "Use global"))
|
||||
self.lineEdit.setToolTip(_translate("FitParameter", "<html><head/><body><p>Lower bound. Same bound is used for all data. Leave empty for no boundary condition.</p></body></html>"))
|
||||
self.label_3.setText(_translate("FitParameter", "Textlabel"))
|
||||
self.lineEdit_2.setToolTip(_translate("FitParameter", "<html><head/><body><p>Upper bound. Same bound is used for all data. Leave empty for no boundary condition.</p></body></html>"))
|
||||
|
@ -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
|
||||
|
@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'src/resources/_ui/interpol_dialog.ui'
|
||||
# Form implementation generated from reading ui file './nmreval/src/resources/_ui/interpol_dialog.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.
|
||||
@ -55,7 +55,7 @@ class Ui_Dialog(object):
|
||||
self.gridLayout.addWidget(self.interp_comboBox, 4, 1, 1, 1)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.gridLayout.addWidget(self.buttonBox, 12, 0, 1, 2)
|
||||
self.line = QtWidgets.QFrame(Dialog)
|
||||
@ -132,8 +132,6 @@ class Ui_Dialog(object):
|
||||
self.label_8.setBuddy(self.dest_combobox)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
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)
|
||||
|
@ -1,10 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'resources/_ui/smoothdialog.ui'
|
||||
# Form implementation generated from reading ui file 'src/resources/_ui/smoothdialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.12.3
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# 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
|
||||
@ -17,9 +18,37 @@ class Ui_SmoothDialog(object):
|
||||
self.gridLayout = QtWidgets.QGridLayout(SmoothDialog)
|
||||
self.gridLayout.setSpacing(3)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.gridLayout.addItem(spacerItem, 7, 0, 1, 1)
|
||||
self.frac_label = QtWidgets.QLabel(SmoothDialog)
|
||||
self.frac_label.setObjectName("frac_label")
|
||||
self.gridLayout.addWidget(self.frac_label, 1, 0, 1, 1)
|
||||
self.gridLayout.addWidget(self.frac_label, 2, 0, 1, 1)
|
||||
self.line = QtWidgets.QFrame(SmoothDialog)
|
||||
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.line.setObjectName("line")
|
||||
self.gridLayout.addWidget(self.line, 5, 0, 1, 2)
|
||||
self.widget = QtWidgets.QWidget(SmoothDialog)
|
||||
self.widget.setObjectName("widget")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget)
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_2.setSpacing(3)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.label = QtWidgets.QLabel(self.widget)
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout_2.addWidget(self.label)
|
||||
self.polynom_spinBox = QtWidgets.QSpinBox(self.widget)
|
||||
self.polynom_spinBox.setMinimum(1)
|
||||
self.polynom_spinBox.setMaximum(3)
|
||||
self.polynom_spinBox.setObjectName("polynom_spinBox")
|
||||
self.horizontalLayout_2.addWidget(self.polynom_spinBox)
|
||||
self.gridLayout.addWidget(self.widget, 3, 0, 1, 2)
|
||||
self.y_checkBox = QtWidgets.QCheckBox(SmoothDialog)
|
||||
self.y_checkBox.setObjectName("y_checkBox")
|
||||
self.gridLayout.addWidget(self.y_checkBox, 6, 1, 1, 1)
|
||||
self.x_checkBox = QtWidgets.QCheckBox(SmoothDialog)
|
||||
self.x_checkBox.setObjectName("x_checkBox")
|
||||
self.gridLayout.addWidget(self.x_checkBox, 6, 0, 1, 1)
|
||||
self.widget_2 = QtWidgets.QWidget(SmoothDialog)
|
||||
self.widget_2.setObjectName("widget_2")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget_2)
|
||||
@ -35,37 +64,17 @@ class Ui_SmoothDialog(object):
|
||||
self.iter_spinBox.setProperty("value", 1)
|
||||
self.iter_spinBox.setObjectName("iter_spinBox")
|
||||
self.horizontalLayout_3.addWidget(self.iter_spinBox)
|
||||
self.gridLayout.addWidget(self.widget_2, 3, 0, 1, 2)
|
||||
self.line = QtWidgets.QFrame(SmoothDialog)
|
||||
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.line.setObjectName("line")
|
||||
self.gridLayout.addWidget(self.line, 4, 0, 1, 2)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(SmoothDialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.gridLayout.addWidget(self.buttonBox, 7, 0, 1, 2)
|
||||
self.widget = QtWidgets.QWidget(SmoothDialog)
|
||||
self.widget.setObjectName("widget")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget)
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_2.setSpacing(3)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.label = QtWidgets.QLabel(self.widget)
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout_2.addWidget(self.label)
|
||||
self.polynom_spinBox = QtWidgets.QSpinBox(self.widget)
|
||||
self.polynom_spinBox.setMinimum(1)
|
||||
self.polynom_spinBox.setMaximum(3)
|
||||
self.polynom_spinBox.setObjectName("polynom_spinBox")
|
||||
self.horizontalLayout_2.addWidget(self.polynom_spinBox)
|
||||
self.gridLayout.addWidget(self.widget, 2, 0, 1, 2)
|
||||
self.gridLayout.addWidget(self.widget_2, 4, 0, 1, 2)
|
||||
self.frac_spinBox = QtWidgets.QSpinBox(SmoothDialog)
|
||||
self.frac_spinBox.setMinimum(1)
|
||||
self.frac_spinBox.setMaximum(999)
|
||||
self.frac_spinBox.setObjectName("frac_spinBox")
|
||||
self.gridLayout.addWidget(self.frac_spinBox, 1, 1, 1, 1)
|
||||
self.gridLayout.addWidget(self.frac_spinBox, 2, 1, 1, 1)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(SmoothDialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.gridLayout.addWidget(self.buttonBox, 8, 0, 1, 2)
|
||||
self.comboBox = QtWidgets.QComboBox(SmoothDialog)
|
||||
self.comboBox.setObjectName("comboBox")
|
||||
self.comboBox.addItem("")
|
||||
@ -77,22 +86,17 @@ class Ui_SmoothDialog(object):
|
||||
self.comboBox.addItem("")
|
||||
self.comboBox.addItem("")
|
||||
self.comboBox.addItem("")
|
||||
self.gridLayout.addWidget(self.comboBox, 0, 0, 1, 2)
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.gridLayout.addItem(spacerItem, 6, 0, 1, 1)
|
||||
self.y_checkBox = QtWidgets.QCheckBox(SmoothDialog)
|
||||
self.y_checkBox.setObjectName("y_checkBox")
|
||||
self.gridLayout.addWidget(self.y_checkBox, 5, 1, 1, 1)
|
||||
self.x_checkBox = QtWidgets.QCheckBox(SmoothDialog)
|
||||
self.x_checkBox.setObjectName("x_checkBox")
|
||||
self.gridLayout.addWidget(self.x_checkBox, 5, 0, 1, 1)
|
||||
self.gridLayout.addWidget(self.comboBox, 1, 0, 1, 2)
|
||||
self.label_2 = QtWidgets.QLabel(SmoothDialog)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 0, 0, 1, 2)
|
||||
self.frac_label.setBuddy(self.frac_spinBox)
|
||||
self.label_3.setBuddy(self.iter_spinBox)
|
||||
self.label.setBuddy(self.polynom_spinBox)
|
||||
self.label_3.setBuddy(self.iter_spinBox)
|
||||
|
||||
self.retranslateUi(SmoothDialog)
|
||||
self.buttonBox.accepted.connect(SmoothDialog.accept)
|
||||
self.buttonBox.rejected.connect(SmoothDialog.reject)
|
||||
self.buttonBox.accepted.connect(SmoothDialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(SmoothDialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(SmoothDialog)
|
||||
SmoothDialog.setTabOrder(self.comboBox, self.frac_spinBox)
|
||||
SmoothDialog.setTabOrder(self.frac_spinBox, self.polynom_spinBox)
|
||||
@ -104,9 +108,11 @@ class Ui_SmoothDialog(object):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
SmoothDialog.setWindowTitle(_translate("SmoothDialog", "1D smoothing filter"))
|
||||
self.frac_label.setText(_translate("SmoothDialog", "Window length"))
|
||||
self.label_3.setText(_translate("SmoothDialog", "Iterations"))
|
||||
self.label.setText(_translate("SmoothDialog", "Polynomial degree"))
|
||||
self.polynom_spinBox.setToolTip(_translate("SmoothDialog", "Deg"))
|
||||
self.y_checkBox.setText(_translate("SmoothDialog", "y log-spaced?"))
|
||||
self.x_checkBox.setText(_translate("SmoothDialog", "x log-spaced?"))
|
||||
self.label_3.setText(_translate("SmoothDialog", "Iterations"))
|
||||
self.frac_spinBox.setToolTip(_translate("SmoothDialog", "<html><head/><body><p>Number of data points used as smoothing window.</p></body></html>"))
|
||||
self.comboBox.setItemText(0, _translate("SmoothDialog", "Moving mean"))
|
||||
self.comboBox.setItemText(1, _translate("SmoothDialog", "Savitzky-Golay"))
|
||||
@ -117,5 +123,4 @@ class Ui_SmoothDialog(object):
|
||||
self.comboBox.setItemText(6, _translate("SmoothDialog", "Moving maximum"))
|
||||
self.comboBox.setItemText(7, _translate("SmoothDialog", "Moving minimum"))
|
||||
self.comboBox.setItemText(8, _translate("SmoothDialog", "Moving sum"))
|
||||
self.y_checkBox.setText(_translate("SmoothDialog", "y log-spaced?"))
|
||||
self.x_checkBox.setText(_translate("SmoothDialog", "x log-spaced?"))
|
||||
self.label_2.setText(_translate("SmoothDialog", "<html><head/><body><p><span style=\" font-weight:600;\">Note:</span> Sets must be sorted for correct results</p></body></html>"))
|
||||
|
@ -300,10 +300,12 @@ class ExperimentContainer(QtCore.QObject):
|
||||
self._relations.pop(relation_type)
|
||||
|
||||
def _update_actions(self):
|
||||
self.actions.update({'sort': self._data.sort,
|
||||
self.actions.update({
|
||||
'sort': self._data.sort,
|
||||
'cut': self._data.cut,
|
||||
'norm': self._data.normalize,
|
||||
'center': self.center})
|
||||
'center': self.center,
|
||||
})
|
||||
|
||||
@plot_update
|
||||
def update(self, opts: dict):
|
||||
@ -311,9 +313,11 @@ class ExperimentContainer(QtCore.QObject):
|
||||
|
||||
def get_properties(self) -> dict:
|
||||
props = OrderedDict()
|
||||
props['General'] = OrderedDict([('Name', self.name),
|
||||
props['General'] = OrderedDict([
|
||||
('Name', self.name),
|
||||
('Value', str(self.value)),
|
||||
('Group', str(self.group))])
|
||||
('Group', str(self.group)),
|
||||
])
|
||||
props['Symbol'] = OrderedDict()
|
||||
props['Line'] = OrderedDict()
|
||||
|
||||
@ -480,10 +484,12 @@ class ExperimentContainer(QtCore.QObject):
|
||||
else:
|
||||
prefix = f'g[{i}].s[{j}].'
|
||||
|
||||
namespace = {prefix + 'x': (self.x, 'x values'),
|
||||
namespace = {
|
||||
prefix + 'x': (self.x, 'x values'),
|
||||
prefix + 'y': [self.y, 'y values'],
|
||||
prefix + 'y_err': (self.y_err, 'y error values'),
|
||||
prefix + 'value': (self.value, str(self.value))}
|
||||
prefix + 'value': (self.value, str(self.value)),
|
||||
}
|
||||
|
||||
if len(self._fits) == 1:
|
||||
namespace.update({
|
||||
|
@ -17,7 +17,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
moveItem = QtCore.pyqtSignal(list, str, str, int) # items, from, to, new row
|
||||
copyItem = QtCore.pyqtSignal(list, str)
|
||||
saveFits = QtCore.pyqtSignal(list)
|
||||
extendFits = QtCore.pyqtSignal(list)
|
||||
extendFits = QtCore.pyqtSignal(list, bool)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def __init__(self, parent=None):
|
||||
@ -49,11 +49,16 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
|
||||
def add_graph(self, idd: str, name: str):
|
||||
item = QtWidgets.QTreeWidgetItem()
|
||||
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable |
|
||||
QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable)
|
||||
item.setFlags(
|
||||
QtCore.Qt.ItemFlag.ItemIsSelectable |
|
||||
QtCore.Qt.ItemFlag.ItemIsDropEnabled |
|
||||
QtCore.Qt.ItemFlag.ItemIsEditable |
|
||||
QtCore.Qt.ItemFlag.ItemIsEnabled |
|
||||
QtCore.Qt.ItemFlag.ItemIsUserCheckable
|
||||
)
|
||||
item.setText(0, name)
|
||||
item.setData(0, QtCore.Qt.UserRole, idd)
|
||||
item.setCheckState(0, QtCore.Qt.Checked)
|
||||
item.setData(0, QtCore.Qt.ItemDataRole.UserRole, idd)
|
||||
item.setCheckState(0, QtCore.Qt.CheckState.Checked)
|
||||
|
||||
self.addTopLevelItem(item)
|
||||
self._checked_graphs.add(idd)
|
||||
@ -67,14 +72,19 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
|
||||
for row in range(self.invisibleRootItem().childCount()):
|
||||
graph = self.invisibleRootItem().child(row)
|
||||
if graph.data(0, QtCore.Qt.UserRole) == gid:
|
||||
if graph.data(0, QtCore.Qt.ItemDataRole.UserRole) == gid:
|
||||
for (idd, name, value) in items:
|
||||
item = QtWidgets.QTreeWidgetItem([name])
|
||||
item.setToolTip(0, f'Value: {value}')
|
||||
item.setData(0, QtCore.Qt.UserRole, idd)
|
||||
item.setCheckState(0, QtCore.Qt.Checked)
|
||||
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsEditable |
|
||||
QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable)
|
||||
item.setData(0, QtCore.Qt.ItemDataRole.UserRole, idd)
|
||||
item.setCheckState(0, QtCore.Qt.CheckState.Checked)
|
||||
item.setFlags(
|
||||
QtCore.Qt.ItemFlag.ItemIsSelectable |
|
||||
QtCore.Qt.ItemFlag.ItemIsDragEnabled |
|
||||
QtCore.Qt.ItemFlag.ItemIsEditable |
|
||||
QtCore.Qt.ItemFlag.ItemIsEnabled |
|
||||
QtCore.Qt.ItemFlag.ItemIsUserCheckable
|
||||
)
|
||||
graph.addChild(item)
|
||||
self._checked_sets.add(idd)
|
||||
|
||||
@ -85,8 +95,8 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
|
||||
@QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem)
|
||||
def data_change(self, item: QtWidgets.QTreeWidgetItem, emit: bool = True) -> tuple[set, set]:
|
||||
idd = item.data(0, QtCore.Qt.UserRole)
|
||||
is_selected = item.checkState(0) == QtCore.Qt.Checked
|
||||
idd = item.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
is_selected = item.checkState(0) == QtCore.Qt.CheckState.Checked
|
||||
to_be_hidden = set()
|
||||
to_be_shown = set()
|
||||
|
||||
@ -104,9 +114,9 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
self.blockSignals(True)
|
||||
for i in range(item.childCount()):
|
||||
child = item.child(i)
|
||||
child.setCheckState(0, QtCore.Qt.Checked)
|
||||
to_be_shown.add(child.data(0, QtCore.Qt.UserRole))
|
||||
self._checked_sets.add(child.data(0, QtCore.Qt.UserRole))
|
||||
child.setCheckState(0, QtCore.Qt.CheckState.Checked)
|
||||
to_be_shown.add(child.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
self._checked_sets.add(child.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
self.blockSignals(False)
|
||||
|
||||
# check state change to unchecked
|
||||
@ -115,10 +125,10 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
self.blockSignals(True)
|
||||
for i in range(item.childCount()):
|
||||
child = item.child(i)
|
||||
child.setCheckState(0, QtCore.Qt.Unchecked)
|
||||
to_be_hidden.add(child.data(0, QtCore.Qt.UserRole))
|
||||
child.setCheckState(0, QtCore.Qt.CheckState.Unchecked)
|
||||
to_be_hidden.add(child.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
try:
|
||||
self._checked_sets.remove(child.data(0, QtCore.Qt.UserRole))
|
||||
self._checked_sets.remove(child.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
except KeyError:
|
||||
pass
|
||||
self.blockSignals(False)
|
||||
@ -153,7 +163,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
@QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem)
|
||||
def new_selection(self, item: QtWidgets.QTreeWidgetItem):
|
||||
if item.parent() is None:
|
||||
self.management.select_window(item.data(0, QtCore.Qt.UserRole))
|
||||
self.management.select_window(item.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
def dropEvent(self, evt: QtGui.QDropEvent):
|
||||
dropped_index = self.indexAt(evt.pos())
|
||||
@ -179,7 +189,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
|
||||
from_parent.removeChild(it)
|
||||
tobemoved.append(it)
|
||||
take_from.append(from_parent.data(0, QtCore.Qt.UserRole))
|
||||
take_from.append(from_parent.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
pos = QtCore.QModelIndex(persistent_drop)
|
||||
if self.dropIndicatorPosition() == QtWidgets.QAbstractItemView.BelowItem:
|
||||
@ -191,8 +201,8 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
else:
|
||||
to_parent.insertChildren(row, tobemoved)
|
||||
|
||||
self.management.move_sets([it.data(0, QtCore.Qt.UserRole) for it in tobemoved],
|
||||
to_parent.data(0, QtCore.Qt.UserRole), take_from,
|
||||
self.management.move_sets([it.data(0, QtCore.Qt.ItemDataRole.UserRole) for it in tobemoved],
|
||||
to_parent.data(0, QtCore.Qt.ItemDataRole.UserRole), take_from,
|
||||
pos=-1 if append else row)
|
||||
|
||||
self.update_indexes()
|
||||
@ -207,7 +217,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
if item is not None:
|
||||
data = item.data(0, QtCore.Qt.UserRole)
|
||||
data = item.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if data == gid_out:
|
||||
from_parent = item
|
||||
|
||||
@ -231,7 +241,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
self.blockSignals(False)
|
||||
|
||||
def sort(self, graph_item: QtWidgets.QTreeWidgetItem, mode: str = 'value'):
|
||||
graph_id = graph_item.data(0, QtCore.Qt.UserRole)
|
||||
graph_id = graph_item.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
sets = self.management.get_attributes(graph_id, mode)
|
||||
sets = [el[0] for el in sorted(sets.items(), key=lambda x: x[1])]
|
||||
|
||||
@ -243,7 +253,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
|
||||
for s in sets:
|
||||
for c in children:
|
||||
if c.data(0, QtCore.Qt.UserRole) == s:
|
||||
if c.data(0, QtCore.Qt.ItemDataRole.UserRole) == s:
|
||||
graph_item.addChild(c)
|
||||
|
||||
self.update_indexes()
|
||||
@ -276,7 +286,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
if item is not None:
|
||||
data = item.data(0, QtCore.Qt.UserRole)
|
||||
data = item.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if data == sid:
|
||||
if name != item.text(0):
|
||||
item.setText(0, name)
|
||||
@ -285,7 +295,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
iterator += 1
|
||||
|
||||
def keyPressEvent(self, evt: QtGui.QKeyEvent):
|
||||
if evt.key() == QtCore.Qt.Key_Delete:
|
||||
if evt.key() == QtCore.Qt.Key.Key_Delete:
|
||||
rm_sets = []
|
||||
rm_graphs = []
|
||||
for idx in self.selectedIndexes():
|
||||
@ -296,20 +306,20 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
if item.parent() is None:
|
||||
for c_i in range(item.childCount()):
|
||||
# add sets inside graph to removal
|
||||
child_data = item.child(c_i).data(0, QtCore.Qt.UserRole)
|
||||
child_data = item.child(c_i).data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if child_data not in rm_sets:
|
||||
rm_sets.append(child_data)
|
||||
rm_graphs.append(item.data(0, QtCore.Qt.UserRole))
|
||||
rm_graphs.append(item.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
else:
|
||||
item_data = item.data(0, QtCore.Qt.UserRole)
|
||||
item_data = item.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if item_data not in rm_sets:
|
||||
rm_sets.append(item_data)
|
||||
|
||||
# self.deleteItem.emit(rm_sets+rm_graphs)
|
||||
self.management.delete_sets(rm_sets+rm_graphs)
|
||||
|
||||
elif evt.key() == QtCore.Qt.Key_Space:
|
||||
elif evt.key() == QtCore.Qt.Key.Key_Space:
|
||||
sets = []
|
||||
from_parent = []
|
||||
|
||||
@ -329,7 +339,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
for it in sets:
|
||||
if it in from_parent:
|
||||
continue
|
||||
it.setCheckState(0, QtCore.Qt.Unchecked if it.checkState(0) == QtCore.Qt.Checked else QtCore.Qt.Checked)
|
||||
it.setCheckState(0, QtCore.Qt.CheckState.Unchecked if it.checkState(0) == QtCore.Qt.CheckState.Checked else QtCore.Qt.CheckState.Checked)
|
||||
s1, s2 = self.data_change(it, emit=False)
|
||||
to_be_hidden |= s2
|
||||
to_be_shown |= s1
|
||||
@ -353,7 +363,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
# find all items that have to be removed
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
_id = item.data(0, QtCore.Qt.UserRole)
|
||||
_id = item.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if _id in ids:
|
||||
try:
|
||||
item_parent = item.parent()
|
||||
@ -431,7 +441,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
if i.column() == 0:
|
||||
continue
|
||||
items.append(self.itemFromIndex(i))
|
||||
graphs.append(self.itemFromIndex(i).data(0, QtCore.Qt.UserRole))
|
||||
graphs.append(self.itemFromIndex(i).data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
if action == del_action:
|
||||
for gid in graphs:
|
||||
@ -455,7 +465,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
del_action = menu.addAction('Exterminate sets')
|
||||
cp_action = menu.addAction('Replicate sets')
|
||||
cat_action = menu.addAction('Join us!')
|
||||
plt_action = save_action = extend_action = None
|
||||
plt_action = save_action = extend_action = subfit_action = None
|
||||
menu.addSeparator()
|
||||
col_menu = menu.addMenu('Color cycle')
|
||||
for c in available_cycles.keys():
|
||||
@ -473,12 +483,12 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
continue
|
||||
|
||||
else:
|
||||
graph_id = parent.data(0, QtCore.Qt.UserRole)
|
||||
graph_id = parent.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if graph_id not in idx:
|
||||
idx[graph_id] = []
|
||||
# collect sets in their graph
|
||||
idx[graph_id].append(item.data(0, QtCore.Qt.UserRole))
|
||||
data = self.management[item.data(0, QtCore.Qt.UserRole)]
|
||||
idx[graph_id].append(item.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
data = self.management[item.data(0, QtCore.Qt.ItemDataRole.UserRole)]
|
||||
if data.mode == 'fit':
|
||||
has_fits = True
|
||||
|
||||
@ -487,6 +497,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
plt_action = menu.addAction('Plot fit parameter')
|
||||
save_action = menu.addAction('Save fit parameter')
|
||||
extend_action = menu.addAction('Extrapolate fit')
|
||||
subfit_action = menu.addAction('Plot partial functions')
|
||||
|
||||
action = menu.exec(evt.globalPos())
|
||||
|
||||
@ -494,6 +505,9 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
for gid, sets in idx.items():
|
||||
s.extend(sets)
|
||||
|
||||
if action is None:
|
||||
return
|
||||
|
||||
if action == del_action:
|
||||
self.management.delete_sets(s)
|
||||
|
||||
@ -511,7 +525,10 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
self.saveFits.emit(s)
|
||||
|
||||
elif action == extend_action:
|
||||
self.extendFits.emit(s)
|
||||
self.extendFits.emit(s, False)
|
||||
|
||||
elif action == subfit_action:
|
||||
self.extendFits.emit(s, True)
|
||||
|
||||
elif action.parent() == col_menu:
|
||||
self.management.set_cycle(s, action.text())
|
||||
@ -523,7 +540,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
if item is not None:
|
||||
if item.data(0, QtCore.Qt.UserRole) == gid:
|
||||
if item.data(0, QtCore.Qt.ItemDataRole.UserRole) == gid:
|
||||
item.setBackground(0, QtGui.QBrush(QtGui.QColor('gray')))
|
||||
else:
|
||||
item.setBackground(0, QtGui.QBrush())
|
||||
@ -536,10 +553,10 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
if item is not None:
|
||||
if item.data(0, QtCore.Qt.UserRole) in sets:
|
||||
item.setCheckState(0, QtCore.Qt.Unchecked)
|
||||
if item.data(0, QtCore.Qt.ItemDataRole.UserRole) in sets:
|
||||
item.setCheckState(0, QtCore.Qt.CheckState.Unchecked)
|
||||
else:
|
||||
self._checked_sets.add(item.data(0, QtCore.Qt.UserRole))
|
||||
self._checked_sets.add(item.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
iterator += 1
|
||||
self.blockSignals(False)
|
||||
|
||||
@ -594,7 +611,7 @@ class DataWidget(QtWidgets.QWidget, Ui_DataWidget):
|
||||
sid = []
|
||||
for i in self.tree.selectedIndexes():
|
||||
if i.column() == 0:
|
||||
sid.append(i.data(role=QtCore.Qt.UserRole))
|
||||
sid.append(i.data(role=QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
self.startShowProperty.emit(sid)
|
||||
|
||||
@ -603,15 +620,23 @@ class DataWidget(QtWidgets.QWidget, Ui_DataWidget):
|
||||
self.proptable.populate(props)
|
||||
|
||||
def change_property(self, key1, key2, value):
|
||||
ids = [item.data(0, QtCore.Qt.UserRole) for item in self.tree.selectedItems()]
|
||||
if key2 == 'Value':
|
||||
try:
|
||||
value = float(value)
|
||||
except ValueError:
|
||||
QtWidgets.QMessageBox.warning(self, 'Invalid entry',
|
||||
'Value %r is not a valid number for `value`.' % value)
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self,
|
||||
'Invalid entry',
|
||||
f'Value {value!r} is not a valid number for `value`.')
|
||||
return
|
||||
|
||||
ids = []
|
||||
for item in self.tree.selectedItems():
|
||||
ids.append(item.data(0, QtCore.Qt.ItemDataRole.UserRole))
|
||||
item.setToolTip(0, str(value))
|
||||
else:
|
||||
ids = [item.data(0, QtCore.Qt.ItemDataRole.UserRole) for item in self.tree.selectedItems()]
|
||||
|
||||
self.propertyChanged.emit(ids, key1, key2, value)
|
||||
|
||||
def uncheck_sets(self, sets: list[str]):
|
||||
|
@ -41,7 +41,7 @@ class PropWidget(QtWidgets.QWidget):
|
||||
idx = table.indexFromItem(item)
|
||||
self.propertyChanged.emit(self.tab.tabText(tab_idx),
|
||||
table.item(idx.row(), idx.column()-1).text(),
|
||||
item.data(QtCore.Qt.DisplayRole))
|
||||
item.data(QtCore.Qt.ItemDataRole.DisplayRole))
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def tab_change(self, idx: int):
|
||||
@ -66,10 +66,10 @@ class PropTable(QtWidgets.QTableWidget):
|
||||
self.blockSignals(True)
|
||||
for k, v in prop.items():
|
||||
value_item = QtWidgets.QTableWidgetItem('')
|
||||
value_item.setData(QtCore.Qt.DisplayRole, v)
|
||||
value_item.setData(QtCore.Qt.ItemDataRole.DisplayRole, v)
|
||||
|
||||
key_item = QtWidgets.QTableWidgetItem(k)
|
||||
key_item.setFlags(QtCore.Qt.NoItemFlags)
|
||||
key_item.setFlags(QtCore.Qt.ItemFlag.NoItemFlags)
|
||||
key_item.setForeground(QtGui.QBrush(QtGui.QColor(0, 0, 0)))
|
||||
|
||||
self.setRowCount(self.rowCount()+1)
|
||||
|
@ -413,7 +413,7 @@ class QPreviewDialog(QtWidgets.QDialog, Ui_ApodEdit):
|
||||
|
||||
vb = self.time_graph.getPlotItem().getViewBox()
|
||||
vb.disableAutoRange(axis=vb.YAxis)
|
||||
|
||||
if self._all_time is not None:
|
||||
self.zerofill_box.setVisible(self._all_time)
|
||||
self.apod_box.setVisible(self._all_time)
|
||||
self.shift_box.setVisible(self._all_time)
|
||||
|
@ -3,10 +3,10 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
|
||||
from numpy import ndarray, iscomplexobj, asarray
|
||||
from pyqtgraph import PlotDataItem
|
||||
|
||||
from ..Qt import QtGui, QtCore, QtWidgets
|
||||
from .._py.valueeditor import Ui_MaskDialog
|
||||
from ..lib.pg_objects import PlotItem
|
||||
|
||||
|
||||
class ValueEditWidget(QtWidgets.QWidget, Ui_MaskDialog):
|
||||
@ -35,12 +35,12 @@ class ValueEditWidget(QtWidgets.QWidget, Ui_MaskDialog):
|
||||
|
||||
self.tableView.setModel(self.model)
|
||||
self.tableView.setSelectionModel(self.selection_model)
|
||||
self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.tableView.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self.tableView.customContextMenuRequested.connect(self.ctx)
|
||||
|
||||
self.selection_real = PlotDataItem(x=[], y=[], symbolSize=25, symbol='x',
|
||||
self.selection_real = PlotItem(x=[], y=[], symbolSize=25, symbol='x',
|
||||
pen=None, symbolPen='#c9308e', symbolBrush='#c9308e')
|
||||
self.selection_imag = PlotDataItem(x=[], y=[], symbolSize=25, symbol='+',
|
||||
self.selection_imag = PlotItem(x=[], y=[], symbolSize=25, symbol='+',
|
||||
pen=None, symbolPen='#dcdcdc', symbolBrush='#dcdcdc')
|
||||
|
||||
def __call__(self, items: dict):
|
||||
@ -133,7 +133,7 @@ class ValueEditWidget(QtWidgets.QWidget, Ui_MaskDialog):
|
||||
def keyPressEvent(self, evt):
|
||||
if evt.matches(QtGui.QKeySequence.Copy):
|
||||
self.copy_selection()
|
||||
elif evt.key() == QtCore.Qt.Key_Delete:
|
||||
elif evt.key() == QtCore.Qt.Key.Key_Delete:
|
||||
self.delete_item()
|
||||
else:
|
||||
super().keyPressEvent(evt)
|
||||
@ -229,7 +229,7 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
"""
|
||||
itemChanged = QtCore.pyqtSignal(int, int, str)
|
||||
load_number = 20
|
||||
maskRole = QtCore.Qt.UserRole+321
|
||||
maskRole = QtCore.Qt.ItemDataRole.UserRole+321
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
@ -240,7 +240,7 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
self.mask = None
|
||||
self.headers = ['x', 'y', '\u0394y']
|
||||
for i, hd in enumerate(self.headers):
|
||||
self.setHeaderData(i, QtCore.Qt.Horizontal, hd)
|
||||
self.setHeaderData(i, QtCore.Qt.Orientation.Horizontal, hd)
|
||||
|
||||
def rowCount(self, *args, **kwargs) -> int:
|
||||
return self.total_rows
|
||||
@ -258,25 +258,28 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
self.mask = mask.tolist()
|
||||
|
||||
self.endResetModel()
|
||||
self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [QtCore.Qt.DisplayRole])
|
||||
self.dataChanged.emit(
|
||||
self.index(0, 0),
|
||||
self.index(0, 1), [QtCore.Qt.ItemDataRole.DisplayRole]
|
||||
)
|
||||
|
||||
def data(self, idx: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole) -> Any:
|
||||
def data(self, idx: QtCore.QModelIndex, role=QtCore.Qt.ItemDataRole.DisplayRole) -> Any:
|
||||
if not idx.isValid():
|
||||
return
|
||||
|
||||
row = idx.row()
|
||||
if role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]:
|
||||
if role in [QtCore.Qt.ItemDataRole.DisplayRole, QtCore.Qt.ItemDataRole.EditRole]:
|
||||
val = self._data[row][idx.column()]
|
||||
return self.as_string(val)
|
||||
|
||||
elif role == QtCore.Qt.BackgroundRole:
|
||||
elif role == QtCore.Qt.ItemDataRole.BackgroundRole:
|
||||
pal = QtGui.QGuiApplication.palette()
|
||||
if not self.mask[row]:
|
||||
return pal.color(QtGui.QPalette.Disabled, QtGui.QPalette.Base)
|
||||
else:
|
||||
return pal.color(QtGui.QPalette.Base)
|
||||
|
||||
elif role == QtCore.Qt.ForegroundRole:
|
||||
elif role == QtCore.Qt.ItemDataRole.ForegroundRole:
|
||||
pal = QtGui.QGuiApplication.palette()
|
||||
if not self.mask[row]:
|
||||
return pal.color(QtGui.QPalette.Disabled, QtGui.QPalette.Text)
|
||||
@ -289,7 +292,7 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
else:
|
||||
return
|
||||
|
||||
def setData(self, idx: QtCore.QModelIndex, value: str | bool, role=QtCore.Qt.DisplayRole) -> Any:
|
||||
def setData(self, idx: QtCore.QModelIndex, value: str | bool, role=QtCore.Qt.ItemDataRole.DisplayRole) -> Any:
|
||||
col, row = idx.column(), idx.row()
|
||||
|
||||
if role == ValueModel.maskRole:
|
||||
@ -299,7 +302,7 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
return True
|
||||
|
||||
if value:
|
||||
if role == QtCore.Qt.EditRole:
|
||||
if role == QtCore.Qt.ItemDataRole.EditRole:
|
||||
if value == self.as_string(self._data[row][col]):
|
||||
return True
|
||||
|
||||
@ -322,9 +325,9 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
else:
|
||||
return False
|
||||
|
||||
def headerData(self, section: int, orientation, role=QtCore.Qt.DisplayRole) -> Any:
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
if orientation == QtCore.Qt.Horizontal:
|
||||
def headerData(self, section: int, orientation, role=QtCore.Qt.ItemDataRole.DisplayRole) -> Any:
|
||||
if role == QtCore.Qt.ItemDataRole.DisplayRole:
|
||||
if orientation == QtCore.Qt.Orientation.Horizontal:
|
||||
return self.headers[section]
|
||||
else:
|
||||
return str(section+1)
|
||||
@ -346,7 +349,7 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
self.endInsertRows()
|
||||
|
||||
def flags(self, idx: QtCore.QModelIndex) -> QtCore.Qt.ItemFlag:
|
||||
return QtCore.QAbstractTableModel.flags(self, idx) | QtCore.Qt.ItemIsEditable
|
||||
return QtCore.QAbstractTableModel.flags(self, idx) | QtCore.Qt.ItemFlag.ItemIsEditable
|
||||
|
||||
def removeRows(self, pos: int, rows: int, parent=None, *args, **kwargs) -> bool:
|
||||
self.beginRemoveRows(parent, pos, pos+rows-1)
|
||||
@ -382,6 +385,6 @@ class ValueModel(QtCore.QAbstractTableModel):
|
||||
@staticmethod
|
||||
def as_string(value) -> str:
|
||||
if isinstance(value, complex):
|
||||
return f'{value.real:.8g}{value.imag:+.8g}j'
|
||||
return f'{value.real:.13g}{value.imag:+.13g}j'
|
||||
else:
|
||||
return f'{value:.8g}'
|
||||
return f'{value:.13g}'
|
||||
|
@ -136,8 +136,8 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
max_x = max(max_x, data.x.max())
|
||||
|
||||
item = QtWidgets.QListWidgetItem(name)
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
item.setData(QtCore.Qt.UserRole, key)
|
||||
item.setCheckState(QtCore.Qt.CheckState.Checked)
|
||||
item.setData(QtCore.Qt.ItemDataRole.UserRole, key)
|
||||
item.setForeground(mkBrush(c.rgb()))
|
||||
self.listWidget.addItem(item)
|
||||
|
||||
@ -191,10 +191,10 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
|
||||
for idx in range(self.listWidget.count()):
|
||||
item = self.listWidget.item(idx)
|
||||
if item.checkState() == QtCore.Qt.Unchecked:
|
||||
if item.checkState() == QtCore.Qt.CheckState.Unchecked:
|
||||
continue
|
||||
|
||||
key = item.data(QtCore.Qt.UserRole)
|
||||
key = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
plot = self._plots[key]
|
||||
data, _ = self._dsc[key]
|
||||
|
||||
@ -214,7 +214,7 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
item = self.listWidget.item(idx)
|
||||
|
||||
tree_item = QtWidgets.QTreeWidgetItem([item.text()])
|
||||
values = self._tg_value.get(item.data(QtCore.Qt.UserRole))
|
||||
values = self._tg_value.get(item.data(QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
if values is not None:
|
||||
for name, pos in values.items():
|
||||
@ -223,7 +223,7 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
|
||||
self.tg_tree.addTopLevelItem(tree_item)
|
||||
|
||||
key = item.data(QtCore.Qt.UserRole)
|
||||
key = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
plot = self._plots[key]
|
||||
data, _ = self._dsc[key]
|
||||
|
||||
@ -251,7 +251,7 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
@QtCore.pyqtSlot(QtWidgets.QListWidgetItem)
|
||||
def change_visibility(self, item: QtWidgets.QListWidgetItem):
|
||||
is_checked = bool(item.checkState())
|
||||
plot = self._plots[item.data(QtCore.Qt.UserRole)]
|
||||
plot = self._plots[item.data(QtCore.Qt.ItemDataRole.UserRole)]
|
||||
for val in plot:
|
||||
val.setVisible(is_checked)
|
||||
|
||||
@ -275,10 +275,10 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
self.tnmh_tree.clear()
|
||||
for idx in range(self.listWidget.count()):
|
||||
item = self.listWidget.item(idx)
|
||||
if item.checkState() == QtCore.Qt.Unchecked:
|
||||
if item.checkState() == QtCore.Qt.CheckState.Unchecked:
|
||||
continue
|
||||
|
||||
key = item.data(QtCore.Qt.UserRole)
|
||||
key = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
data = self.get_fictive(key, baselines)
|
||||
|
||||
@ -292,7 +292,7 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
item = self.listWidget.item(idx)
|
||||
|
||||
tree_item = QtWidgets.QTreeWidgetItem([item.text()])
|
||||
values = self._fit.get(item.data(QtCore.Qt.UserRole))
|
||||
values = self._fit.get(item.data(QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
if values is not None:
|
||||
child_item = QtWidgets.QTreeWidgetItem([values.parameter_string()])
|
||||
@ -305,10 +305,10 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
ret_dic = {}
|
||||
for idx in range(self.listWidget.count()):
|
||||
item = self.listWidget.item(idx)
|
||||
if item.checkState() == QtCore.Qt.Unchecked:
|
||||
if item.checkState() == QtCore.Qt.CheckState.Unchecked:
|
||||
continue
|
||||
|
||||
key = item.data(QtCore.Qt.UserRole)
|
||||
key = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
cp = None
|
||||
if self.fictive_export_check.isChecked():
|
||||
@ -332,10 +332,10 @@ class TgCalculator(QtWidgets.QWizard, Ui_DSCEvalDialog):
|
||||
m = []
|
||||
for idx in range(self.listWidget.count()):
|
||||
item = self.listWidget.item(idx)
|
||||
if item.checkState() == QtCore.Qt.Unchecked:
|
||||
if item.checkState() == QtCore.Qt.CheckState.Unchecked:
|
||||
continue
|
||||
|
||||
key = item.data(QtCore.Qt.UserRole)
|
||||
key = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
data, _ = self._dsc[key]
|
||||
try:
|
||||
tg_value = self._tg_value[key][tg_type][0]
|
||||
|
@ -1,138 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from nmreval.utils.text import convert
|
||||
|
||||
from ..Qt import QtCore, QtWidgets, QtGui
|
||||
from .._py.fitmodelwidget import Ui_FitParameter
|
||||
from .._py.save_fitmodel_dialog import Ui_SaveDialog
|
||||
from ..lib.iconloading import get_icon
|
||||
from ..lib.tables import TableWidget
|
||||
|
||||
|
||||
class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter):
|
||||
"""
|
||||
Widget to show a global parameter
|
||||
"""
|
||||
|
||||
value_requested = QtCore.pyqtSignal(object)
|
||||
value_changed = QtCore.pyqtSignal(str)
|
||||
state_changed = QtCore.pyqtSignal()
|
||||
replace_single_value = QtCore.pyqtSignal(object)
|
||||
|
||||
def __init__(self, label: str = 'Fitparameter', parent=None, fixed: bool = False):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.name = label
|
||||
|
||||
self.parametername.setText(convert(label) + ' ')
|
||||
|
||||
self.parameter_line.setText('1')
|
||||
self.parameter_line.setMaximumWidth(160)
|
||||
self.lineEdit.setMaximumWidth(100)
|
||||
self.lineEdit_2.setMaximumWidth(100)
|
||||
|
||||
self.label_3.setText(f'< {convert(label)} <')
|
||||
|
||||
self.checkBox.stateChanged.connect(self.enableBounds)
|
||||
self.global_checkbox.stateChanged.connect(lambda: self.state_changed.emit())
|
||||
self.parameter_line.editingFinished.connect(self.update_parameter)
|
||||
self.parameter_line.values_requested.connect(lambda: self.value_requested.emit(self))
|
||||
self.parameter_line.replace_single_values.connect(lambda: self.replace_single_value.emit(None))
|
||||
self.parameter_line.editingFinished.connect(lambda: self.value_changed.emit(self.parameter_line.text()))
|
||||
self.fixed_check.toggled.connect(self.set_fixed)
|
||||
|
||||
if fixed:
|
||||
self.fixed_check.hide()
|
||||
|
||||
self.parameter_pos = None
|
||||
self.func_idx = None
|
||||
|
||||
self._linetext = '1'
|
||||
|
||||
self.menu = QtWidgets.QMenu(self)
|
||||
|
||||
def set_parameter_string(self, p: str):
|
||||
self.parameter_line.setText(p)
|
||||
self.parameter_line.setToolTip(p)
|
||||
|
||||
def set_bounds(self, lb: float, ub: float, cbox: bool = True):
|
||||
self.checkBox.setCheckState(QtCore.Qt.Checked if cbox else QtCore.Qt.Unchecked)
|
||||
for val, bds_line in [(lb, self.lineEdit), (ub, self.lineEdit_2)]:
|
||||
if val is not None:
|
||||
bds_line.setText(str(val))
|
||||
else:
|
||||
bds_line.setText('')
|
||||
|
||||
def enableBounds(self, value: int):
|
||||
self.lineEdit.setEnabled(value == 2)
|
||||
self.lineEdit_2.setEnabled(value == 2)
|
||||
|
||||
def set_parameter(self, p: float | None, bds: tuple[float, float, bool] = None,
|
||||
fixed: bool = None, glob: bool = None):
|
||||
ptext = f'{p:.4g}'
|
||||
|
||||
self.set_parameter_string(ptext)
|
||||
|
||||
if bds is not None:
|
||||
self.set_bounds(*bds)
|
||||
|
||||
if fixed is not None:
|
||||
self.fixed_check.setCheckState(QtCore.Qt.CheckState.Unchecked if fixed else QtCore.Qt.CheckState.Checked)
|
||||
|
||||
if glob is not None:
|
||||
self.global_checkbox.setCheckState(QtCore.Qt.CheckState.Checked if glob else QtCore.Qt.CheckState.Unchecked)
|
||||
|
||||
def get_parameter(self):
|
||||
try:
|
||||
p = float(self.parameter_line.text().replace(',', '.'))
|
||||
except ValueError:
|
||||
p = self.parameter_line.text().replace(',', '.')
|
||||
|
||||
if self.checkBox.isChecked():
|
||||
lb_text = self.lineEdit.text()
|
||||
lb = None
|
||||
if lb_text:
|
||||
try:
|
||||
lb = float(lb_text.replace(',', '.'))
|
||||
except ValueError:
|
||||
lb = lb_text
|
||||
|
||||
ub_text = self.lineEdit_2.text()
|
||||
rb = None
|
||||
if ub_text:
|
||||
try:
|
||||
rb = float(ub_text.replace(',', '.'))
|
||||
except ValueError:
|
||||
rb = ub_text
|
||||
else:
|
||||
lb = rb = None
|
||||
|
||||
bounds = (lb, rb)
|
||||
|
||||
return p, bounds, not self.fixed_check.isChecked(), self.global_checkbox.isChecked()
|
||||
|
||||
@QtCore.pyqtSlot(bool)
|
||||
def set_fixed(self, state: bool):
|
||||
# self.global_checkbox.setVisible(not state)
|
||||
self.frame.setVisible(not state)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def update_parameter(self):
|
||||
new_value = self.parameter_line.text()
|
||||
if not new_value:
|
||||
self.parameter_line.setText('1')
|
||||
|
||||
try:
|
||||
float(new_value)
|
||||
is_text = False
|
||||
except ValueError:
|
||||
is_text = True
|
||||
self.global_checkbox.setCheckState(False)
|
||||
|
||||
self.set_fixed(is_text or self.fixed_check.isChecked())
|
||||
|
||||
|
||||
class QSaveModelDialog(QtWidgets.QDialog, Ui_SaveDialog):
|
||||
def __init__(self, types=None, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
@ -172,30 +45,37 @@ class FitModelTree(QtWidgets.QTreeWidget):
|
||||
treeChanged = QtCore.pyqtSignal()
|
||||
itemRemoved = QtCore.pyqtSignal(int)
|
||||
|
||||
counterRole = QtCore.Qt.UserRole + 1
|
||||
operatorRole = QtCore.Qt.UserRole + 2
|
||||
counterRole = QtCore.Qt.ItemDataRole.UserRole + 1
|
||||
operatorRole = QtCore.Qt.ItemDataRole.UserRole + 2
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setHeaderHidden(True)
|
||||
self.setDragEnabled(True)
|
||||
self.setDragDropMode(QtWidgets.QTreeWidget.InternalMove)
|
||||
self.setDefaultDropAction(QtCore.Qt.MoveAction)
|
||||
self.setDefaultDropAction(QtCore.Qt.DropAction.MoveAction)
|
||||
|
||||
self.itemSelectionChanged.connect(lambda: self.treeChanged.emit())
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
operators = [QtCore.Qt.Key_Plus, QtCore.Qt.Key_Asterisk,
|
||||
QtCore.Qt.Key_Minus, QtCore.Qt.Key_Slash]
|
||||
operators = [
|
||||
QtCore.Qt.Key.Key_Plus,
|
||||
QtCore.Qt.Key.Key_Asterisk,
|
||||
QtCore.Qt.Key.Key_Minus,
|
||||
QtCore.Qt.Key.Key_Slash
|
||||
]
|
||||
|
||||
if evt.key() == QtCore.Qt.Key_Delete:
|
||||
if evt.key() == QtCore.Qt.Key.Key_Delete:
|
||||
for item in self.selectedItems():
|
||||
self.remove_function(item)
|
||||
|
||||
elif evt.key() == QtCore.Qt.Key_Space:
|
||||
for item in self.treeWidget.selectedItems():
|
||||
item.setCheckState(0, QtCore.Qt.Checked) if item.checkState(
|
||||
0) == QtCore.Qt.Unchecked else item.setCheckState(0, QtCore.Qt.Unchecked)
|
||||
elif evt.key() == QtCore.Qt.Key.Key_Space:
|
||||
for item in self.selectedItems():
|
||||
cs = item.checkState(0)
|
||||
if cs == QtCore.Qt.CheckState.Unchecked:
|
||||
item.setCheckState(0, QtCore.Qt.CheckState.Checked)
|
||||
else:
|
||||
item.setCheckState(0, QtCore.Qt.CheckState.Unchecked)
|
||||
|
||||
elif evt.key() in operators:
|
||||
idx = operators.index(evt.key())
|
||||
@ -246,7 +126,7 @@ class FitModelTree(QtWidgets.QTreeWidget):
|
||||
color = QtGui.QColor(color)
|
||||
|
||||
it = QtWidgets.QTreeWidgetItem()
|
||||
it.setData(0, QtCore.Qt.UserRole, idx)
|
||||
it.setData(0, QtCore.Qt.ItemDataRole.UserRole, idx)
|
||||
it.setData(0, self.counterRole, cnt)
|
||||
it.setData(0, self.operatorRole, op)
|
||||
it.setText(0, name)
|
||||
@ -257,7 +137,7 @@ class FitModelTree(QtWidgets.QTreeWidget):
|
||||
it.setForeground(0, QtGui.QBrush(color))
|
||||
|
||||
it.setIcon(0, get_icon(self.icons[op]))
|
||||
it.setCheckState(0, QtCore.Qt.Checked if active else QtCore.Qt.Unchecked)
|
||||
it.setCheckState(0, QtCore.Qt.CheckState.Checked if active else QtCore.Qt.CheckState.Unchecked)
|
||||
|
||||
if parent is None:
|
||||
self.addTopLevelItem(it)
|
||||
@ -277,7 +157,7 @@ class FitModelTree(QtWidgets.QTreeWidget):
|
||||
def get_selected(self):
|
||||
try:
|
||||
it = self.selectedItems()[0]
|
||||
function_nr = it.data(0, QtCore.Qt.UserRole)
|
||||
function_nr = it.data(0, QtCore.Qt.ItemDataRole.UserRole)
|
||||
idx = it.data(0, self.counterRole)
|
||||
|
||||
except IndexError:
|
||||
@ -300,10 +180,10 @@ class FitModelTree(QtWidgets.QTreeWidget):
|
||||
it = parent.child(i)
|
||||
|
||||
child = {
|
||||
'idx': it.data(0, QtCore.Qt.UserRole),
|
||||
'idx': it.data(0, QtCore.Qt.ItemDataRole.UserRole),
|
||||
'op': it.data(0, self.operatorRole),
|
||||
'pos': pos,
|
||||
'active': (it.checkState(0) == QtCore.Qt.Checked),
|
||||
'active': (it.checkState(0) == QtCore.Qt.CheckState.Checked),
|
||||
'children': []
|
||||
}
|
||||
|
||||
@ -371,8 +251,8 @@ class FitTableWidget(TableWidget):
|
||||
|
||||
for (sid, name) in set_ids:
|
||||
item = QtWidgets.QTableWidgetItem(name)
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
item.setData(QtCore.Qt.UserRole+1, sid)
|
||||
item.setCheckState(QtCore.Qt.CheckState.Checked)
|
||||
item.setData(QtCore.Qt.ItemDataRole.UserRole+1, sid)
|
||||
row = self.rowCount()
|
||||
self.setRowCount(row+1)
|
||||
self.setItem(row, 0, item)
|
||||
@ -390,15 +270,15 @@ class FitTableWidget(TableWidget):
|
||||
|
||||
for i in range(self.rowCount()):
|
||||
item = self.item(i, 0)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
if item.checkState() == QtCore.Qt.CheckState.Checked:
|
||||
mod = self.cellWidget(i, 1).currentData()
|
||||
if mod is None:
|
||||
mod = default
|
||||
|
||||
if include_name:
|
||||
arg = (item.data(QtCore.Qt.UserRole+1), item.text())
|
||||
arg = (item.data(QtCore.Qt.ItemDataRole.UserRole+1), item.text())
|
||||
else:
|
||||
arg = item.data(QtCore.Qt.UserRole+1)
|
||||
arg = item.data(QtCore.Qt.ItemDataRole.UserRole+1)
|
||||
|
||||
if mod not in data:
|
||||
data[mod] = []
|
||||
@ -411,8 +291,8 @@ class FitTableWidget(TableWidget):
|
||||
for i in range(self.rowCount()):
|
||||
item = self.item(i, 0)
|
||||
if include_name:
|
||||
ret_val.append((item.data(QtCore.Qt.UserRole+1), item.text()))
|
||||
ret_val.append((item.data(QtCore.Qt.ItemDataRole.UserRole+1), item.text()))
|
||||
else:
|
||||
ret_val.append(item.data(QtCore.Qt.UserRole+1))
|
||||
ret_val.append(item.data(QtCore.Qt.ItemDataRole.UserRole+1))
|
||||
|
||||
return ret_val
|
||||
|
@ -1,14 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from nmreval.fit.parameter import Parameter
|
||||
from nmreval.utils.text import convert
|
||||
|
||||
from ..Qt import QtWidgets, QtCore, QtGui
|
||||
from .._py.fitfuncwidget import Ui_FormFit
|
||||
from .._py.fitmodelwidget import Ui_FitParameter
|
||||
from ..lib.forms import SelectionWidget
|
||||
from .fit_forms import FitModelWidget
|
||||
|
||||
|
||||
class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
@ -30,16 +28,15 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
self.scrollwidget2.setLayout(QtWidgets.QVBoxLayout())
|
||||
|
||||
def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent):
|
||||
modifiers = QtCore.Qt.KeyboardModifier.ControlModifier | QtCore.Qt.KeyboardModifier.ShiftModifier
|
||||
if isinstance(evt, QtGui.QKeyEvent):
|
||||
if (evt.key() == QtCore.Qt.Key_Right) and \
|
||||
(evt.modifiers() == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier):
|
||||
if (evt.key() == QtCore.Qt.Key.Key_Right) and (evt.modifiers() == modifiers):
|
||||
self.change_single_parameter(src.value, sender=src)
|
||||
self.select_next_preview(1)
|
||||
|
||||
return True
|
||||
|
||||
elif (evt.key() == QtCore.Qt.Key_Left) and \
|
||||
(evt.modifiers() == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier):
|
||||
elif (evt.key() == QtCore.Qt.Key.Key_Left) and (evt.modifiers() == modifiers):
|
||||
self.change_single_parameter(src.value, sender=src)
|
||||
self.select_next_preview(-1)
|
||||
|
||||
@ -65,7 +62,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
self.glob_values = [1] * len(func.params)
|
||||
|
||||
for k, v in enumerate(func.params):
|
||||
widgt = FitModelWidget(label=v, parent=self.scrollwidget)
|
||||
widgt = ParameterGlobalWidget(name=v, parent=self.scrollwidget)
|
||||
widgt.parameter_pos = k
|
||||
widgt.func_idx = idx
|
||||
try:
|
||||
@ -95,7 +92,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
for w1, w2 in zip(self.global_parameter, self.data_parameter):
|
||||
w1.parametername.setFixedSize(self.max_width)
|
||||
w1.checkBox.setFixedSize(self.max_width)
|
||||
w2.label.setFixedSize(self.max_width)
|
||||
w2.parametername.setFixedSize(self.max_width)
|
||||
|
||||
if hasattr(func, 'choices') and func.choices is not None:
|
||||
cbox = func.choices
|
||||
@ -175,7 +172,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
# disable single parameter if it is set global, enable if global is unset
|
||||
widget = self.sender()
|
||||
idx = self.global_parameter.index(widget)
|
||||
enable = (widget.global_checkbox.checkState() == QtCore.Qt.Unchecked)
|
||||
enable = (widget.global_checkbox.checkState() == QtCore.Qt.CheckState.Unchecked)
|
||||
self.data_parameter[idx].setEnabled(enable)
|
||||
|
||||
def select_next_preview(self, direction):
|
||||
@ -215,7 +212,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
param_general = []
|
||||
|
||||
for g in self.global_parameter:
|
||||
if isinstance(g, FitModelWidget):
|
||||
if isinstance(g, ParameterGlobalWidget):
|
||||
p_i, bds_i, fixed_i, global_i = g.get_parameter()
|
||||
parameter_i = Parameter(name=g.name, value=p_i, lb=bds_i[0], ub=bds_i[1], var=fixed_i)
|
||||
param_general.append(parameter_i)
|
||||
@ -236,7 +233,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
|
||||
p = []
|
||||
|
||||
for i, (p_i, g) in enumerate(zip(parameter, self.global_parameter)):
|
||||
if isinstance(g, FitModelWidget):
|
||||
if isinstance(g, ParameterGlobalWidget):
|
||||
if (p_i is None) or is_global[i]:
|
||||
# set has no oen value
|
||||
p.append(param_general[i].copy())
|
||||
@ -303,8 +300,8 @@ class ParameterSingleWidget(QtWidgets.QWidget):
|
||||
self._init_ui()
|
||||
|
||||
self.name = name
|
||||
self.label.setText(convert(name))
|
||||
self.label.setToolTip('If this is bold then this parameter is only for this data. '
|
||||
self.parametername.setText(convert(name))
|
||||
self.parametername.setToolTip('If 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())
|
||||
@ -316,8 +313,8 @@ class ParameterSingleWidget(QtWidgets.QWidget):
|
||||
layout.setContentsMargins(2, 2, 2, 2)
|
||||
layout.setSpacing(2)
|
||||
|
||||
self.label = QtWidgets.QLabel(self)
|
||||
layout.addWidget(self.label)
|
||||
self.parametername = QtWidgets.QLabel(self)
|
||||
layout.addWidget(self.parametername)
|
||||
|
||||
layout.addSpacerItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum))
|
||||
|
||||
@ -347,6 +344,133 @@ class ParameterSingleWidget(QtWidgets.QWidget):
|
||||
|
||||
def show_as_local_parameter(self, is_local: bool):
|
||||
if is_local:
|
||||
self.label.setStyleSheet('font-weight: bold;')
|
||||
self.parametername.setStyleSheet('font-weight: bold;')
|
||||
else:
|
||||
self.label.setStyleSheet('')
|
||||
self.parametername.setStyleSheet('')
|
||||
|
||||
|
||||
class ParameterGlobalWidget(QtWidgets.QWidget, Ui_FitParameter):
|
||||
"""
|
||||
Widget to show a global parameter
|
||||
"""
|
||||
|
||||
value_requested = QtCore.pyqtSignal(object)
|
||||
value_changed = QtCore.pyqtSignal(str)
|
||||
state_changed = QtCore.pyqtSignal()
|
||||
replace_single_value = QtCore.pyqtSignal(object)
|
||||
|
||||
def __init__(self, name: str = 'Fitparameter', parent=None, fixed: bool = False):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.name = name
|
||||
self.reset_button.setVisible(False)
|
||||
|
||||
self.parametername.setText(convert(name) + ' ')
|
||||
|
||||
self.parameter_line.setText('1')
|
||||
self.parameter_line.setMaximumWidth(160)
|
||||
self.lineEdit.setMaximumWidth(100)
|
||||
self.lineEdit_2.setMaximumWidth(100)
|
||||
|
||||
self.label_3.setText(f'< {convert(name)} <')
|
||||
|
||||
self.checkBox.stateChanged.connect(self.enableBounds)
|
||||
self.global_checkbox.stateChanged.connect(lambda: self.state_changed.emit())
|
||||
self.parameter_line.editingFinished.connect(self.update_parameter)
|
||||
self.parameter_line.values_requested.connect(lambda: self.value_requested.emit(self))
|
||||
self.parameter_line.replace_single_values.connect(lambda: self.replace_single_value.emit(None))
|
||||
self.parameter_line.editingFinished.connect(lambda: self.value_changed.emit(self.parameter_line.text()))
|
||||
self.fixed_check.toggled.connect(self.set_fixed)
|
||||
|
||||
if fixed:
|
||||
self.fixed_check.hide()
|
||||
|
||||
self.reset_button.setVisible(False)
|
||||
|
||||
self.parameter_pos = None
|
||||
self.func_idx = None
|
||||
|
||||
self._linetext = '1'
|
||||
|
||||
self.menu = QtWidgets.QMenu(self)
|
||||
|
||||
def set_parameter_string(self, p: str):
|
||||
self.parameter_line.setText(p)
|
||||
self.parameter_line.setToolTip(p)
|
||||
|
||||
def set_bounds(self, lb: float, ub: float, cbox: bool = True):
|
||||
self.checkBox.setCheckState(QtCore.Qt.CheckState.Checked if cbox else QtCore.Qt.CheckState.Unchecked)
|
||||
for val, bds_line in [(lb, self.lineEdit), (ub, self.lineEdit_2)]:
|
||||
if val is not None:
|
||||
bds_line.setText(str(val))
|
||||
else:
|
||||
bds_line.setText('')
|
||||
|
||||
def enableBounds(self, value: int):
|
||||
self.lineEdit.setEnabled(value == 2)
|
||||
self.lineEdit_2.setEnabled(value == 2)
|
||||
|
||||
def set_parameter(self, p: float | None, bds: tuple[float, float, bool] = None,
|
||||
fixed: bool = None, glob: bool = None):
|
||||
ptext = f'{p:.4g}'
|
||||
|
||||
self.set_parameter_string(ptext)
|
||||
|
||||
if bds is not None:
|
||||
self.set_bounds(*bds)
|
||||
|
||||
if fixed is not None:
|
||||
self.fixed_check.setCheckState(QtCore.Qt.CheckState.Unchecked if fixed else QtCore.Qt.CheckState.Checked)
|
||||
|
||||
if glob is not None:
|
||||
self.global_checkbox.setCheckState(QtCore.Qt.CheckState.Checked if glob else QtCore.Qt.CheckState.Unchecked)
|
||||
|
||||
def get_parameter(self):
|
||||
try:
|
||||
p = float(self.parameter_line.text().replace(',', '.'))
|
||||
except ValueError:
|
||||
p = self.parameter_line.text().replace(',', '.')
|
||||
|
||||
if self.checkBox.isChecked():
|
||||
lb_text = self.lineEdit.text()
|
||||
lb = None
|
||||
if lb_text:
|
||||
try:
|
||||
lb = float(lb_text.replace(',', '.'))
|
||||
except ValueError:
|
||||
lb = lb_text
|
||||
|
||||
ub_text = self.lineEdit_2.text()
|
||||
rb = None
|
||||
if ub_text:
|
||||
try:
|
||||
rb = float(ub_text.replace(',', '.'))
|
||||
except ValueError:
|
||||
rb = ub_text
|
||||
else:
|
||||
lb = rb = None
|
||||
|
||||
bounds = (lb, rb)
|
||||
|
||||
return p, bounds, not self.fixed_check.isChecked(), self.global_checkbox.isChecked()
|
||||
|
||||
@QtCore.pyqtSlot(bool)
|
||||
def set_fixed(self, state: bool):
|
||||
# self.global_checkbox.setVisible(not state)
|
||||
self.frame.setVisible(not state)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def update_parameter(self):
|
||||
new_value = self.parameter_line.text()
|
||||
if not new_value:
|
||||
self.parameter_line.setText('1')
|
||||
|
||||
try:
|
||||
float(new_value)
|
||||
is_text = False
|
||||
except ValueError:
|
||||
is_text = True
|
||||
self.global_checkbox.setCheckState(False)
|
||||
|
||||
self.set_fixed(is_text or self.fixed_check.isChecked())
|
||||
|
99
src/gui_qt/fit/fit_toolbar.py
Normal file
99
src/gui_qt/fit/fit_toolbar.py
Normal file
@ -0,0 +1,99 @@
|
||||
from ..Qt import QtWidgets, QtGui, QtCore
|
||||
from ..lib.iconloading import get_icon
|
||||
from ..lib.pg_objects import RegionItem
|
||||
|
||||
|
||||
class FitToolbar(QtWidgets.QToolBar):
|
||||
def __init__(
|
||||
self,
|
||||
fitaction: QtWidgets.QAction,
|
||||
limit_menu: QtWidgets.QMenu,
|
||||
parent=None,
|
||||
):
|
||||
super().__init__('Fit', parent=parent)
|
||||
|
||||
self.fit_action = fitaction
|
||||
self.region = RegionItem()
|
||||
self.addAction(fitaction)
|
||||
|
||||
self.fitlim_button = QtWidgets.QToolButton(self)
|
||||
self.fitlim_button.setMenu(limit_menu)
|
||||
self.fitlim_button.setPopupMode(self.fitlim_button.InstantPopup)
|
||||
self.fitlim_button.setIcon(get_icon('fit_region'))
|
||||
self.addWidget(self.fitlim_button)
|
||||
|
||||
self.label = QtWidgets.QLabel(self)
|
||||
self.label.setText('L: ')
|
||||
self.addWidget(self.label)
|
||||
self.label.setEnabled(False)
|
||||
|
||||
self.lineedit = QtWidgets.QLineEdit(self)
|
||||
self.lineedit.setValidator(QtGui.QDoubleValidator())
|
||||
self.lineedit.setMaximumWidth(92)
|
||||
self.addWidget(self.lineedit)
|
||||
self.lineedit.setEnabled(False)
|
||||
|
||||
self.label2 = QtWidgets.QLabel(self)
|
||||
self.label2.setText(' R: ')
|
||||
self.addWidget(self.label2)
|
||||
self.label2.setEnabled(False)
|
||||
|
||||
self.lineedit2 = QtWidgets.QLineEdit(self)
|
||||
self.lineedit2.setValidator(QtGui.QDoubleValidator())
|
||||
self.addWidget(self.lineedit2)
|
||||
self.lineedit2.setMaximumWidth(92)
|
||||
self.lineedit2.setEnabled(False)
|
||||
|
||||
self.limit_group = QtWidgets.QActionGroup(self)
|
||||
for ac in limit_menu.actions():
|
||||
self.limit_group.addAction(ac)
|
||||
|
||||
self.limit_group.triggered.connect(self.change_limit_type)
|
||||
|
||||
self.region.sigRegionChanged.connect(self.change_labels)
|
||||
self.change_labels()
|
||||
|
||||
self.lineedit.textChanged.connect(self.move_region)
|
||||
self.lineedit2.textChanged.connect(self.move_region)
|
||||
|
||||
@QtCore.pyqtSlot(QtWidgets.QAction)
|
||||
def change_limit_type(self, action: QtWidgets.QAction):
|
||||
is_custom = (action.text() in ['Custom', 'Exclude region'])
|
||||
print(is_custom)
|
||||
|
||||
for w in [self.label, self.label2, self.lineedit, self.lineedit2]:
|
||||
w.setEnabled(is_custom)
|
||||
|
||||
def change_labels(self):
|
||||
r = self.region.getRegion()
|
||||
self.lineedit.blockSignals(True)
|
||||
self.lineedit.setText(f'{r[0]:.4g}')
|
||||
self.lineedit.blockSignals(False)
|
||||
|
||||
self.lineedit2.blockSignals(True)
|
||||
self.lineedit2.setText(f'{r[1]:.4g}')
|
||||
self.lineedit2.blockSignals(False)
|
||||
|
||||
def move_region(self):
|
||||
try:
|
||||
r_min = float(self.lineedit.text())
|
||||
except ValueError:
|
||||
r_min = None
|
||||
|
||||
try:
|
||||
r_max = float(self.lineedit2.text())
|
||||
except ValueError:
|
||||
r_max = None
|
||||
|
||||
if r_min is not None and r_max is not None:
|
||||
self.region.setRegion((r_min, r_max), use_log=True)
|
||||
|
||||
def get_limit(self):
|
||||
action_text = self.limit_group.checkedAction().text()
|
||||
|
||||
return {
|
||||
'None': 'none',
|
||||
'Visible x range': 'x',
|
||||
'Custom': ('in', self.region.getRegion()),
|
||||
'Exclude region': ('out', self.region.getRegion()),
|
||||
}[action_text]
|
@ -165,7 +165,7 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
|
||||
self.iscomplex = False
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
f = self.functions[item.data(0, QtCore.Qt.UserRole)]
|
||||
f = self.functions[item.data(0, QtCore.Qt.ItemDataRole.UserRole)]
|
||||
if hasattr(f, 'iscomplex') and f.iscomplex:
|
||||
self.iscomplex = True
|
||||
break
|
||||
@ -226,7 +226,7 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
|
||||
iterator = QtWidgets.QTreeWidgetItemIterator(self.functree)
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
f = self.functions[item.data(0, QtCore.Qt.UserRole)]
|
||||
f = self.functions[item.data(0, QtCore.Qt.ItemDataRole.UserRole)]
|
||||
cnt = item.data(0, self.functree.counterRole)
|
||||
all_parameters[f'{f.name}_{cnt}'] = [(convert(pp, new='str'), (cnt, i)) for i, pp in enumerate(f.params)]
|
||||
|
||||
@ -240,7 +240,7 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
if item.checkState(0) != QtCore.Qt.CheckState.Unchecked:
|
||||
f = self.functions[item.data(0, QtCore.Qt.UserRole)]
|
||||
f = self.functions[item.data(0, QtCore.Qt.ItemDataRole.UserRole)]
|
||||
if hasattr(f, 'iscomplex') and f.iscomplex:
|
||||
iscomplex = True
|
||||
break
|
||||
|
@ -9,7 +9,6 @@ import numpy as np
|
||||
from pyqtgraph import mkPen
|
||||
|
||||
from nmreval.fit._meta import MultiModel, ModelFactory
|
||||
from nmreval.fit.data import Data
|
||||
from nmreval.fit.model import Model
|
||||
from nmreval.fit.parameter import Parameters
|
||||
from nmreval.fit.result import FitResult
|
||||
@ -42,8 +41,8 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
self._management = mgmt
|
||||
|
||||
self._current_model = next(QFitDialog.model_cnt)
|
||||
self.show_combobox.setItemData(0, self._current_model, QtCore.Qt.UserRole)
|
||||
self.default_combobox.setItemData(0, self._current_model, QtCore.Qt.UserRole)
|
||||
self.show_combobox.setItemData(0, self._current_model, QtCore.Qt.ItemDataRole.UserRole)
|
||||
self.default_combobox.setItemData(0, self._current_model, QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
self.data_table = FitTableWidget(self.data_widget)
|
||||
self.data_widget.addWidget(self.data_table)
|
||||
@ -150,9 +149,9 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
|
||||
# deselect all fit sets
|
||||
for i in range(self.data_table.rowCount()):
|
||||
data_id = self.data_table.item(i, 0).data(QtCore.Qt.UserRole+1)
|
||||
data_id = self.data_table.item(i, 0).data(QtCore.Qt.ItemDataRole.UserRole+1)
|
||||
if self._management[data_id].mode == 'fit' or self._management[data_id].has_relation(Relations.isFitPartOf):
|
||||
self.data_table.item(i, 0).setCheckState(QtCore.Qt.Unchecked)
|
||||
self.data_table.item(i, 0).setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||
|
||||
if self.models:
|
||||
for m in self.models.keys():
|
||||
@ -176,7 +175,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
|
||||
self.default_combobox.addItem('Model '+idx, userData=idx)
|
||||
self.show_combobox.addItem('Model '+idx, userData=idx)
|
||||
self.show_combobox.setItemData(self.show_combobox.count()-1, idx, QtCore.Qt.UserRole)
|
||||
self.show_combobox.setItemData(self.show_combobox.count()-1, idx, QtCore.Qt.ItemDataRole.UserRole)
|
||||
self.show_combobox.setCurrentIndex(self.show_combobox.count()-1)
|
||||
|
||||
self._current_model = idx
|
||||
@ -190,7 +189,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
self.get_functions()
|
||||
self.functionwidget.clear()
|
||||
|
||||
self._current_model = self.show_combobox.itemData(idx, QtCore.Qt.UserRole)
|
||||
self._current_model = self.show_combobox.itemData(idx, QtCore.Qt.ItemDataRole.UserRole)
|
||||
if self._current_model in self.models and len(self.models[self._current_model]):
|
||||
for el in self.models[self._current_model]:
|
||||
self.functionwidget.add_function(**el)
|
||||
@ -220,8 +219,14 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
if len(self.models) == 1:
|
||||
self.model_frame.hide()
|
||||
|
||||
def _prepare(self, model: list, function_use: list = None,
|
||||
parameter: dict = None, add_idx: bool = False, cnt: int = 0) -> tuple[dict, int]:
|
||||
def _prepare(
|
||||
self,
|
||||
model: list,
|
||||
function_use: list = None,
|
||||
parameter: dict = None,
|
||||
add_idx: bool = False,
|
||||
cnt: int = 0,
|
||||
) -> tuple[dict, int]:
|
||||
|
||||
if parameter is None:
|
||||
parameter = {
|
||||
@ -264,7 +269,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
|
||||
if f['children']:
|
||||
# recurse for children
|
||||
_, cnt = self._prepare(f['children'], parameter=parameter, add_idx=add_idx, cnt=cnt)
|
||||
_, cnt = self._prepare(f['children'], parameter=parameter, function_use=function_use, add_idx=add_idx, cnt=cnt)
|
||||
|
||||
return parameter, cnt
|
||||
|
||||
@ -276,7 +281,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
|
||||
func_dict = {}
|
||||
for model_name, model_parameter in self.models.items():
|
||||
func, order, param_len = ModelFactory.create_from_list(model_parameter)
|
||||
func, order, param_len, _ = ModelFactory.create_from_list(model_parameter)
|
||||
multiple_funcs = isinstance(func, MultiModel)
|
||||
if func is None:
|
||||
continue
|
||||
@ -388,7 +393,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
|
||||
func_dict = {}
|
||||
for k, mod in self.models.items():
|
||||
func, order, param_len = ModelFactory.create_from_list(mod)
|
||||
func, order, param_len, _ = ModelFactory.create_from_list(mod)
|
||||
multiple_funcs = isinstance(func, MultiModel)
|
||||
|
||||
if k in data:
|
||||
@ -496,7 +501,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog):
|
||||
if model_p['active']:
|
||||
cnt += self.param_widgets[model_p['cnt']].set_parameter(fit_id, param[cnt:])
|
||||
if model_p['children']:
|
||||
cnt += self.set_parameter_iter(fit_id, param, model_p['children'], cnt=cnt)
|
||||
cnt = self.set_parameter_iter(fit_id, param, model_p['children'], cnt=cnt)
|
||||
|
||||
return cnt
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from math import isnan
|
||||
|
||||
from pyqtgraph import mkBrush, mkPen
|
||||
from pyqtgraph import mkBrush, mkPen, mkColor
|
||||
from numpy import abs as np_abs, isfinite as np_isfinite
|
||||
|
||||
from nmreval.utils.text import convert
|
||||
@ -16,7 +18,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
closed = QtCore.pyqtSignal(dict, list, str, bool, bool, list)
|
||||
redoFit = QtCore.pyqtSignal(dict)
|
||||
|
||||
def __init__(self, results: list, management, parent=None):
|
||||
def __init__(self, results: list, sub_colors: dict, management, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
|
||||
@ -28,12 +30,14 @@ 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 = []
|
||||
self._results = {}
|
||||
self.graph_opts = {}
|
||||
self.last_idx = None
|
||||
self.func_colors = sub_colors
|
||||
|
||||
self.fit_plot = self.graphicsView.addPlot(row=1, col=0, title='Fit')
|
||||
self.resid_plot = self.graphicsView.addPlot(row=0, col=0, title='Residual')
|
||||
@ -45,21 +49,29 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.graphicsView.ci.layout.setRowStretchFactor(0, 1)
|
||||
self.graphicsView.ci.layout.setRowStretchFactor(1, 2)
|
||||
|
||||
self.resid_graph = PlotItem(x=[], y=[],
|
||||
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=[],
|
||||
pen=None
|
||||
)
|
||||
self.resid_graph_imag = PlotItem(
|
||||
x=[], y=[],
|
||||
symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)),
|
||||
pen=None)
|
||||
pen=None
|
||||
)
|
||||
self.resid_plot.addItem(self.resid_graph)
|
||||
self.resid_plot.addItem(self.resid_graph_imag)
|
||||
|
||||
self.data_graph = PlotItem(x=[], y=[],
|
||||
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=[],
|
||||
pen=None
|
||||
)
|
||||
self.data_graph_imag = PlotItem(
|
||||
x=[], y=[],
|
||||
symbol='s', symbolPen=None, symbolBrush=mkBrush(color=(255, 127, 14)),
|
||||
pen=None)
|
||||
pen=None
|
||||
)
|
||||
self.fit_plot.addItem(self.data_graph)
|
||||
self.fit_plot.addItem(self.data_graph_imag)
|
||||
|
||||
@ -82,13 +94,14 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
self.set_results(results)
|
||||
|
||||
def __call__(self, results: list):
|
||||
def __call__(self, results: list, sub_colors: dict):
|
||||
self._previous_fits = {}
|
||||
self.sets_comboBox.blockSignals(True)
|
||||
self.sets_comboBox.clear()
|
||||
self.sets_comboBox.blockSignals(False)
|
||||
self._results = {}
|
||||
self._opts = {}
|
||||
self.func_colors = sub_colors
|
||||
|
||||
self.set_results(results)
|
||||
|
||||
@ -190,10 +203,11 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.fit_graph.setData(x=res.x, y=res.y.real)
|
||||
self.fit_graph_imag.setData(x=res.x, y=res.y.imag)
|
||||
|
||||
for i, f in enumerate(sub_funcs):
|
||||
item = PlotItem(x=f.x, y=f.y.real, pen=mkPen({'color': i, 'style': 2}))
|
||||
for f, c in zip(sub_funcs, self.func_colors[idx]):
|
||||
col = mkColor(*[c_i*255 for c_i in c])
|
||||
item = PlotItem(x=f.x, y=f.y.real, pen=mkPen({'color': col, 'style': 2}))
|
||||
self.fit_plot.addItem(item)
|
||||
item = PlotItem(x=f.x, y=f.y.imag, pen=mkPen({'color': i, 'style': 2}))
|
||||
item = PlotItem(x=f.x, y=f.y.imag, pen=mkPen({'color': col, 'style': 2}))
|
||||
self.fit_plot.addItem(item)
|
||||
|
||||
else:
|
||||
@ -202,8 +216,8 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.fit_graph.setData(x=res.x, y=res.y)
|
||||
self.fit_graph_imag.setData(x=[], y=[])
|
||||
|
||||
for i, f in enumerate(sub_funcs):
|
||||
item = PlotItem(x=f.x, y=f.y, pen=mkPen({'color': i, 'style': 2}))
|
||||
for f, c in zip(sub_funcs, self.func_colors[idx]):
|
||||
item = PlotItem(x=f.x, y=f.y, pen=mkPen({'color': mkColor(*[c_i*255 for c_i in c]), 'style': 2}))
|
||||
self.fit_plot.addItem(item)
|
||||
|
||||
self._plot_residuals(idx)
|
||||
@ -217,8 +231,8 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
if idx in self.graph_opts:
|
||||
view_range, logx, logy = self.graph_opts[idx]
|
||||
self.fit_plot.setLogMode(x=logx, y=logy)
|
||||
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)
|
||||
@ -229,20 +243,16 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
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)
|
||||
|
||||
@ -356,7 +366,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:
|
||||
@ -372,6 +382,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
|
||||
@ -409,10 +421,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)
|
||||
|
||||
@ -420,12 +435,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
|
||||
|
@ -670,11 +670,14 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow):
|
||||
|
||||
else:
|
||||
if os.path.exists(outfile):
|
||||
if QtWidgets.QMessageBox.warning(self, 'Export graphic',
|
||||
if QtWidgets.QMessageBox.warning(
|
||||
self,
|
||||
'Export graphic',
|
||||
f'{os.path.split(outfile)[1]} already exists.\n'
|
||||
f'Do you REALLY want to replace it?',
|
||||
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
|
||||
QtWidgets.QMessageBox.No) == QtWidgets.QMessageBox.No:
|
||||
QtWidgets.QMessageBox.No
|
||||
) == QtWidgets.QMessageBox.No:
|
||||
return
|
||||
|
||||
bg_color = self._bgcolor
|
||||
@ -716,16 +719,20 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow):
|
||||
logger.exception(f'{item} could not exported because {e.args}')
|
||||
continue
|
||||
|
||||
if item_dic:
|
||||
if len(item) == 2:
|
||||
# plot can show errorbars
|
||||
if len(item_dic['x']):
|
||||
item_dic['yerr'] = item[1].opts['topData']
|
||||
|
||||
if item_dic:
|
||||
else:
|
||||
item_dic['yerr'] = []
|
||||
dic['items'].append(item_dic)
|
||||
|
||||
for item in self._external_items:
|
||||
try:
|
||||
dic['items'].append(item.get_data_opts())
|
||||
item_dic = item.get_data_opts()
|
||||
if item_dic:
|
||||
dic['items'].append(item_dic)
|
||||
except Exception as e:
|
||||
logger.exception(f'{item} could not be exported because {e.args}')
|
||||
continue
|
||||
|
@ -38,7 +38,7 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
self.changestaggeredrange(0)
|
||||
|
||||
self.ascii_table.contextMenuEvent = self.ctx_table
|
||||
self.ascii_table.horizontalHeader().setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.ascii_table.horizontalHeader().setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self.ascii_table.horizontalHeader().customContextMenuRequested.connect(self.ctx_table)
|
||||
|
||||
self.skip = False
|
||||
@ -65,7 +65,7 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
self.set_column_names(1)
|
||||
|
||||
self.skippy_checkbox.blockSignals(True)
|
||||
self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.skippy_checkbox.setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||
self.skippy_checkbox.blockSignals(False)
|
||||
|
||||
return self
|
||||
@ -132,7 +132,10 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
self.ascii_table.setHorizontalHeaderLabels(map(str, range(1, self.ascii_table.columnCount() + 1)))
|
||||
if self.column_checkBox.isChecked() and self.line_spinBox.isEnabled():
|
||||
header_line = self.reader.header[self.line_spinBox.value()-1]
|
||||
self.ascii_table.setHorizontalHeaderLabels(header_line.split())
|
||||
header_line = header_line.strip('\n\t\r, ')
|
||||
header_line = re.sub(r'[\t ;,]+', ';', header_line)
|
||||
|
||||
self.ascii_table.setHorizontalHeaderLabels(header_line.split(';'))
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_staggered_checkBox_stateChanged')
|
||||
def changestaggeredrange(self, state: int):
|
||||
@ -178,11 +181,12 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
@QtCore.pyqtSlot()
|
||||
def accept(self):
|
||||
if self.apply():
|
||||
self.close()
|
||||
super().accept()
|
||||
|
||||
def apply(self):
|
||||
# default row for x is the first row, it will be superseded if an integer number is given.
|
||||
x = self.x_lineedit.text()
|
||||
is_valid = True
|
||||
if x:
|
||||
try:
|
||||
x = int(x)-1
|
||||
@ -191,16 +195,35 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
else:
|
||||
x = None
|
||||
|
||||
if not self.check_column_numbers(x, max(self.reader.width)):
|
||||
_ = QtWidgets.QMessageBox.information(self, 'Improper input',
|
||||
f'Input for x axis is invalid')
|
||||
return False
|
||||
|
||||
try:
|
||||
y = [int(t)-1 for t in self.y_lineedit.text().split(' ')]
|
||||
except ValueError:
|
||||
y = None
|
||||
|
||||
if not self.check_column_numbers(y, max(self.reader.width)):
|
||||
_ = QtWidgets.QMessageBox.information(self, 'Improper input',
|
||||
f'Input for y axis is invalid')
|
||||
return False
|
||||
|
||||
try:
|
||||
y_err = [int(t)-1 for t in self.deltay_lineEdit.text().split(' ')]
|
||||
except ValueError:
|
||||
y_err = None
|
||||
|
||||
mode = self.buttonGroup.checkedButton().text()
|
||||
if mode != 'Points':
|
||||
y_err = None
|
||||
|
||||
if not self.check_column_numbers(y, max(self.reader.width)):
|
||||
_ = QtWidgets.QMessageBox.information(self, 'Improper input',
|
||||
f'Input for y_err axis is invalid')
|
||||
return False
|
||||
|
||||
col_header = None
|
||||
if self.column_checkBox.isChecked():
|
||||
col_header = []
|
||||
@ -218,21 +241,22 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
x=x,
|
||||
y=y,
|
||||
yerr=y_err,
|
||||
mode=self.buttonGroup.checkedButton().text(),
|
||||
mode=mode,
|
||||
col_names=col_header,
|
||||
num_value=self.get_numerical_value(),
|
||||
)
|
||||
self.data_read.emit(ret_dic)
|
||||
|
||||
except ImportError as e:
|
||||
except Exception as e:
|
||||
_ = QtWidgets.QMessageBox.information(self, 'Reading failed',
|
||||
f'Import data failed with {e.args}')
|
||||
f'Import data failed with\n {e.args[0]}')
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_buttonGroup_buttonClicked')
|
||||
def show_error(self, val: int):
|
||||
self.deltay_lineEdit.setEnabled(val == -3)
|
||||
self.deltay_lineEdit.setEnabled(val == -2)
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_skippy_checkbox_stateChanged')
|
||||
def skip_next_dial(self, _: int):
|
||||
@ -281,7 +305,7 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
else:
|
||||
self.label_8.setText(fname)
|
||||
|
||||
def get_numerical_value(self):
|
||||
def get_numerical_value(self) -> float:
|
||||
val = 0
|
||||
if self.re_button.isChecked() and self._matches:
|
||||
m = self._matches[self.re_match_index.value()-1]
|
||||
@ -292,3 +316,21 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
|
||||
val = float(self.custom_input.text())
|
||||
|
||||
return val
|
||||
|
||||
def check_column_numbers(self, values: int | list[int] | str | None, num_column: int) -> bool:
|
||||
is_valid = False
|
||||
if values is None:
|
||||
is_valid = True
|
||||
elif values == 'index':
|
||||
is_valid = True
|
||||
|
||||
elif isinstance(values, int):
|
||||
is_valid = values < num_column
|
||||
elif isinstance(values, list):
|
||||
try:
|
||||
is_valid = all(v < num_column for v in values)
|
||||
except TypeError:
|
||||
is_valid = False
|
||||
|
||||
return is_valid
|
||||
|
||||
|
@ -78,14 +78,22 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
for opts in self.sample.steps:
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable)
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
item.setFlags(
|
||||
QtCore.Qt.ItemFlag.ItemIsEnabled |
|
||||
QtCore.Qt.ItemFlag.ItemIsSelectable |
|
||||
QtCore.Qt.ItemFlag.ItemIsUserCheckable
|
||||
)
|
||||
item.setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||
|
||||
if opts[0] == 'i':
|
||||
item.setFlags(QtCore.Qt.NoItemFlags)
|
||||
item.setFlags(QtCore.Qt.ItemFlag.NoItemFlags)
|
||||
item.setText(f'{opts[1]:.2f} K for {opts[2] / 60:.0f} min')
|
||||
else:
|
||||
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable)
|
||||
item.setFlags(
|
||||
QtCore.Qt.ItemFlag.ItemIsEnabled |
|
||||
QtCore.Qt.ItemFlag.ItemIsSelectable |
|
||||
QtCore.Qt.ItemFlag.ItemIsUserCheckable
|
||||
)
|
||||
item.setText(f'{opts[2]:.2f} K to {opts[3]:.2f} K with {opts[1]} K/min')
|
||||
|
||||
self.step_listWidget.addItem(item)
|
||||
@ -97,7 +105,12 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
if empty:
|
||||
self.empty = self.calibrator.set_measurement(empty, mode='empty')
|
||||
|
||||
# avoid ValueError breaking data update
|
||||
if self.empty.fname.is_relative_to(Path.home()):
|
||||
self.empty_label.setText('~/' + str(self.empty.fname.relative_to(Path.home())))
|
||||
else:
|
||||
self.empty_label.setText(str(self.empty.fname))
|
||||
|
||||
self.update_plots()
|
||||
|
||||
@ -118,8 +131,8 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
self.references.append(ref)
|
||||
item = QtWidgets.QTableWidgetItem(str(ref.fname.name))
|
||||
item.setData(QtCore.Qt.UserRole, ref.fname)
|
||||
item.setFlags(QtCore.Qt.ItemIsEnabled)
|
||||
item.setData(QtCore.Qt.ItemDataRole.UserRole, ref.fname)
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
|
||||
rowcnt = self.reference_tableWidget.rowCount()
|
||||
self.reference_tableWidget.setRowCount(rowcnt+1)
|
||||
@ -132,7 +145,7 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
@QtCore.pyqtSlot(name='on_ref_remove_pushButton_clicked')
|
||||
def remove_reference(self):
|
||||
idx = self.reference_tableWidget.currentRow()
|
||||
self.calibrator.remove_reference(self.reference_tableWidget.item(idx, 0).data(QtCore.Qt.UserRole))
|
||||
self.calibrator.remove_reference(self.reference_tableWidget.item(idx, 0).data(QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
self.reference_tableWidget.removeRow(idx)
|
||||
self.update_plots()
|
||||
@ -145,10 +158,10 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
for row in range(self.step_listWidget.count()):
|
||||
if idx == row:
|
||||
continue
|
||||
self.step_listWidget.item(row).setCheckState(QtCore.Qt.Unchecked)
|
||||
self.step_listWidget.item(row).setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||
self.step_listWidget.blockSignals(False)
|
||||
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
if item.checkState() == QtCore.Qt.CheckState.Checked:
|
||||
mode, rate, _, _ = self.sample.steps[idx]
|
||||
self.current_run = (rate, mode)
|
||||
self.sample_idx = idx
|
||||
@ -217,6 +230,8 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
if empty_data is not None:
|
||||
self.empty_sample.setData(x=empty_data[0], y=empty_data[1])
|
||||
else:
|
||||
self.empty_sample.setData(x=[], y=[])
|
||||
|
||||
self.calib_graph.clear()
|
||||
|
||||
@ -249,11 +264,16 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
||||
except TypeError:
|
||||
return
|
||||
|
||||
if self.cp_checkBox.isChecked() and self.references:
|
||||
y_label = 'cp'
|
||||
else:
|
||||
y_label = 'q'
|
||||
|
||||
rate, mode = self.current_run
|
||||
new_val = DSC(sample_data[0], sample_data[1], value=rate, name=f'{self.fname.stem} {rate} ({mode})')
|
||||
new_val = DSC(sample_data[0], sample_data[1], value=rate, name=f'{self.fname.stem} {rate}K-min ({mode}, {y_label})')
|
||||
|
||||
if filesave:
|
||||
new_val.savetxt(self.fname.with_name(f'{self.fname.stem} {rate}K-min {mode}.dat'.replace(' ', '_')))
|
||||
new_val.savetxt(self.fname.with_name(f'{self.fname.stem}_{rate}K-min_{y_label}{mode}.dat'.replace(' ', '_')))
|
||||
close_after = False
|
||||
else:
|
||||
self.data_read.emit([new_val])
|
||||
|
@ -22,14 +22,22 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
|
||||
self.start_lineedit.setValidator(QtGui.QDoubleValidator())
|
||||
self.stop_lineedit.setValidator(QtGui.QDoubleValidator())
|
||||
|
||||
self.graph_checkbox.stateChanged.connect(lambda x: self.graph_comboBox.setEnabled(not bool(x)))
|
||||
self.graph_checkbox.stateChanged.connect(
|
||||
lambda x: self.graph_comboBox.setEnabled(x == QtCore.Qt.CheckState.Unchecked)
|
||||
)
|
||||
|
||||
self.listWidget.installEventFilter(self)
|
||||
|
||||
def __call__(self, path=None):
|
||||
if path is None:
|
||||
path = pathlib.Path().home()
|
||||
self.path = path
|
||||
self.listWidget.clear()
|
||||
|
||||
def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent) -> bool:
|
||||
# intercept key press in listwidget to allow deletion with Del
|
||||
if evt.type() == QtCore.QEvent.KeyPress:
|
||||
if evt.key() == QtCore.Qt.Key_Delete:
|
||||
if evt.type() == QtCore.QEvent.Type.KeyPress:
|
||||
if evt.key() == QtCore.Qt.Key.Key_Delete:
|
||||
self.listWidget.takeItem(self.listWidget.currentRow())
|
||||
return True
|
||||
|
||||
@ -41,21 +49,25 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_region_checkBox_stateChanged')
|
||||
def use_region(self, state: int):
|
||||
self.start_lineedit.setEnabled(state == QtCore.Qt.Checked)
|
||||
self.stop_lineedit.setEnabled(state == QtCore.Qt.Checked)
|
||||
self.start_lineedit.setEnabled(state == QtCore.Qt.CheckState.Checked)
|
||||
self.stop_lineedit.setEnabled(state == QtCore.Qt.CheckState.Checked)
|
||||
|
||||
@QtCore.pyqtSlot(name='on_file_pushbutton_clicked')
|
||||
@QtCore.pyqtSlot(name='on_dir_pushbutton_clicked')
|
||||
def get_input(self):
|
||||
if self.sender() == self.file_pushbutton:
|
||||
infiles, _ = QtWidgets.QFileDialog.getOpenFileNames(caption='Select HDF files',
|
||||
infiles, _ = QtWidgets.QFileDialog.getOpenFileNames(
|
||||
caption='Select HDF files',
|
||||
directory=str(self.path),
|
||||
filter='HDF files (*.h5)')
|
||||
filter='HDF files (*.h5)',
|
||||
)
|
||||
|
||||
else:
|
||||
infiles = QtWidgets.QFileDialog.getExistingDirectory(caption='Select input directory',
|
||||
infiles = QtWidgets.QFileDialog.getExistingDirectory(
|
||||
caption='Select input directory',
|
||||
directory=str(self.path),
|
||||
options=QtWidgets.QFileDialog.ShowDirsOnly)
|
||||
options=QtWidgets.QFileDialog.ShowDirsOnly,
|
||||
)
|
||||
infiles = [infiles] if infiles else infiles
|
||||
|
||||
if infiles:
|
||||
@ -65,14 +77,18 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
|
||||
|
||||
@QtCore.pyqtSlot(name='on_savebutton_clicked')
|
||||
def save_path(self):
|
||||
outfile = QtWidgets.QFileDialog.getExistingDirectory(self, caption='Select directory',
|
||||
outfile = QtWidgets.QFileDialog.getExistingDirectory(
|
||||
self,
|
||||
caption='Select directory',
|
||||
directory=self.label.text(),
|
||||
options=QtWidgets.QFileDialog.ShowDirsOnly)
|
||||
options=QtWidgets.QFileDialog.ShowDirsOnly,
|
||||
)
|
||||
if outfile:
|
||||
self.label.setText(outfile)
|
||||
|
||||
def accept(self):
|
||||
items = [self.listWidget.item(i).text() for i in range(self.listWidget.count())]
|
||||
print(items)
|
||||
if items:
|
||||
with busy_cursor():
|
||||
self.read(items)
|
||||
@ -107,9 +123,10 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
|
||||
|
||||
ret_vals = []
|
||||
ret_vals.extend(fc_eval.get_parameter(path=self.label.text(), kind='temp', parameter=save_variables))
|
||||
print(ret_vals)
|
||||
|
||||
grp = ''
|
||||
if not self.graph_checkbox.isChecked():
|
||||
grp = self.graph_comboBox.currentData(QtCore.Qt.UserRole)
|
||||
grp = self.graph_comboBox.currentData(QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
self.data_read.emit(ret_vals, grp)
|
||||
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
import struct
|
||||
|
||||
from ..Qt import QtCore
|
||||
from ..Qt import QtCore, QtWidgets
|
||||
from .asciireader import QAsciiReader
|
||||
from .hdfreader import QHdfViewer
|
||||
from .bdsreader import QBDSReader
|
||||
@ -26,8 +26,12 @@ class QFileReader(QtCore.QObject):
|
||||
self.reader = {}
|
||||
|
||||
for ext, reader in [
|
||||
('txt', QAsciiReader), ('dsc', QDSCReader), ('agr', QGraceReader),
|
||||
('bds', QBDSReader), ('hdf', QHdfViewer), ('nmr', QNMRReader)
|
||||
('txt', QAsciiReader),
|
||||
('dsc', QDSCReader),
|
||||
('agr', QGraceReader),
|
||||
('bds', QBDSReader),
|
||||
('hdf', QHdfViewer),
|
||||
('nmr', QNMRReader),
|
||||
]:
|
||||
self.register(ext, reader)
|
||||
|
||||
@ -47,6 +51,7 @@ class QFileReader(QtCore.QObject):
|
||||
if not isinstance(fname, list):
|
||||
fname = [fname]
|
||||
|
||||
status = QtWidgets.QDialog.Accepted
|
||||
for f in fname:
|
||||
f = Path(f)
|
||||
dtype = self.guess_type(f)
|
||||
@ -57,7 +62,10 @@ class QFileReader(QtCore.QObject):
|
||||
|
||||
try:
|
||||
# If QAsciiReader.skip = True it accepts automatically and returns None
|
||||
r(f).exec()
|
||||
if status == QtWidgets.QDialog.DialogCode.Rejected and isinstance(r, QAsciiReader) and self.reader['txt'].skip:
|
||||
break
|
||||
status = r(f).exec()
|
||||
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from .codeeditor import _make_textformats
|
||||
from ..Qt import QtWidgets, QtCore, QtGui
|
||||
from nmreval.configs import config_paths
|
||||
@ -113,3 +116,28 @@ class QLog(QtWidgets.QDialog):
|
||||
|
||||
for lines in text[-100:]:
|
||||
self.plainTextEdit.appendPlainText(lines[:-1])
|
||||
|
||||
|
||||
class ConsoleDock(QtWidgets.QDockWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.code = QtWidgets.QPlainTextEdit(parent)
|
||||
self.code.highlight = LogHighlighter(self.code.document())
|
||||
self.code.setReadOnly(True)
|
||||
self.code.setMaximumBlockCount(50)
|
||||
self.setWidget(self.code)
|
||||
|
||||
|
||||
class QTextHandler(logging.Handler):
|
||||
def __init__(self, parent):
|
||||
super().__init__()
|
||||
|
||||
self.console = ConsoleDock(parent)
|
||||
self.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
|
||||
self.setLevel(logging.WARNING)
|
||||
|
||||
def emit(self, record):
|
||||
msg = self.format(record)
|
||||
self.console.code.appendPlainText(msg)
|
||||
self.console.show()
|
||||
|
@ -22,7 +22,8 @@ class Namespace:
|
||||
|
||||
if basic:
|
||||
self.add_namespace(
|
||||
{'x': (None, 'x values'),
|
||||
{
|
||||
'x': (None, 'x values'),
|
||||
'y': (None, 'x values'),
|
||||
'y_err': (None, 'y error values'),
|
||||
'fit': (None, 'dictionary of fit parameter', 'fit["PIKA"]'),
|
||||
@ -32,7 +33,8 @@ class Namespace:
|
||||
)
|
||||
|
||||
self.add_namespace(
|
||||
{'sin': (np.sin, 'Sine', 'sin(PIKA)'),
|
||||
{
|
||||
'sin': (np.sin, 'Sine', 'sin(PIKA)'),
|
||||
'cos': (np.cos, 'Cosine', 'cos(PIKA)'),
|
||||
'tan': (np.tan, 'Tangens', 'tan(PIKA)'),
|
||||
'ln': (np.log, 'Natural Logarithm', 'ln(PIKA)'),
|
||||
@ -45,7 +47,8 @@ class Namespace:
|
||||
parents=('Basic', 'Functions'))
|
||||
|
||||
self.add_namespace(
|
||||
{'max': (np.max, 'Maximum value', 'max(PIKA)'),
|
||||
{
|
||||
'max': (np.max, 'Maximum value', 'max(PIKA)'),
|
||||
'min': (np.min, 'Minimum value', 'min(PIKA)'),
|
||||
'argmax': (np.argmax, 'Index of maximum value', 'argmax(PIKA)'),
|
||||
'argmin': (np.argmax, 'Index of minimum value', 'argmin(PIKA)'),
|
||||
@ -54,19 +57,24 @@ class Namespace:
|
||||
|
||||
if const:
|
||||
self.add_namespace(
|
||||
{'e': (constants.e, 'e / As'),
|
||||
{
|
||||
'e': (constants.e, 'e / As'),
|
||||
'eps0': (constants.epsilon0, 'epsilon0 / As/Vm'),
|
||||
'Eu': (constants.Eu,), 'h': (constants.h, 'h / eVs'),
|
||||
'hbar': (constants.hbar, 'hbar / eVs'), 'kB': (constants.kB, 'kB / eV/K'),
|
||||
'mu0': (constants.mu0, 'mu0 / Vs/Am'), 'NA': (constants.NA, 'NA / 1/mol'),
|
||||
'pi': (constants.pi,), 'R': (constants.R, 'R / eV'),
|
||||
'Eu': (constants.Eu,),
|
||||
'h': (constants.h, 'h / eVs'),
|
||||
'hbar': (constants.hbar, 'hbar / eVs'),
|
||||
'kB': (constants.kB, 'kB / eV/K'),
|
||||
'mu0': (constants.mu0, 'mu0 / Vs/Am'),
|
||||
'NA': (constants.NA, 'NA / 1/mol'),
|
||||
'pi': (constants.pi,),
|
||||
'R': (constants.R, 'R / eV'),
|
||||
},
|
||||
parents=('Constants', 'Maybe useful'),
|
||||
)
|
||||
|
||||
self.add_namespace(
|
||||
{f'gamma["{k}"]': (v, k, f'gamma["{k}"]') for k, v in constants.gamma.items()},
|
||||
parents=('Constants', 'Magnetogyric ratios (in 1/(sT))')
|
||||
parents=('Constants', 'Gyromagnetic ratios (in 1/(sT))')
|
||||
)
|
||||
|
||||
if fitfuncs:
|
||||
@ -199,7 +207,7 @@ class QNamespaceWidget(QtWidgets.QWidget, Ui_Form):
|
||||
|
||||
for entry in subspace:
|
||||
key_item = QtWidgets.QTableWidgetItem(entry)
|
||||
key_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
key_item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
|
||||
vals = self.namespace.namespace[entry]
|
||||
|
||||
@ -214,12 +222,12 @@ class QNamespaceWidget(QtWidgets.QWidget, Ui_Form):
|
||||
display = vals[1]
|
||||
|
||||
value_item = QtWidgets.QTableWidgetItem(display)
|
||||
value_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
value_item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
|
||||
key_item.setData(QtCore.Qt.UserRole, alias)
|
||||
key_item.setData(QtCore.Qt.UserRole+1, entry)
|
||||
value_item.setData(QtCore.Qt.UserRole, alias)
|
||||
value_item.setData(QtCore.Qt.UserRole+1, entry)
|
||||
key_item.setData(QtCore.Qt.ItemDataRole.UserRole, alias)
|
||||
key_item.setData(QtCore.Qt.ItemDataRole.UserRole+1, entry)
|
||||
value_item.setData(QtCore.Qt.ItemDataRole.UserRole, alias)
|
||||
value_item.setData(QtCore.Qt.ItemDataRole.UserRole+1, entry)
|
||||
|
||||
row = self.namespace_table.rowCount()
|
||||
self.namespace_table.setRowCount(row+1)
|
||||
@ -241,5 +249,5 @@ class QNamespaceWidget(QtWidgets.QWidget, Ui_Form):
|
||||
|
||||
@QtCore.pyqtSlot(QtWidgets.QTableWidgetItem, name='on_namespace_table_itemDoubleClicked')
|
||||
def item_selected(self, item: QtWidgets.QTableWidgetItem):
|
||||
self.selected.emit(item.data(QtCore.Qt.UserRole))
|
||||
self.sendKey.emit(item.data(QtCore.Qt.UserRole+1))
|
||||
self.selected.emit(item.data(QtCore.Qt.ItemDataRole.UserRole))
|
||||
self.sendKey.emit(item.data(QtCore.Qt.ItemDataRole.UserRole+1))
|
||||
|
@ -183,6 +183,8 @@ class PlotItem(PlotDataItem):
|
||||
brush = self.opts['symbolBrush']
|
||||
if isinstance(brush, tuple):
|
||||
self.opts['symbolcolor'] = brush
|
||||
elif isinstance(brush, str):
|
||||
self.opts['symbolcolor'] = int(f'0x{brush[1:3]}', 16), int(f'0x{brush[3:5]}', 16), int(f'0x{brush[5:7]}', 16)
|
||||
else:
|
||||
c = brush.color()
|
||||
self.opts['symbolcolor'] = c.red(), c.green(), c.blue()
|
||||
@ -340,7 +342,8 @@ class PlotItem(PlotDataItem):
|
||||
|
||||
opts = self.opts
|
||||
item_dic = {
|
||||
'x': x, 'y': y,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'name': opts.get('name', ''),
|
||||
'symbolsize': opts['symbolSize'],
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ from ..Qt import QtGui, QtWidgets, QtCore
|
||||
@contextmanager
|
||||
def busy_cursor():
|
||||
try:
|
||||
cursor = QtGui.QCursor(QtCore.Qt.ForbiddenCursor)
|
||||
cursor = QtGui.QCursor(QtCore.Qt.CursorShape.ForbiddenCursor)
|
||||
QtWidgets.QApplication.setOverrideCursor(cursor)
|
||||
yield
|
||||
|
||||
|
3
src/gui_qt/main/console.py
Normal file
3
src/gui_qt/main/console.py
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
|
@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from numpy import geomspace, linspace
|
||||
@ -13,17 +12,18 @@ from nmreval.lib.logger import logger
|
||||
from nmreval.io.sessionwriter import NMRWriter
|
||||
|
||||
from .management import UpperManagement
|
||||
from ..lib.logger import QTextHandler
|
||||
from ..Qt import QtGui, QtPrintSupport
|
||||
from ..data.shift_graphs import QShift
|
||||
from ..data.signaledit import QPreviewDialog, QBaselineDialog
|
||||
from ..dsc.glass_dialog import TgCalculator
|
||||
from ..fit.fit_toolbar import FitToolbar
|
||||
from ..fit.result import FitExtension, QFitResult
|
||||
from ..graphs.graphwindow import QGraphWindow
|
||||
from ..graphs.movedialog import QMover
|
||||
from ..io.fcbatchreader import QFCReader
|
||||
from ..io.filedialog import *
|
||||
from ..lib.iconloading import make_action_icons, get_icon
|
||||
from ..lib.pg_objects import RegionItem
|
||||
from ..lib.starter import make_starter
|
||||
from ..math.binning import BinningWindow
|
||||
from ..math.evaluation import QEvalDialog
|
||||
@ -62,6 +62,13 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.fitresult_dialog = None
|
||||
self.eval = None
|
||||
self.editor = None
|
||||
self._interpol_dialog = None
|
||||
self.fc_reader = None
|
||||
|
||||
self.logtext = QTextHandler(self)
|
||||
logger.addHandler(self.logtext)
|
||||
self.addDockWidget(QtCore.Qt.DockWidgetArea.BottomDockWidgetArea, self.logtext.console)
|
||||
self.logtext.console.hide()
|
||||
|
||||
self.movedialog = QMover(self)
|
||||
|
||||
@ -97,12 +104,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.norm_toolbutton.setIcon(get_icon('normal'))
|
||||
self.toolbar_edit.addWidget(self.norm_toolbutton)
|
||||
|
||||
self.fitlim_button = QtWidgets.QToolButton(self)
|
||||
self.fitlim_button.setMenu(self.menuLimits)
|
||||
self.fitlim_button.setPopupMode(self.fitlim_button.InstantPopup)
|
||||
self.fitlim_button.setIcon(get_icon('fit_region'))
|
||||
self.toolBar_fit.addWidget(self.fitlim_button)
|
||||
|
||||
while self.tabWidget.count() > 2:
|
||||
self.tabWidget.removeTab(self.tabWidget.count()-1)
|
||||
|
||||
@ -120,9 +121,11 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.statusBar.addWidget(self.mousepos)
|
||||
|
||||
self.fitregion = RegionItem()
|
||||
self._fit_plot_id = None
|
||||
|
||||
self.fit_toolbar = FitToolbar(self.action_FitWidget, self.menuLimits, self)
|
||||
self.addToolBar(self.fit_toolbar)
|
||||
|
||||
self.setGeometry(QtWidgets.QStyle.alignedRect(
|
||||
QtCore.Qt.LayoutDirection.LeftToRight,
|
||||
QtCore.Qt.AlignmentFlag.AlignCenter,
|
||||
@ -138,11 +141,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.ac_group.addAction(self.action_nm_fit)
|
||||
self.ac_group.addAction(self.action_odr_fit)
|
||||
|
||||
self.ac_group2 = QtWidgets.QActionGroup(self)
|
||||
self.ac_group2.addAction(self.action_no_range)
|
||||
self.ac_group2.addAction(self.action_x_range)
|
||||
self.ac_group2.addAction(self.action_custom_range)
|
||||
|
||||
def _init_signals(self):
|
||||
self.actionRedo = self.management.undostack.createRedoAction(self)
|
||||
icon = QtGui.QIcon.fromTheme("edit-redo")
|
||||
@ -158,7 +156,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
|
||||
self.action_save_fit_parameter.triggered.connect(self.save_fit_parameter)
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.ac_group2.triggered.connect(self.change_fit_limits)
|
||||
self.fit_toolbar.limit_group.triggered.connect(self.change_fit_limits)
|
||||
|
||||
self.t1action.triggered.connect(lambda: self._show_tab('t1_temp'))
|
||||
self.action_edit.triggered.connect(self.do_preview)
|
||||
@ -237,7 +235,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.action_norm_first.triggered.connect(lambda: self.management.apply('norm', ('first',)))
|
||||
self.action_norm_last.triggered.connect(lambda: self.management.apply('norm', ('last',)))
|
||||
self.action_norm_area.triggered.connect(lambda: self.management.apply('norm', ('area',)))
|
||||
self.action_cut.triggered.connect(lambda: self.management.cut())
|
||||
self.action_cut_xaxis.triggered.connect(lambda: self.management.cut(True, False))
|
||||
self.action_cut_yaxis.triggered.connect(lambda: self.management.cut(False, True))
|
||||
|
||||
self.actionConcatenate_sets.triggered.connect(lambda: self.management.cat())
|
||||
|
||||
@ -268,14 +267,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
|
||||
@QtCore.pyqtSlot(name='on_actionOpen_FC_triggered')
|
||||
def read_fc(self):
|
||||
reader = QFCReader(path=self.path, parent=self)
|
||||
reader.add_graphs(self.management.graphs.list())
|
||||
reader.data_read.connect(self.management.add_new_data)
|
||||
reader.exec()
|
||||
if self.fc_reader is None:
|
||||
self.fc_reader = QFCReader(path=self.path, parent=self)
|
||||
self.fc_reader.data_read.connect(self.management.add_new_data)
|
||||
else:
|
||||
self.fc_reader(path=self.path)
|
||||
self.fc_reader.add_graphs(self.management.graphs.list())
|
||||
self.fc_reader.exec()
|
||||
|
||||
self.path = reader.path
|
||||
|
||||
del reader
|
||||
self.path = self.fc_reader.path
|
||||
|
||||
@QtCore.pyqtSlot(name='on_actionPrint_triggered')
|
||||
def print(self):
|
||||
@ -705,10 +705,13 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
return
|
||||
|
||||
gnames = self.management.graphs.tree()
|
||||
dialog = InterpolDialog(parent=self)
|
||||
dialog.set_data(gnames, self.current_graph_widget.id)
|
||||
dialog.new_data.connect(self.management.interpolate_data)
|
||||
dialog.show()
|
||||
if self._interpol_dialog is None:
|
||||
self._interpol_dialog = InterpolDialog(parent=self)
|
||||
self._interpol_dialog.new_data.connect(self.management.interpolate_data)
|
||||
else:
|
||||
self._interpol_dialog()
|
||||
self._interpol_dialog.set_data(gnames, self.current_graph_widget.id)
|
||||
self._interpol_dialog.show()
|
||||
|
||||
@QtCore.pyqtSlot(name='on_action_calc_triggered')
|
||||
def open_eval_dialog(self):
|
||||
@ -898,30 +901,29 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.fit_dialog.load(self.management.active_sets)
|
||||
for item in self.fit_dialog.preview_lines:
|
||||
self.current_graph_widget.add_external(item)
|
||||
if self.action_custom_range.isChecked():
|
||||
self.current_graph_widget.add_external(self.fitregion)
|
||||
if self.action_custom_range.isChecked() or self.actionExclude_region.isChecked():
|
||||
self.current_graph_widget.add_external(self.fit_toolbar.region)
|
||||
|
||||
block_window = True
|
||||
else:
|
||||
for item in self.fit_dialog.preview_lines:
|
||||
self.current_graph_widget.remove_external(item)
|
||||
self.current_graph_widget.remove_external(self.fitregion)
|
||||
self.current_graph_widget.remove_external(self.fit_toolbar.region)
|
||||
|
||||
return block_window
|
||||
|
||||
@QtCore.pyqtSlot(QtWidgets.QAction)
|
||||
def change_fit_limits(self, action: QtWidgets.QAction):
|
||||
if action == self.action_custom_range and self.fit_dialog.isVisible():
|
||||
self.current_graph_widget.add_external(self.fitregion)
|
||||
if self.current_graph_widget is None:
|
||||
return
|
||||
|
||||
if action in [self.action_custom_range, self.actionExclude_region] and self.fit_dialog.isVisible():
|
||||
self.current_graph_widget.add_external(self.fit_toolbar.region)
|
||||
else:
|
||||
self.current_graph_widget.remove_external(self.fitregion)
|
||||
self.current_graph_widget.remove_external(self.fit_toolbar.region)
|
||||
|
||||
def start_fit(self, parameter, links, fit_options):
|
||||
fit_options['limits'] = {
|
||||
self.action_no_range: 'none',
|
||||
self.action_x_range: 'x',
|
||||
self.action_custom_range: self.fitregion.getRegion()
|
||||
}[self.ac_group2.checkedAction()]
|
||||
fit_options['limits'] = self.fit_toolbar.get_limit()
|
||||
|
||||
fit_options['fit_mode'] = {
|
||||
self.action_lm_fit: 'lsq',
|
||||
@ -957,19 +959,19 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
for item in self.fit_dialog.preview_lines:
|
||||
g.add_external(item)
|
||||
|
||||
@QtCore.pyqtSlot(list)
|
||||
def show_fit_results(self, results: list):
|
||||
@QtCore.pyqtSlot(list, dict)
|
||||
def show_fit_results(self, results: list, sub_colors: dict[str, tuple[float, float, float]]):
|
||||
self.fit_dialog.fit_button.setEnabled(True)
|
||||
self.fit_timer.stop()
|
||||
self.status.setText('')
|
||||
if results:
|
||||
if self.fitresult_dialog is None:
|
||||
self.fitresult_dialog = QFitResult(results, self.management, parent=self)
|
||||
self.fitresult_dialog = QFitResult(results, sub_colors, 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(results, sub_colors)
|
||||
self.fitresult_dialog.add_graphs(self.management.graphs.list())
|
||||
self.fitresult_dialog.show()
|
||||
|
||||
@ -989,14 +991,19 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.editor.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||
self.editor.show()
|
||||
|
||||
@QtCore.pyqtSlot(list)
|
||||
def extend_fit(self, sets: list):
|
||||
@QtCore.pyqtSlot(list, bool)
|
||||
def extend_fit(self, sets: list, only_subplots: bool):
|
||||
if only_subplots:
|
||||
self.management.extend_fits(sets, None, True)
|
||||
return
|
||||
|
||||
w = FitExtension(self)
|
||||
res = w.exec()
|
||||
if res:
|
||||
p = w.values
|
||||
x = linspace(p[0], p[1], num=p[2])
|
||||
self.management.extend_fits(sets, x)
|
||||
spacefunc = geomspace if p[3] else linspace
|
||||
x = spacefunc(p[0], p[1], num=p[2])
|
||||
self.management.extend_fits(sets, x, False)
|
||||
|
||||
@QtCore.pyqtSlot(name='on_action_create_fit_function_triggered')
|
||||
def open_fitmodel_wizard(self):
|
||||
|
@ -85,7 +85,7 @@ class UpperManagement(QtCore.QObject):
|
||||
newData = QtCore.pyqtSignal([list, str], [list, str, bool])
|
||||
deleteData = QtCore.pyqtSignal(list)
|
||||
dataChanged = QtCore.pyqtSignal(str)
|
||||
fitFinished = QtCore.pyqtSignal(list)
|
||||
fitFinished = QtCore.pyqtSignal(list, dict)
|
||||
stopFit = QtCore.pyqtSignal()
|
||||
properties_collected = QtCore.pyqtSignal(dict)
|
||||
unset_state = QtCore.pyqtSignal(list)
|
||||
@ -428,6 +428,7 @@ class UpperManagement(QtCore.QObject):
|
||||
self.graphs[d.graph].update_legend(identifier, name)
|
||||
elif identifier in self.graphs:
|
||||
self.graphs[identifier].title = name
|
||||
self.graphs.valueChanged.emit()
|
||||
else:
|
||||
raise KeyError('Unknown ID ' + str(identifier))
|
||||
|
||||
@ -449,10 +450,17 @@ class UpperManagement(QtCore.QObject):
|
||||
self.undostack.push(single_undo)
|
||||
self.undostack.endMacro()
|
||||
|
||||
def cut(self):
|
||||
def cut(self, x: bool = False, y: bool = False) -> None:
|
||||
if self.current_graph:
|
||||
xlim, _ = self.graphs[self.current_graph].ranges
|
||||
self.apply('cut', xlim)
|
||||
xlim, ylim = self.graphs[self.current_graph].ranges
|
||||
|
||||
if x is False:
|
||||
xlim = (None, None)
|
||||
|
||||
if y is False:
|
||||
ylim = (None, None)
|
||||
|
||||
self.apply('cut', (*xlim, *ylim))
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def unmask(self):
|
||||
@ -503,29 +511,46 @@ class UpperManagement(QtCore.QObject):
|
||||
we = we_option
|
||||
|
||||
if m_complex is None or m_complex == 1:
|
||||
# model is not complex: m_complex = None
|
||||
# model is complex, fit real part: m_complex = 1
|
||||
_y = data_i.y.real
|
||||
elif m_complex == 2 and np.iscomplexobj(data_i.y):
|
||||
data_complex = 1
|
||||
elif m_complex == 2:
|
||||
# model is complex, fit imag part: m_complex = 2
|
||||
if np.iscomplexobj(data_i.y):
|
||||
# data is complex, use imag part
|
||||
_y = data_i.y.imag
|
||||
data_complex = 2
|
||||
else:
|
||||
# data is real
|
||||
_y = data_i.y
|
||||
data_complex = 1
|
||||
else:
|
||||
# model is complex, fit complex: m_complex = 0
|
||||
# use data as given (complex or not)
|
||||
_y = data_i.y
|
||||
data_complex = 0
|
||||
|
||||
_x = data_i.x
|
||||
|
||||
# options for fit limits 'none', 'x', ('in', custom region), ('out', excluded region)
|
||||
if fit_limits == 'none':
|
||||
inside = slice(None)
|
||||
elif fit_limits == 'x':
|
||||
x_lim, _ = self.graphs[self.current_graph].ranges
|
||||
inside = np.where((_x >= x_lim[0]) & (_x <= x_lim[1]))
|
||||
elif fit_limits[0] == 'in':
|
||||
inside = np.where((_x >= fit_limits[1][0]) & (_x <= fit_limits[1][1]))
|
||||
else:
|
||||
inside = np.where((_x >= fit_limits[0]) & (_x <= fit_limits[1]))
|
||||
inside = np.where((_x < fit_limits[1][0]) | (_x > fit_limits[1][1]))
|
||||
|
||||
try:
|
||||
if isinstance(we, str):
|
||||
d = fit_d.Data(_x[inside], _y[inside], we=we, idx=set_id)
|
||||
d = fit_d.Data(_x[inside], _y[inside], we=we, idx=set_id, complex_type=data_complex)
|
||||
else:
|
||||
d = fit_d.Data(_x[inside], _y[inside], we=we[inside], idx=set_id)
|
||||
d = fit_d.Data(_x[inside], _y[inside], we=we[inside], idx=set_id, complex_type=data_complex)
|
||||
except Exception as e:
|
||||
raise Exception(f'Setting data failed for {set_id}')
|
||||
raise Exception(f'Setting data failed for {data_i.name}') from e
|
||||
|
||||
d.set_model(m)
|
||||
try:
|
||||
@ -541,7 +566,7 @@ class UpperManagement(QtCore.QObject):
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error('Fit preparation failed', *e.args)
|
||||
logger.error(f'Fit preparation failed with error: {e.args}')
|
||||
QtWidgets.QMessageBox.warning(QtWidgets.QWidget(),
|
||||
'Fit prep failed',
|
||||
f'Fit preparation failed:\n'
|
||||
@ -569,13 +594,23 @@ class UpperManagement(QtCore.QObject):
|
||||
def end_fit(self, result: list, success: bool):
|
||||
if success:
|
||||
logger.info('Successful fit')
|
||||
self.fitFinished.emit(result)
|
||||
|
||||
sub_colors = {}
|
||||
for k, v in self.__fit_options[0].items():
|
||||
sub_colors.update({set_id: v['color'] for set_id in v['data_parameter']})
|
||||
|
||||
self.fitFinished.emit(result, sub_colors)
|
||||
|
||||
else:
|
||||
e = result[0]
|
||||
logger.exception(e, exc_info=True)
|
||||
QtWidgets.QMessageBox.warning(QtWidgets.QWidget(), 'Fit failed',
|
||||
f'Fit kaput with exception: \n\n{e!r}')
|
||||
self.fitFinished.emit([])
|
||||
QtWidgets.QMessageBox.warning(
|
||||
QtWidgets.QWidget(),
|
||||
'Fit failed',
|
||||
f'Fit kaput with exception: \n\n{e!r}'
|
||||
)
|
||||
self.fitFinished.emit([], {})
|
||||
|
||||
self._fit_active = False
|
||||
|
||||
@QtCore.pyqtSlot(dict)
|
||||
@ -613,7 +648,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()
|
||||
@ -676,16 +711,20 @@ class UpperManagement(QtCore.QObject):
|
||||
|
||||
self.newData.emit(f_id_list, gid)
|
||||
|
||||
def extend_fits(self, set_id: list, x_range: np.ndarray):
|
||||
def extend_fits(self, set_id: list, x_range: np.ndarray | None, only_subplots: bool):
|
||||
graphs = {}
|
||||
for sid in set_id:
|
||||
data = self[sid]
|
||||
fit = data.copy(full=True, keep_color=True)
|
||||
fit.data = fit.data.with_new_x(x_range)
|
||||
data = fit = self[sid]
|
||||
|
||||
graph_id = data.graph
|
||||
if graph_id not in graphs:
|
||||
graphs[graph_id] = []
|
||||
|
||||
if not only_subplots:
|
||||
fit = data.copy(full=True, keep_color=True)
|
||||
if x_range is not None:
|
||||
fit.data = fit.data.with_new_x(x_range)
|
||||
|
||||
graphs[graph_id].append(self.add(fit))
|
||||
|
||||
color_scheme = available_cycles['colorblind']
|
||||
|
@ -16,6 +16,12 @@ class InterpolDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.step_lineEdit.setValidator(QtGui.QIntValidator())
|
||||
|
||||
self._data = {}
|
||||
self._src_id = None
|
||||
self._dest_graph = ''
|
||||
|
||||
def __call__(self):
|
||||
self.listWidget.clear()
|
||||
self._data = {}
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_xaxis_comboBox_currentIndexChanged')
|
||||
def change_x_source(self, idx: int):
|
||||
@ -25,29 +31,41 @@ class InterpolDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
def set_data(self, data, current_gid):
|
||||
self.graph_combobox.blockSignals(True)
|
||||
self._data = {}
|
||||
dest_idx = 0
|
||||
for (gid, graph_name), sets in data.items():
|
||||
self.graph_combobox.addItem(graph_name, userData=gid)
|
||||
self.dest_combobox.addItem(graph_name, userData=gid)
|
||||
if self._dest_graph == gid:
|
||||
dest_idx = self.dest_combobox.currentIndex()
|
||||
if gid == current_gid:
|
||||
self.make_list(sets)
|
||||
self._data[gid] = sets
|
||||
self.graph_combobox.blockSignals(False)
|
||||
self.change_graph(0)
|
||||
self.change_graph(dest_idx)
|
||||
|
||||
def make_list(self, current_sets):
|
||||
for sid, set_name in current_sets:
|
||||
item = QtWidgets.QListWidgetItem(set_name)
|
||||
item.setData(QtCore.Qt.UserRole, sid)
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
item.setData(QtCore.Qt.ItemDataRole.UserRole, sid)
|
||||
item.setCheckState(QtCore.Qt.CheckState.Checked)
|
||||
self.listWidget.addItem(item)
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_graph_combobox_currentIndexChanged')
|
||||
def change_graph(self, idx: int):
|
||||
self.set_combobox.clear()
|
||||
gid = self.graph_combobox.itemData(idx, QtCore.Qt.UserRole)
|
||||
gid = self.graph_combobox.itemData(idx, QtCore.Qt.ItemDataRole.UserRole)
|
||||
set_idx = -1
|
||||
if gid is not None:
|
||||
for set_key, set_name in self._data[gid]:
|
||||
for i, (set_key, set_name) in enumerate(self._data[gid]):
|
||||
print(self._src_id, set_key, set_name, i)
|
||||
self.set_combobox.addItem(set_name, userData=set_key)
|
||||
print(self.set_combobox.currentIndex())
|
||||
if self._src_id == set_key:
|
||||
set_idx = i
|
||||
|
||||
print(set_idx)
|
||||
if set_idx > -1:
|
||||
self.set_combobox.setCurrentIndex(set_idx)
|
||||
|
||||
def collect_parameter(self):
|
||||
xlog = self.xlog_checkBox.isChecked()
|
||||
@ -71,21 +89,35 @@ class InterpolDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
x_src = (start, stop, step, loggy)
|
||||
else:
|
||||
x_src = (self.set_combobox.currentData(QtCore.Qt.UserRole),)
|
||||
self._src_id = self.set_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
|
||||
x_src = (self._src_id,)
|
||||
|
||||
dest_graph = self.dest_combobox.currentData(QtCore.Qt.UserRole)
|
||||
self._dest_graph = self.dest_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
use_data = []
|
||||
for i in range(self.listWidget.count()):
|
||||
item = self.listWidget.item(i)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
use_data.append(item.data(QtCore.Qt.UserRole))
|
||||
if item.checkState() == QtCore.Qt.CheckState.Checked:
|
||||
use_data.append(item.data(QtCore.Qt.ItemDataRole.UserRole))
|
||||
|
||||
self.new_data.emit(use_data, mode, xlog, ylog, x_src, dest_graph)
|
||||
self.new_data.emit(use_data, mode, xlog, ylog, x_src, self._dest_graph)
|
||||
|
||||
return True
|
||||
|
||||
def accept(self):
|
||||
def _save_state(self):
|
||||
self._src_id = self.set_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
|
||||
self._dest_graph = self.dest_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
|
||||
|
||||
@QtCore.pyqtSlot(QtWidgets.QAbstractButton, name='on_buttonBox_clicked')
|
||||
def check_next_actions(self, bttn: QtWidgets.QAbstractButton):
|
||||
role = self.buttonBox.buttonRole(bttn)
|
||||
self._save_state()
|
||||
|
||||
if role == self.buttonBox.ButtonRole.RejectRole:
|
||||
self.close()
|
||||
else:
|
||||
success = self.collect_parameter()
|
||||
if success:
|
||||
super().accept()
|
||||
|
||||
if success and role == self.buttonBox.ButtonRole.AcceptRole:
|
||||
self.close()
|
||||
|
||||
|
@ -12,10 +12,10 @@ class QSmooth(QtWidgets.QDialog, Ui_SmoothDialog):
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_comboBox_currentIndexChanged')
|
||||
def change_mode(self, idx: int):
|
||||
if idx == 2:
|
||||
if idx == 1:
|
||||
self.widget.show()
|
||||
self.widget_2.hide()
|
||||
elif idx == 3:
|
||||
elif idx == 2:
|
||||
self.widget.show()
|
||||
self.widget_2.show()
|
||||
else:
|
||||
@ -29,12 +29,24 @@ class QSmooth(QtWidgets.QDialog, Ui_SmoothDialog):
|
||||
idx = self.comboBox.currentIndex()
|
||||
|
||||
# this order must match the combobox
|
||||
para['mode'] = ['mean', 'savgol', 'loess', 'median', 'std', 'var', 'max', 'min', 'sum'][idx]
|
||||
para['mode'] = [
|
||||
'mean',
|
||||
'savgol',
|
||||
'loess',
|
||||
'median',
|
||||
'std',
|
||||
'var',
|
||||
'max',
|
||||
'min',
|
||||
'sum',
|
||||
][idx]
|
||||
|
||||
if idx == 2:
|
||||
# Savitzky-Golay needs also polynomial degree
|
||||
if idx == 1:
|
||||
para['deg'] = self.polynom_spinBox.value()
|
||||
|
||||
if idx == 3:
|
||||
# LOESS needs also polynomial degree and number of iterations
|
||||
if idx == 2:
|
||||
para['deg'] = self.polynom_spinBox.value()
|
||||
para['it'] = self.iter_spinBox.value()
|
||||
|
||||
|
@ -320,7 +320,11 @@ class Points:
|
||||
pts = []
|
||||
|
||||
_tmp_x = self._x[self.mask]
|
||||
_tmp_y = self._y[self.mask]
|
||||
x_order = np.argsort(_tmp_x)
|
||||
_tmp_x = _tmp_x[x_order]
|
||||
_tmp_y = self._y[self.mask][x_order]
|
||||
_tmp_yerr = self._y_err[self.mask][x_order]
|
||||
|
||||
if idx is not None:
|
||||
for idx_i in idx:
|
||||
if isinstance(idx_i, tuple):
|
||||
@ -338,7 +342,7 @@ class Points:
|
||||
right_b = int(min(len(self), x_idx + avg_range[1] + 1))
|
||||
|
||||
if left_b < right_b:
|
||||
pts.append([_tmp_x[x_idx], *self._average(avg_mode, x_idx, left_b, right_b)])
|
||||
pts.append([_tmp_x[x_idx], *self._average(_tmp_x, _tmp_y, _tmp_yerr, avg_mode, x_idx, left_b, right_b)])
|
||||
else:
|
||||
pts.append([_tmp_x[x_idx], _tmp_y[x_idx], self._y_err[x_idx]])
|
||||
|
||||
@ -358,28 +362,37 @@ class Points:
|
||||
left_b = int(max(0, x_idx - avg_range[0]))
|
||||
right_b = int(min(len(self), x_idx + avg_range[1] + 1))
|
||||
|
||||
pts.append([_tmp_x[x_idx], *self._average(avg_mode, x_idx, left_b, right_b)])
|
||||
pts.append([_tmp_x[x_idx], *self._average(_tmp_x, _tmp_y, _tmp_yerr, avg_mode, x_idx, left_b, right_b)])
|
||||
|
||||
return pts
|
||||
|
||||
def _average(self, mode: str, idx, left: int, right: int) -> tuple[float, float]:
|
||||
@staticmethod
|
||||
def _average(
|
||||
x: np.ndarray,
|
||||
y: np.ndarray,
|
||||
y_err: np.ndarray,
|
||||
mode: str,
|
||||
idx: int,
|
||||
left: int,
|
||||
right: int,
|
||||
) -> tuple[float, float]:
|
||||
if mode == 'mean':
|
||||
y_mean = np.mean(self._y[self.mask][left:right].real)
|
||||
y_err = np.linalg.norm(self._y_err[self.mask][left:right]) / (right - left)
|
||||
y_mean = np.mean(y[left:right].real)
|
||||
y_err_mean = np.linalg.norm(y_err[left:right]) / (right - left)
|
||||
|
||||
elif mode == 'sum':
|
||||
y_mean = np.sum(self._y[self.mask][left:right].real)
|
||||
y_err = np.linalg.norm(self._y_err[self.mask][left:right])
|
||||
y_mean = np.sum(y[left:right].real)
|
||||
y_err_mean = np.linalg.norm(y_err[left:right])
|
||||
|
||||
elif mode == 'integral':
|
||||
y_mean = simpson(self._y[self.mask][left:right].real, x=self._x[left:right])
|
||||
y_err = np.linalg.norm(cumulative_trapezoid(self._y_err[self.mask][left:right].real, x=self._x[left:right]))
|
||||
y_mean = simpson(y[left:right].real, x=x[left:right])
|
||||
y_err_mean = np.linalg.norm(cumulative_trapezoid(y_err[left:right].real, x=x[left:right]))
|
||||
|
||||
else:
|
||||
y_mean = self._y[self.mask][idx].real
|
||||
y_err = self._y_err[self.mask][idx]
|
||||
y_mean = y[idx].real
|
||||
y_err_mean = y_err[idx]
|
||||
|
||||
return y_mean, y_err
|
||||
return y_mean, y_err_mean
|
||||
|
||||
def concatenate(self, other):
|
||||
"""
|
||||
@ -527,26 +540,37 @@ class Points:
|
||||
|
||||
return self
|
||||
|
||||
def cut(self, low_lim: float = None, high_lim: float = None):
|
||||
def cut(self, x_low: float = None, x_high: float = None, y_low: float = None, y_high: float = None):
|
||||
"""
|
||||
Cut
|
||||
Args:
|
||||
low_lim:
|
||||
high_lim:
|
||||
x_low: Lower limit
|
||||
x_high: Upper limit for x values
|
||||
y_low: Lower limit
|
||||
y_high: Upper limit for x valuew
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
if low_lim is None and high_lim is None:
|
||||
|
||||
if x_low is None and x_high is None and y_low is None and y_high is None:
|
||||
return self
|
||||
|
||||
if low_lim is None:
|
||||
low_lim = np.min(self._x)
|
||||
if x_low is None:
|
||||
x_low = np.min(self._x)-1
|
||||
|
||||
if high_lim is None:
|
||||
high_lim = np.max(self._x)
|
||||
if x_high is None:
|
||||
x_high = np.max(self._x)+1
|
||||
|
||||
_mask = np.ma.masked_inside(self._x, low_lim, high_lim).mask
|
||||
if y_low is None:
|
||||
y_low = np.min(self._y.real)-1
|
||||
|
||||
if y_high is None:
|
||||
y_high = np.max(self._y.real)+1
|
||||
|
||||
x_mask = (self._x >= x_low) & (self._x <= x_high)
|
||||
y_mask = (self._y.real >= y_low) & (self._y.real <= y_high)
|
||||
_mask = x_mask & y_mask
|
||||
|
||||
self._x = self._x[_mask]
|
||||
self._y = self._y[_mask]
|
||||
|
@ -3,7 +3,12 @@ from ctypes import c_double, cast, pointer, c_void_p
|
||||
|
||||
import numpy as np
|
||||
from scipy import LowLevelCallable
|
||||
from scipy.integrate import quad, simps as simpson
|
||||
|
||||
from scipy.integrate import quad
|
||||
try:
|
||||
from scipy.integrate import simps as simpson
|
||||
except ImportError:
|
||||
from scipy.integrate import simpson
|
||||
|
||||
from .base import Distribution
|
||||
from ..lib.utils import ArrayLike
|
||||
|
@ -9,7 +9,13 @@ from inspect import signature, Parameter
|
||||
class ModelFactory:
|
||||
|
||||
@staticmethod
|
||||
def create_from_list(funcs: list, left=None, func_order=None, param_len=None, left_cnt=None):
|
||||
def create_from_list(
|
||||
funcs: list,
|
||||
left=None,
|
||||
func_order: list[int] = None,
|
||||
param_len: list[int] = None,
|
||||
left_cnt: int = 0,
|
||||
):
|
||||
if func_order is None:
|
||||
func_order = []
|
||||
|
||||
@ -20,32 +26,50 @@ class ModelFactory:
|
||||
if not func['active']:
|
||||
continue
|
||||
|
||||
func_order.append(func['cnt'])
|
||||
param_len.append(len(func['func'].params))
|
||||
|
||||
if func['children']:
|
||||
right, _, _ = ModelFactory.create_from_list(func['children'], left_cnt=func['pos'],
|
||||
func_order=func_order, param_len=param_len)
|
||||
right_cnt = None
|
||||
right = MultiModel(func['func'], right, func['children'][0]['op'], left_idx=func['cnt'], right_idx=None)
|
||||
f = func.copy()
|
||||
f['children'] = []
|
||||
right, _, _, right_cnt = ModelFactory.create_from_list(
|
||||
[f] + func['children'],
|
||||
left_cnt=func['pos'],
|
||||
func_order=func_order,
|
||||
param_len=param_len,
|
||||
)
|
||||
else:
|
||||
right = func['func']
|
||||
right_cnt = func['cnt']
|
||||
|
||||
func_order.append(func['cnt'])
|
||||
param_len.append(len(func['func'].params))
|
||||
|
||||
if left is None:
|
||||
left = right
|
||||
left_cnt = right_cnt
|
||||
else:
|
||||
left = MultiModel(left, right, func['op'],
|
||||
left_idx=left_cnt, right_idx=right_cnt)
|
||||
left = MultiModel(left, right, func['op'], left_idx=left_cnt, right_idx=right_cnt)
|
||||
|
||||
return left, func_order, param_len
|
||||
return left, func_order, param_len, left_cnt
|
||||
|
||||
|
||||
class MultiModel:
|
||||
op_repr = {operator.add: ' + ', operator.mul: ' * ', operator.sub: ' - ', operator.truediv: ' / '}
|
||||
str_op = {'+': operator.add, '*': operator.mul, '-': operator.sub, '/': operator.truediv}
|
||||
int_op = {0: operator.add, 1: operator.mul, 2: operator.sub, 3: operator.truediv}
|
||||
op_repr = {
|
||||
operator.add: ' + ',
|
||||
operator.mul: ' * ',
|
||||
operator.sub: ' - ',
|
||||
operator.truediv: ' / ',
|
||||
}
|
||||
str_op = {
|
||||
'+': operator.add,
|
||||
'*': operator.mul,
|
||||
'-': operator.sub,
|
||||
'/': operator.truediv,
|
||||
}
|
||||
int_op = {
|
||||
0: operator.add,
|
||||
1: operator.mul,
|
||||
2: operator.sub,
|
||||
3: operator.truediv,
|
||||
}
|
||||
|
||||
def __init__(self,
|
||||
left: Any,
|
||||
@ -69,6 +93,9 @@ class MultiModel:
|
||||
if self._op is None:
|
||||
raise ValueError('Invalid binary operator.')
|
||||
|
||||
if right_idx is None:
|
||||
right_idx = left_idx + 1
|
||||
|
||||
self.name = '('
|
||||
self.params = []
|
||||
self.bounds = []
|
||||
|
@ -6,10 +6,13 @@ from .model import Model
|
||||
from .parameter import Parameters, Parameter
|
||||
|
||||
|
||||
class Data(object):
|
||||
def __init__(self, x, y, we=None, idx=None):
|
||||
class Data:
|
||||
def __init__(self, x, y, we=None, idx=None, complex_type: int = 0):
|
||||
self.x = np.asarray(x)
|
||||
self.y = np.asarray(y)
|
||||
if self.x.size == 0 or self.y.size == 0:
|
||||
raise ValueError("Data is empty")
|
||||
|
||||
if self.y.shape[0] != self.x.shape[0]:
|
||||
raise ValueError(f'x and y have different lengths {self.x.shape[0]} and {self.y.shape[0]}')
|
||||
|
||||
@ -20,6 +23,7 @@ class Data(object):
|
||||
self.parameter = Parameters()
|
||||
self.para_keys: list = []
|
||||
self.fun_kwargs = {}
|
||||
self.complex_type = complex_type
|
||||
|
||||
def __len__(self):
|
||||
return self.y.shape[0]
|
||||
|
@ -361,7 +361,7 @@ class FitRoutine(object):
|
||||
with np.errstate(all='ignore'):
|
||||
res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=500 * len(p0))
|
||||
|
||||
err, corr, partial_corr = self._calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape)
|
||||
err, corr, partial_corr = _calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape)
|
||||
self.make_results(data, res.x, var, data.para_keys, res.jac.shape,
|
||||
err=err, corr=corr, partial_corr=partial_corr)
|
||||
|
||||
@ -375,7 +375,7 @@ class FitRoutine(object):
|
||||
with np.errstate(all='ignore'):
|
||||
res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=500 * len(p0))
|
||||
|
||||
err, corr, partial_corr = self._calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape)
|
||||
err, corr, partial_corr = _calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape)
|
||||
for v, var_pars_k in zip(data, data_pars):
|
||||
self.make_results(v, res.x, var, var_pars_k, res.jac.shape,
|
||||
err=err, corr=corr, partial_corr=partial_corr)
|
||||
@ -458,9 +458,17 @@ class FitRoutine(object):
|
||||
self.make_results(v, res.beta, var, var_pars_k, (sum(len(d) for d in data), len(p0)),
|
||||
err=res.sd_beta, corr=corr, partial_corr=partial_corr)
|
||||
|
||||
def make_results(self, data, p, var_pars, used_pars, shape,
|
||||
err=None, corr=None, partial_corr=None):
|
||||
|
||||
def make_results(
|
||||
self,
|
||||
data: Data,
|
||||
p: list[float],
|
||||
var_pars: list[str],
|
||||
used_pars: list[str],
|
||||
shape: tuple[int, int],
|
||||
err: list[float] = None,
|
||||
corr: np.ndarray = None,
|
||||
partial_corr: np.ndarray = None,
|
||||
):
|
||||
if err is None:
|
||||
err = [0] * len(p)
|
||||
|
||||
@ -498,22 +506,24 @@ class FitRoutine(object):
|
||||
model = data.get_model()
|
||||
|
||||
self.result[idx] = FitResultCreator.make_with_model(
|
||||
model,
|
||||
data.x,
|
||||
data.y,
|
||||
actual_parameters,
|
||||
data.fun_kwargs,
|
||||
data.we_string,
|
||||
data.idx,
|
||||
*shape,
|
||||
model=model,
|
||||
x_orig=data.x,
|
||||
y_orig=data.y,
|
||||
p=actual_parameters,
|
||||
fun_kwargs=data.fun_kwargs,
|
||||
we=data.we_string,
|
||||
idx=data.idx,
|
||||
nobs=shape[0],
|
||||
nvar=shape[1],
|
||||
corr=actual_corr,
|
||||
pcorr=actual_pcorr,
|
||||
data_mode=data.complex_type,
|
||||
)
|
||||
|
||||
return self.result
|
||||
|
||||
@staticmethod
|
||||
def _calc_error(jac, chi, nobs, nvars):
|
||||
|
||||
def _calc_error(jac, chi, nobs, nvars):
|
||||
# copy of scipy.curve_fit to calculate covariance
|
||||
# noinspection PyTupleAssignmentBalance
|
||||
try:
|
||||
|
@ -9,7 +9,7 @@ from ._meta import MultiModel
|
||||
from .parameter import Parameters, Parameter
|
||||
|
||||
|
||||
class Model(object):
|
||||
class Model:
|
||||
def __init__(self, model, *args, **kwargs):
|
||||
self.idx = kwargs.pop('idx', None)
|
||||
|
||||
|
@ -11,6 +11,7 @@ from scipy.stats import f as fdist
|
||||
from scipy.interpolate import interp1d
|
||||
|
||||
from ._meta import MultiModel
|
||||
from .model import Model
|
||||
from .parameter import Parameter
|
||||
from ..data.points import Points
|
||||
from ..data.signals import Signal
|
||||
@ -36,17 +37,30 @@ class FitResultCreator:
|
||||
else:
|
||||
resid = kwargs['y'] - y_orig
|
||||
|
||||
stats = FitResultCreator.calc_statistics(resid, _y)
|
||||
stats = calc_statistics(resid, _y)
|
||||
|
||||
return FitResult(kwargs['x'], kwargs['y'], x_orig, y_orig, params, dict(kwargs['choice']), resid, 0, 0,
|
||||
kwargs['name'], stats, idx)
|
||||
return FitResult(
|
||||
x=kwargs['x'],
|
||||
y=kwargs['y'],
|
||||
x_data=x_orig,
|
||||
y_data=y_orig,
|
||||
params=params,
|
||||
fun_kwargs=dict(kwargs['choice']),
|
||||
resid=resid,
|
||||
nobs=0,
|
||||
nvar=0,
|
||||
we='',
|
||||
name=kwargs['name'],
|
||||
stats=stats,
|
||||
idx=idx,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def make_with_model(
|
||||
model: 'Model',
|
||||
x_orig: np.ndarray,
|
||||
y_orig: np.ndarray,
|
||||
p: 'Parameters',
|
||||
p: list,
|
||||
fun_kwargs: dict,
|
||||
we: str,
|
||||
idx: str | None,
|
||||
@ -54,6 +68,7 @@ class FitResultCreator:
|
||||
nvar: int,
|
||||
corr: np.ndarray,
|
||||
pcorr: np.ndarray,
|
||||
data_mode: int,
|
||||
) -> FitResult:
|
||||
if np.all(x_orig > 0) and (np.max(x_orig) > 100 * np.min(x_orig)):
|
||||
islog = True
|
||||
@ -83,17 +98,11 @@ class FitResultCreator:
|
||||
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
|
||||
_y = check_complex(model.func(p_final, _x, **fun_kwargs), actual_mode, data_mode)
|
||||
|
||||
fun_kwargs['complex_mode'] = actual_mode
|
||||
|
||||
stats = FitResultCreator.calc_statistics(_y, resid, nobs, nvar)
|
||||
stats = calc_statistics(_y, resid, nobs, nvar)
|
||||
varied = [p.var for p in parameters.values()]
|
||||
|
||||
if corr is None:
|
||||
@ -134,38 +143,9 @@ class FitResultCreator:
|
||||
pcorr=partial_correlation,
|
||||
islog=islog,
|
||||
func=model,
|
||||
data_complex=data_mode,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def calc_statistics(y, residual, nobs=None, nvar=None):
|
||||
chi = (residual**2).sum()
|
||||
try:
|
||||
r = 1 - chi/((y-np.mean(y))**2).sum()
|
||||
except RuntimeWarning:
|
||||
r = -9999
|
||||
|
||||
if nobs is None:
|
||||
nobs = 1
|
||||
|
||||
if nvar is None:
|
||||
nvar = 0
|
||||
|
||||
dof = nobs - nvar
|
||||
loglikehood = nobs * np.log(chi / nobs)
|
||||
|
||||
stats = {
|
||||
'chi^2': chi,
|
||||
'R^2': r,
|
||||
'AIC': loglikehood + 2 * nvar,
|
||||
'BIC': loglikehood + np.log(nobs) * nvar,
|
||||
'adj. R^2': 1 - (nobs-1) / (dof+1e-13) * (1-r),
|
||||
'red. chi^2': chi / (dof + 1e-13),
|
||||
}
|
||||
|
||||
stats['AICc'] = stats['AIC'] + 2*(nvar+1)*nvar / (dof - 1 + 1e-13)
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
class FitResult(Points):
|
||||
|
||||
@ -188,7 +168,8 @@ class FitResult(Points):
|
||||
pcorr: np.ndarray = None,
|
||||
islog: bool = False,
|
||||
func=None,
|
||||
**kwargs
|
||||
data_complex: int = 1,
|
||||
**kwargs,
|
||||
):
|
||||
|
||||
self.parameter, name = self._prepare_names(params, name)
|
||||
@ -210,6 +191,7 @@ class FitResult(Points):
|
||||
self.y_data = y_data
|
||||
self._model_name = name
|
||||
self._func = func
|
||||
self._data_complex = data_complex
|
||||
|
||||
@staticmethod
|
||||
def _prepare_names(parameter: dict, modelname: str):
|
||||
@ -418,20 +400,12 @@ class FitResult(Points):
|
||||
if self.func is None:
|
||||
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
|
||||
fun_kwargs = {k: v for k, v in self.fun_kwargs.items()}
|
||||
if self.fun_kwargs.get('complex_mode', -1) == -1:
|
||||
fun_kwargs.pop('complex_mode', None)
|
||||
y_values = self.func.func(self.p_final, x_values, **fun_kwargs)
|
||||
y_values = check_complex(y_values, self.fun_kwargs.get('complex_mode', -1), self._data_complex)
|
||||
|
||||
new_fit.set_data(x_values, y_values, y_err=0.0)
|
||||
|
||||
@ -442,20 +416,16 @@ class FitResult(Points):
|
||||
raise ValueError('no fit function available to calculate new y 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
|
||||
actual_mode = self.fun_kwargs.get('complex_mode', -1)
|
||||
fun_kwargs = {k: v for k, v in self.fun_kwargs.items()}
|
||||
if self.fun_kwargs.get('complex_mode', -1) == -1:
|
||||
fun_kwargs.pop('complex_mode', None)
|
||||
|
||||
for sub_name, sub_y in zip(self.func.sub_name(), self.func.sub(self.p_final, x_values, **self.fun_kwargs)):
|
||||
if not actual_mode < 0:
|
||||
if actual_mode == 1:
|
||||
sub_y.imag = 0
|
||||
elif actual_mode == 2:
|
||||
sub_y.real = 0
|
||||
sub_y = check_complex(sub_y, actual_mode, self._data_complex)
|
||||
|
||||
if np.iscomplexobj(sub_y):
|
||||
part_functions.append(Signal(x_values, sub_y, name=sub_name))
|
||||
|
||||
else:
|
||||
part_functions.append(Points(x_values, sub_y, name=sub_name))
|
||||
|
||||
@ -463,3 +433,49 @@ class FitResult(Points):
|
||||
self.fun_kwargs['complex_mode'] = actual_mode
|
||||
|
||||
return part_functions
|
||||
|
||||
|
||||
def check_complex(y, model_complex, data_complex):
|
||||
if not np.iscomplexobj(y):
|
||||
return y
|
||||
|
||||
if model_complex == 1:
|
||||
y.imag = 0
|
||||
if data_complex == 1:
|
||||
y = y.real
|
||||
elif model_complex == 2:
|
||||
y.real = 0
|
||||
if data_complex == 1:
|
||||
y = y.imag
|
||||
|
||||
return y
|
||||
|
||||
|
||||
def calc_statistics(y, residual, nobs=None, nvar=None):
|
||||
chi = (residual**2).sum()
|
||||
try:
|
||||
r = 1 - chi/((y-np.mean(y))**2).sum()
|
||||
except RuntimeWarning:
|
||||
r = -9999
|
||||
|
||||
if nobs is None:
|
||||
nobs = 1
|
||||
|
||||
if nvar is None:
|
||||
nvar = 0
|
||||
|
||||
dof = nobs - nvar
|
||||
loglikehood = nobs * np.log(chi / nobs)
|
||||
|
||||
stats = {
|
||||
'chi^2': chi,
|
||||
'R^2': r,
|
||||
'AIC': loglikehood + 2 * nvar,
|
||||
'BIC': loglikehood + np.log(nobs) * nvar,
|
||||
'adj. R^2': 1 - (nobs-1) / (dof+1e-13) * (1-r),
|
||||
'red. chi^2': chi / (dof + 1e-13),
|
||||
}
|
||||
|
||||
stats['AICc'] = stats['AIC'] + 2*(nvar+1)*nvar / (dof - 1 + 1e-13)
|
||||
|
||||
return stats
|
||||
|
@ -49,7 +49,7 @@ class AsciiReader:
|
||||
with self.fname.open('r') as f:
|
||||
for i, line in enumerate(islice(f, len(self.header)+len(self.lines), num_lines)):
|
||||
line = line.strip('\n\t\r, ')
|
||||
line = re.sub(r'[\t ;,] *', ';', line)
|
||||
line = re.sub(r'[\t ;,]+', ';', line)
|
||||
line = line.split(';')
|
||||
|
||||
try:
|
||||
@ -183,7 +183,13 @@ class AsciiReader:
|
||||
single_len = 2
|
||||
stepsize = 2
|
||||
|
||||
cls = {'points': Points, 'fid': FID, 'spectrum': Spectrum, 'bds': BDS, 'dsc': DSC}[mode]
|
||||
cls = {
|
||||
'points': Points,
|
||||
'fid': FID,
|
||||
'spectrum': Spectrum,
|
||||
'bds': BDS,
|
||||
'dsc': DSC,
|
||||
}[mode]
|
||||
|
||||
for j in range(1, num_y+1, stepsize):
|
||||
if col_names is not None:
|
||||
@ -191,7 +197,7 @@ class AsciiReader:
|
||||
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])
|
||||
kwargs['name'] = f'{filename}_{y[j-1]+1}'
|
||||
|
||||
if j+num_y < raw_data.shape[2]:
|
||||
kwargs['y_err'] = raw_data[i, :, j+num_y]
|
||||
|
@ -11,7 +11,8 @@ try:
|
||||
from scipy.integrate import simpson
|
||||
except ImportError:
|
||||
from scipy.integrate import simps as simpson
|
||||
from scipy.interpolate import interp1d
|
||||
from scipy.interpolate import CubicSpline
|
||||
|
||||
|
||||
ReferenceValue = namedtuple('Reference', ['name', 'transitions'])
|
||||
Cyclohexane = ReferenceValue('Cyclohexane', [(-87.06+273.15, 79.58), (6.54+273.15, None)])
|
||||
@ -38,7 +39,7 @@ class DSCSample:
|
||||
def read_file(self, fname: str | Path) -> None:
|
||||
fname = Path(fname)
|
||||
|
||||
# file contains weird deg C character in stupiod ISO encoding
|
||||
# file contains weird deg C character in stupid ISO encoding
|
||||
with fname.open('r', encoding='iso-8859-15') as f:
|
||||
ii = 1
|
||||
for line in f:
|
||||
@ -144,9 +145,12 @@ class DSCCalibrator:
|
||||
self.reference = []
|
||||
self.ref_list = []
|
||||
|
||||
def set_measurement(self,
|
||||
fname: str | Path | DSCSample, mode: str = 'sample',
|
||||
reference: ReferenceValue = Cyclohexane):
|
||||
def set_measurement(
|
||||
self: DSCCalibrator,
|
||||
fname: str | Path | DSCSample,
|
||||
mode: str = 'sample',
|
||||
reference: ReferenceValue = Cyclohexane
|
||||
):
|
||||
if mode not in ['sample', 'empty', 'reference']:
|
||||
raise ValueError(f'Unknown mode {mode}, not "sample", "empty", "reference"')
|
||||
if mode == 'reference' and not isinstance(reference, ReferenceValue):
|
||||
@ -266,7 +270,12 @@ class DSCCalibrator:
|
||||
|
||||
return sol
|
||||
|
||||
def get_data(self, idx: int, slope: str = 'iso', limits: tuple[float, float] = None):
|
||||
def get_data(
|
||||
self: DSCCalibrator,
|
||||
idx: int,
|
||||
slope: str = 'iso',
|
||||
limits: tuple[float, float] = None
|
||||
) -> tuple[np.ndarray, np.ndarray, np.ndarray,np.ndarray | None, np.ndarray]:
|
||||
if self.sample.steps[idx][0] == 'i':
|
||||
raise ValueError('baseline correction is not implemented for isotherms')
|
||||
|
||||
@ -292,7 +301,7 @@ class DSCCalibrator:
|
||||
empty_y = empty_data[1]
|
||||
if self.sample.length(idx) != self.empty.length(idx_empty):
|
||||
with np.errstate(all='ignore'):
|
||||
empty_y = interp1d(empty_data[2]-empty_data[2, 0], empty_data[1], fill_value='extrapolate')(sample_data[2, 0])
|
||||
empty_y = CubicSpline(empty_data[2]-empty_data[2, 0], empty_data[1], extrapolate=True)(sample_data[2] - sample_data[2, 0])
|
||||
|
||||
sample_data[1] -= empty_y
|
||||
drift_value = sample_data.copy()[(2, 1), :]
|
||||
@ -346,9 +355,10 @@ class DSCCalibrator:
|
||||
|
||||
offset = region[0, 0]
|
||||
sample_data[1] -= m * (sample_data[2] - region[1, 0]) + offset
|
||||
line = np.array([[sample_data[2, 0], sample_data[2, -1]],
|
||||
[m * (sample_data[2, 0] - region[1, 0]) + offset,
|
||||
m * (sample_data[2, -1] - region[1, 0]) + offset]])
|
||||
line = np.array([
|
||||
[sample_data[2, 0], sample_data[2, -1]],
|
||||
[m * (sample_data[2, 0] - region[1, 0]) + offset, m * (sample_data[2, -1] - region[1, 0]) + offset]
|
||||
])
|
||||
|
||||
else:
|
||||
line = np.array([[sample_data[2, 0], sample_data[2, -1]], [0, 0]])
|
||||
|
@ -3,14 +3,21 @@ import numpy.polynomial.polynomial as poly
|
||||
from scipy import signal as signal
|
||||
|
||||
|
||||
__all__ = ['smooth', 'loess', 'savgol',
|
||||
'running_max', 'running_min',
|
||||
'running_var', 'running_std',
|
||||
'running_median', 'running_mean',
|
||||
'running_sum']
|
||||
__all__ = [
|
||||
'smooth',
|
||||
'loess',
|
||||
'savgol',
|
||||
'running_max',
|
||||
'running_min',
|
||||
'running_var',
|
||||
'running_std',
|
||||
'running_median',
|
||||
'running_mean',
|
||||
'running_sum',
|
||||
]
|
||||
|
||||
|
||||
def loess(x, y, window_size, it=0, deg=2):
|
||||
def loess(x, y, window_size: int, it: int = 0, deg: int = 2):
|
||||
# ULTRA LANGSAM !!!
|
||||
it = max(it, 0)
|
||||
|
||||
@ -81,19 +88,19 @@ def savgol(x, y, window_size: int, deg: int = 2, mode: str = 'mirror'):
|
||||
return new_y
|
||||
|
||||
|
||||
def running_mean(x, y, window_size):
|
||||
def running_mean(x, y, window_size: int):
|
||||
return _running_func(np.nanmean, x, y, window_size)
|
||||
|
||||
|
||||
def running_median(x, y, window_size):
|
||||
def running_median(x, y, window_size: int):
|
||||
return _running_func(np.nanmedian, x, y, window_size)
|
||||
|
||||
|
||||
def running_std(x, y, window_size):
|
||||
def running_std(x, y, window_size: int):
|
||||
return _running_func(np.nanstd, x, y, window_size)
|
||||
|
||||
|
||||
def running_var(x, y, window_size):
|
||||
def running_var(x, y, window_size: int):
|
||||
return _running_func(np.nanvar, x, y, window_size)
|
||||
|
||||
|
||||
@ -132,11 +139,27 @@ def _moving_window(arr, nn):
|
||||
return np.lib.stride_tricks.as_strided(arr, shapes, strides)
|
||||
|
||||
|
||||
_funcs = {'loess': loess, 'savgol': savgol, 'mean': running_mean, 'median': running_median,
|
||||
'std': running_std, 'var': running_var, 'max': running_max, 'min': running_min, 'sum': running_sum}
|
||||
_funcs = {
|
||||
'loess': loess,
|
||||
'savgol': savgol,
|
||||
'mean': running_mean,
|
||||
'median': running_median,
|
||||
'std': running_std,
|
||||
'var': running_var,
|
||||
'max': running_max,
|
||||
'min': running_min,
|
||||
'sum': running_sum,
|
||||
}
|
||||
|
||||
|
||||
def smooth(data, window_size, mode='mean', logx=False, logy=False, **kwargs):
|
||||
def smooth(
|
||||
data: 'Data',
|
||||
window_size: int,
|
||||
mode: str = 'mean',
|
||||
logx: bool = False,
|
||||
logy: bool = False,
|
||||
**kwargs
|
||||
):
|
||||
try:
|
||||
func = _funcs[mode]
|
||||
except KeyError:
|
||||
@ -162,6 +185,6 @@ def smooth(data, window_size, mode='mean', logx=False, logy=False, **kwargs):
|
||||
new_y = 10**new_y
|
||||
|
||||
new_data = data.copy()
|
||||
new_data.set_data(x=new_x, y=new_y, y_err=None)
|
||||
new_data.set_data(x=new_x, y=new_y, y_err=np.zeros_like(new_y))
|
||||
|
||||
return new_data
|
||||
|
@ -191,6 +191,18 @@ class PowerLawCross:
|
||||
return ret_val
|
||||
|
||||
|
||||
class Sinc:
|
||||
type = 'Basic'
|
||||
name = 'Sinc'
|
||||
equation = 'C * sinc((x-x_{0})/w)'
|
||||
params = ['C', 'x_{0}', 'w']
|
||||
|
||||
@staticmethod
|
||||
def func(x, c: float, x0: float, w: float):
|
||||
# numpy sinc is defined as sin(pi*x)/(pi*x)
|
||||
return c * np.sinc(((x-x0)/w)/np.pi)
|
||||
|
||||
|
||||
class Sine:
|
||||
"""
|
||||
Wavy sine function
|
||||
|
@ -172,6 +172,14 @@
|
||||
<property name="title">
|
||||
<string>&Data</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuCut_to_visible_range">
|
||||
<property name="title">
|
||||
<string>Cut to visible range</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_cut_xaxis"/>
|
||||
<addaction name="action_cut_yaxis"/>
|
||||
</widget>
|
||||
<addaction name="action_new_set"/>
|
||||
<addaction name="action_delete_sets"/>
|
||||
<addaction name="actionMove_between_plots"/>
|
||||
@ -181,7 +189,7 @@
|
||||
<addaction name="action_sort_pts"/>
|
||||
<addaction name="actionSkip_points"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_cut"/>
|
||||
<addaction name="menuCut_to_visible_range"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionChange_datatypes"/>
|
||||
</widget>
|
||||
@ -247,6 +255,7 @@
|
||||
<addaction name="action_no_range"/>
|
||||
<addaction name="action_x_range"/>
|
||||
<addaction name="action_custom_range"/>
|
||||
<addaction name="actionExclude_region"/>
|
||||
</widget>
|
||||
<addaction name="action_FitWidget"/>
|
||||
<addaction name="separator"/>
|
||||
@ -437,30 +446,6 @@
|
||||
<addaction name="t1action"/>
|
||||
<addaction name="actionCalculateT1"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar_fit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fit</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="action_FitWidget"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar_spectrum">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@ -885,11 +870,6 @@
|
||||
<string>Integration...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_cut">
|
||||
<property name="text">
|
||||
<string>Cut to visible range</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMove_between_plots">
|
||||
<property name="text">
|
||||
<string>Move sets...</string>
|
||||
@ -1045,6 +1025,30 @@
|
||||
<string>TNMH...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExclude_region">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exclude region</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_cut_xaxis">
|
||||
<property name="text">
|
||||
<string>x axis</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove data points outside visible x range.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_cut_yaxis">
|
||||
<property name="text">
|
||||
<string>y axis</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove data points outside visible y range. Uses real part of points.</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -96,11 +96,14 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="region_box">
|
||||
<property name="title">
|
||||
<string>Evaluate region (empty values default to start/end)</string>
|
||||
<string>Evaluate region (empty values default to values of the script)</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
@ -311,7 +314,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="graph_comboBox"/>
|
||||
<widget class="QComboBox" name="graph_comboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="graph_checkbox">
|
||||
|
@ -67,6 +67,12 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>160</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Initial values</string>
|
||||
</property>
|
||||
@ -92,6 +98,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reset_button">
|
||||
<property name="text">
|
||||
<string>Use global</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@ -151,6 +164,12 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Lower bound. Same bound is used for all data. Leave empty for no boundary condition.</p></body></html></string>
|
||||
</property>
|
||||
@ -195,6 +214,12 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Upper bound. Same bound is used for all data. Leave empty for no boundary condition.</p></body></html></string>
|
||||
</property>
|
||||
|
@ -354,59 +354,26 @@
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="extrapolate_box">
|
||||
<property name="toolTip">
|
||||
<string>Extrapolates only main function</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Extrapolate curves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QCheckBox" name="parameter_checkbox">
|
||||
<property name="text">
|
||||
<string>Plot parameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="6">
|
||||
<item row="1" column="7">
|
||||
<widget class="QComboBox" name="graph_comboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QCheckBox" name="graph_checkBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New graph for parameter</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="minx_line">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@ -419,10 +386,45 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" rowspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="extrapolate_box">
|
||||
<property name="toolTip">
|
||||
<string>Extrapolates only main function</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Extrapolate curves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="numx_line">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string># pts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="6">
|
||||
<widget class="QCheckBox" name="graph_checkBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New graph for parameter</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -432,7 +434,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@ -445,20 +447,33 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="numx_line">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string># pts</string>
|
||||
<item row="0" column="5" rowspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<item row="1" column="4">
|
||||
<widget class="QCheckBox" name="newx_log_checkbox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>log-spaced?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="curve_checkbox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Plot fit curve</string>
|
||||
</property>
|
||||
@ -469,6 +484,12 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="partial_checkBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Plot partial functions</string>
|
||||
</property>
|
||||
@ -476,6 +497,19 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="6" colspan="2">
|
||||
<widget class="QCheckBox" name="parameter_checkbox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Plot parameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -119,7 +119,7 @@
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -300,38 +300,5 @@
|
||||
<tabstop>dest_combobox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>251</x>
|
||||
<y>490</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>319</x>
|
||||
<y>490</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -17,7 +17,20 @@
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<item row="7" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="frac_label">
|
||||
<property name="text">
|
||||
<string>Window length</string>
|
||||
@ -27,68 +40,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Iterations</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>iter_spinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="iter_spinBox">
|
||||
<property name="maximum">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
@ -132,7 +91,65 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="y_checkBox">
|
||||
<property name="text">
|
||||
<string>y log-spaced?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="x_checkBox">
|
||||
<property name="text">
|
||||
<string>x log-spaced?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Iterations</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>iter_spinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="iter_spinBox">
|
||||
<property name="maximum">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="frac_spinBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Number of data points used as smoothing window.</p></body></html></string>
|
||||
@ -145,7 +162,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -194,30 +221,13 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="y_checkBox">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>y log-spaced?</string>
|
||||
<string><html><head/><body><p><span style=" font-weight:600;">Note:</span> Sets must be sorted for correct results</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="x_checkBox">
|
||||
<property name="text">
|
||||
<string>x log-spaced?</string>
|
||||
<property name="margin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
Loading…
Reference in New Issue
Block a user