extrapolate_fit (#21)
New sets with arbitrary x range can be created from fit results Co-authored-by: Dominik Demuth <dominik.demuth@physik.tu-darmstadt.de> Reviewed-on: #21
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file './resources/_ui/fitresult.ui'
|
||||
# Form implementation generated from reading ui file '/autohome/dominik/nmreval-gitea/src/resources/_ui/fitresult.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.4
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(817, 584)
|
||||
Dialog.resize(864, 649)
|
||||
self.gridLayout = QtWidgets.QGridLayout(Dialog)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.sets_comboBox = ElideComboBox(Dialog)
|
||||
@ -51,6 +51,21 @@ 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.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)
|
||||
@ -59,22 +74,44 @@ class Ui_Dialog(object):
|
||||
self.graph_checkBox.setSizePolicy(sizePolicy)
|
||||
self.graph_checkBox.setChecked(True)
|
||||
self.graph_checkBox.setObjectName("graph_checkBox")
|
||||
self.gridLayout_2.addWidget(self.graph_checkBox, 1, 1, 1, 1)
|
||||
self.graph_comboBox = QtWidgets.QComboBox(self.groupBox)
|
||||
self.graph_comboBox.setEnabled(False)
|
||||
self.graph_comboBox.setObjectName("graph_comboBox")
|
||||
self.gridLayout_2.addWidget(self.graph_comboBox, 1, 2, 1, 1)
|
||||
self.gridLayout_2.addWidget(self.graph_checkBox, 1, 5, 1, 1)
|
||||
self.minx_line = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.minx_line.setEnabled(False)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, 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.maxx_line = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.maxx_line.setEnabled(False)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, 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.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.curve_checkbox = QtWidgets.QCheckBox(self.groupBox)
|
||||
self.curve_checkbox.setChecked(True)
|
||||
self.curve_checkbox.setObjectName("curve_checkbox")
|
||||
self.gridLayout_2.addWidget(self.curve_checkbox, 0, 0, 1, 1)
|
||||
self.horizontalLayout.addWidget(self.curve_checkbox)
|
||||
self.partial_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||
self.partial_checkBox.setObjectName("partial_checkBox")
|
||||
self.gridLayout_2.addWidget(self.partial_checkBox, 1, 0, 1, 1)
|
||||
self.parameter_checkbox = QtWidgets.QCheckBox(self.groupBox)
|
||||
self.parameter_checkbox.setChecked(True)
|
||||
self.parameter_checkbox.setObjectName("parameter_checkbox")
|
||||
self.gridLayout_2.addWidget(self.parameter_checkbox, 0, 1, 1, 1)
|
||||
self.horizontalLayout.addWidget(self.partial_checkBox)
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 4)
|
||||
self.gridLayout.addWidget(self.groupBox, 5, 0, 1, 2)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setSpacing(3)
|
||||
@ -91,40 +128,38 @@ class Ui_Dialog(object):
|
||||
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.line.setObjectName("line")
|
||||
self.gridLayout.addWidget(self.line, 3, 0, 1, 2)
|
||||
self.stack = QtWidgets.QToolBox(Dialog)
|
||||
self.stack = QtWidgets.QTabWidget(Dialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.stack.sizePolicy().hasHeightForWidth())
|
||||
self.stack.setSizePolicy(sizePolicy)
|
||||
self.stack.setObjectName("stack")
|
||||
self.page = QtWidgets.QWidget()
|
||||
self.page.setGeometry(QtCore.QRect(0, 0, 399, 346))
|
||||
self.page.setObjectName("page")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.page)
|
||||
self.stackPage1 = QtWidgets.QWidget()
|
||||
self.stackPage1.setObjectName("stackPage1")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.stackPage1)
|
||||
self.gridLayout_3.setContentsMargins(3, 3, 3, 3)
|
||||
self.gridLayout_3.setSpacing(3)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.logy_box = QtWidgets.QCheckBox(self.page)
|
||||
self.logy_box = QtWidgets.QCheckBox(self.stackPage1)
|
||||
self.logy_box.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.logy_box.setObjectName("logy_box")
|
||||
self.gridLayout_3.addWidget(self.logy_box, 2, 1, 1, 1)
|
||||
self.logx_box = QtWidgets.QCheckBox(self.page)
|
||||
self.logx_box = QtWidgets.QCheckBox(self.stackPage1)
|
||||
self.logx_box.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.logx_box.setObjectName("logx_box")
|
||||
self.gridLayout_3.addWidget(self.logx_box, 2, 0, 1, 1)
|
||||
self.graphicsView = GraphicsLayoutWidget(self.page)
|
||||
self.graphicsView = GraphicsLayoutWidget(self.stackPage1)
|
||||
self.graphicsView.setObjectName("graphicsView")
|
||||
self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 2)
|
||||
self.stack.addItem(self.page, "")
|
||||
self.page_2 = QtWidgets.QWidget()
|
||||
self.page_2.setGeometry(QtCore.QRect(0, 0, 399, 346))
|
||||
self.page_2.setObjectName("page_2")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page_2)
|
||||
self.stack.addTab(self.stackPage1, "")
|
||||
self.stackPage2 = QtWidgets.QWidget()
|
||||
self.stackPage2.setObjectName("stackPage2")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.stackPage2)
|
||||
self.verticalLayout_2.setContentsMargins(3, 3, 3, 3)
|
||||
self.verticalLayout_2.setSpacing(3)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.stats_tableWidget = QtWidgets.QTableWidget(self.page_2)
|
||||
self.stats_tableWidget = QtWidgets.QTableWidget(self.stackPage2)
|
||||
self.stats_tableWidget.setFrameShape(QtWidgets.QFrame.Box)
|
||||
self.stats_tableWidget.setGridStyle(QtCore.Qt.NoPen)
|
||||
self.stats_tableWidget.setColumnCount(1)
|
||||
@ -133,15 +168,14 @@ class Ui_Dialog(object):
|
||||
self.stats_tableWidget.horizontalHeader().setVisible(False)
|
||||
self.stats_tableWidget.horizontalHeader().setSortIndicatorShown(True)
|
||||
self.verticalLayout_2.addWidget(self.stats_tableWidget)
|
||||
self.stack.addItem(self.page_2, "")
|
||||
self.page_3 = QtWidgets.QWidget()
|
||||
self.page_3.setGeometry(QtCore.QRect(0, 0, 399, 346))
|
||||
self.page_3.setObjectName("page_3")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.page_3)
|
||||
self.stack.addTab(self.stackPage2, "")
|
||||
self.stackPage3 = QtWidgets.QWidget()
|
||||
self.stackPage3.setObjectName("stackPage3")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.stackPage3)
|
||||
self.verticalLayout_3.setContentsMargins(3, 3, 3, 3)
|
||||
self.verticalLayout_3.setSpacing(3)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.corr_tableWidget = QtWidgets.QTableWidget(self.page_3)
|
||||
self.corr_tableWidget = QtWidgets.QTableWidget(self.stackPage3)
|
||||
self.corr_tableWidget.setFrameShape(QtWidgets.QFrame.Box)
|
||||
self.corr_tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.corr_tableWidget.setGridStyle(QtCore.Qt.NoPen)
|
||||
@ -159,28 +193,34 @@ class Ui_Dialog(object):
|
||||
self.corr_tableWidget.horizontalHeader().setStretchLastSection(True)
|
||||
self.corr_tableWidget.verticalHeader().setVisible(False)
|
||||
self.verticalLayout_3.addWidget(self.corr_tableWidget)
|
||||
self.stack.addItem(self.page_3, "")
|
||||
self.stack.addTab(self.stackPage3, "")
|
||||
self.gridLayout.addWidget(self.stack, 0, 1, 3, 1)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.stack.setCurrentIndex(0)
|
||||
self.stack.layout().setSpacing(0)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Fit results"))
|
||||
self.groupBox.setTitle(_translate("Dialog", "Output"))
|
||||
self.graph_checkBox.setText(_translate("Dialog", "New graph"))
|
||||
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.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.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"))
|
||||
self.reject_fit_checkBox.setText(_translate("Dialog", "Reject this fit"))
|
||||
self.del_prev_checkBox.setText(_translate("Dialog", "Delete previous fits"))
|
||||
self.logy_box.setText(_translate("Dialog", "logarithmic y axis"))
|
||||
self.logx_box.setText(_translate("Dialog", "logarithmic x axis"))
|
||||
self.stack.setItemText(self.stack.indexOf(self.page), _translate("Dialog", "Plot"))
|
||||
self.stack.setItemText(self.stack.indexOf(self.page_2), _translate("Dialog", "Statistics"))
|
||||
self.stack.setTabText(self.stack.indexOf(self.stackPage1), _translate("Dialog", "Plot"))
|
||||
self.stack.setTabText(self.stack.indexOf(self.stackPage2), _translate("Dialog", "Statistics"))
|
||||
item = self.corr_tableWidget.horizontalHeaderItem(0)
|
||||
item.setText(_translate("Dialog", "Parameter 1"))
|
||||
item = self.corr_tableWidget.horizontalHeaderItem(1)
|
||||
@ -189,6 +229,6 @@ class Ui_Dialog(object):
|
||||
item.setText(_translate("Dialog", "Corr."))
|
||||
item = self.corr_tableWidget.horizontalHeaderItem(3)
|
||||
item.setText(_translate("Dialog", "Partial Corr."))
|
||||
self.stack.setItemText(self.stack.indexOf(self.page_3), _translate("Dialog", "Correlations"))
|
||||
self.stack.setTabText(self.stack.indexOf(self.stackPage3), _translate("Dialog", "Correlations"))
|
||||
from ..lib.forms import ElideComboBox
|
||||
from pyqtgraph import GraphicsLayoutWidget
|
||||
|
@ -553,7 +553,9 @@ class FitContainer(ExperimentContainer):
|
||||
setattr(self, n, getattr(data, n))
|
||||
|
||||
def _init_plot(self, **kwargs):
|
||||
color = kwargs.get('color', (0, 0, 0))
|
||||
color = kwargs.get('color')
|
||||
if color is None:
|
||||
color = kwargs.get('linecolor', (0, 0, 0))
|
||||
if isinstance(color, BaseColor):
|
||||
color = color.rgb()
|
||||
|
||||
@ -605,7 +607,7 @@ class SignalContainer(ExperimentContainer):
|
||||
linecolor = kwargs.get('linecolor', color)
|
||||
|
||||
if symcolor is None and linecolor is None:
|
||||
color = next(self.colors)
|
||||
color = next(self.colors) if color is None else color
|
||||
symcolor = color
|
||||
linecolor = color
|
||||
elif symcolor is None:
|
||||
|
@ -17,6 +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)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
@ -387,6 +388,10 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
for c in available_cycles.keys():
|
||||
col_menu.addAction(c)
|
||||
|
||||
action = menu.exec(evt.globalPos())
|
||||
if action is None:
|
||||
return
|
||||
|
||||
graphs = []
|
||||
items = []
|
||||
for i in self.selectedIndexes():
|
||||
@ -395,7 +400,6 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
items.append(self.itemFromIndex(i))
|
||||
graphs.append(self.itemFromIndex(i).data(0, QtCore.Qt.UserRole))
|
||||
|
||||
action = menu.exec(evt.globalPos())
|
||||
if action == del_action:
|
||||
for gid in graphs:
|
||||
self.management.delete_graph(gid)
|
||||
@ -414,8 +418,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 = None
|
||||
save_action = None
|
||||
plt_action = save_action = extend_action = None
|
||||
menu.addSeparator()
|
||||
col_menu = menu.addMenu('Color cycle')
|
||||
for c in available_cycles.keys():
|
||||
@ -446,6 +449,7 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
menu.addSeparator()
|
||||
plt_action = menu.addAction('Plot fit parameter')
|
||||
save_action = menu.addAction('Save fit parameter')
|
||||
extend_action = menu.addAction('Extrapolate fit')
|
||||
|
||||
action = menu.exec(evt.globalPos())
|
||||
|
||||
@ -469,6 +473,9 @@ class DataTree(QtWidgets.QTreeWidget):
|
||||
elif action == save_action:
|
||||
self.saveFits.emit(s)
|
||||
|
||||
elif action == extend_action:
|
||||
self.extendFits.emit(s)
|
||||
|
||||
elif action.parent() == col_menu:
|
||||
self.management.set_cycle(s, action.text())
|
||||
|
||||
|
@ -11,7 +11,7 @@ from ..lib.pg_objects import PlotItem
|
||||
|
||||
|
||||
class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
closed = QtCore.pyqtSignal(dict, list, str, bool, dict)
|
||||
closed = QtCore.pyqtSignal(dict, list, str, bool, bool, list)
|
||||
redoFit = QtCore.pyqtSignal(dict)
|
||||
|
||||
def __init__(self, results: list, management, parent=None):
|
||||
@ -20,10 +20,17 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
self._management = management
|
||||
|
||||
self.maxx_line.setValidator(QtGui.QDoubleValidator())
|
||||
self.minx_line.setValidator(QtGui.QDoubleValidator())
|
||||
self.numx_line.setValidator(QtGui.QIntValidator())
|
||||
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._prevs = {}
|
||||
self._models = {}
|
||||
|
||||
for (res, parts) in results:
|
||||
for res in results:
|
||||
idx = res.idx
|
||||
data_k = management.data[idx]
|
||||
|
||||
@ -36,8 +43,7 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
for fit in data_k.get_fits():
|
||||
self._prevs[idx].append((fit.name, fit.statistics, fit.nobs-fit.nvar))
|
||||
|
||||
self._results = {res.idx: res for (res, _) in results}
|
||||
self._parts = {res.idx: parts for (res, parts) in results}
|
||||
self._results = {res.idx: res for res in results}
|
||||
self._opts = [(False, False) for _ in range(len(self._results))]
|
||||
|
||||
self.residplot = self.graphicsView.addPlot(row=0, col=0)
|
||||
@ -273,12 +279,75 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
plot_fits = self.curve_checkbox.isChecked()
|
||||
|
||||
if self.partial_checkBox.checkState() == QtCore.Qt.Checked:
|
||||
self.closed.emit(self._results, self._opts, graph, plot_fits, self._parts)
|
||||
else:
|
||||
self.closed.emit(self._results, self._opts, graph, plot_fits, {})
|
||||
|
||||
parts = self.partial_checkBox.checkState() == QtCore.Qt.Checked
|
||||
|
||||
extrapolate = [None, None, None]
|
||||
if self.extrapolate_box.isChecked():
|
||||
try:
|
||||
extrapolate[0] = float(self.minx_line.text())
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
extrapolate[1] = float(self.maxx_line.text())
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
extrapolate[2] = int(self.numx_line.text())
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
|
||||
self.closed.emit(self._results, self._opts, graph, plot_fits, parts, extrapolate)
|
||||
self.accept()
|
||||
|
||||
else:
|
||||
self.reject()
|
||||
|
||||
|
||||
class FitExtension(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
gridLayout = QtWidgets.QGridLayout(self)
|
||||
|
||||
self.label = QtWidgets.QLabel('Minimum value')
|
||||
gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||
|
||||
self.min_line = QtWidgets.QLineEdit()
|
||||
self.min_line.setValidator(QtGui.QDoubleValidator())
|
||||
gridLayout.addWidget(self.min_line, 0, 1, 1, 1)
|
||||
|
||||
self.label_2 = QtWidgets.QLabel('Maximum value')
|
||||
gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
|
||||
|
||||
self.max_line = QtWidgets.QLineEdit()
|
||||
self.max_line.setValidator(QtGui.QDoubleValidator())
|
||||
gridLayout.addWidget(self.max_line, 1, 1, 1, 1)
|
||||
|
||||
self.label_3 = QtWidgets.QLabel('Number of pts.')
|
||||
gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
|
||||
|
||||
self.num_pts = QtWidgets.QLineEdit()
|
||||
self.num_pts.setValidator(QtGui.QIntValidator())
|
||||
gridLayout.addWidget(self.num_pts, 2, 1, 1, 1)
|
||||
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox()
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2)
|
||||
|
||||
self.setLayout(gridLayout)
|
||||
|
||||
self.buttonBox.accepted.connect(self.accept)
|
||||
self.buttonBox.rejected.connect(self.reject)
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
try:
|
||||
xmin = float(self.min_line.text())
|
||||
xmax = float(self.max_line.text())
|
||||
nums = int(self.num_pts.text())
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
return xmin, xmax, nums
|
@ -11,10 +11,10 @@ from pyqtgraph import ViewBox
|
||||
from nmreval.configs import *
|
||||
|
||||
from .management import UpperManagement
|
||||
from ..Qt import QtCore, QtGui, QtPrintSupport, QtWidgets
|
||||
from ..Qt import QtGui, QtPrintSupport
|
||||
from ..data.shift_graphs import QShift
|
||||
from ..data.signaledit import QApodDialog, QBaselineDialog, QPhasedialog
|
||||
from ..fit.result import QFitResult
|
||||
from ..fit.result import FitExtension, QFitResult
|
||||
from ..graphs.graphwindow import QGraphWindow
|
||||
from ..graphs.movedialog import QMover
|
||||
from ..io.fcbatchreader import QFCReader
|
||||
@ -164,6 +164,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.datawidget.startShowProperty.connect(self.management.get_properties)
|
||||
self.datawidget.propertyChanged.connect(self.management.update_property)
|
||||
self.datawidget.tree.saveFits.connect(self.save_fit_parameter)
|
||||
self.datawidget.tree.extendFits.connect(self.extend_fit)
|
||||
|
||||
self.management.newData.connect(self.show_new_data)
|
||||
self.management.newGraph.connect(self.new_graph)
|
||||
@ -907,10 +908,10 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
res_dialog.redoFit.connect(self.management.redo_fits)
|
||||
res_dialog.show()
|
||||
|
||||
@QtCore.pyqtSlot(dict, list, str, bool, dict)
|
||||
def accepts_fit(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: dict) -> None:
|
||||
@QtCore.pyqtSlot(dict, list, str, bool, bool, list)
|
||||
def accepts_fit(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: bool, extrapolate: list) -> None:
|
||||
self.fit_dialog.set_parameter(res)
|
||||
self.management.make_fits(res, opts, param_graph, show_fit, parts)
|
||||
self.management.make_fits(res, opts, param_graph, show_fit, parts, extrapolate)
|
||||
|
||||
@QtCore.pyqtSlot(name='on_actionFunction_editor_triggered')
|
||||
def edit_models(self):
|
||||
@ -922,6 +923,16 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
self.editor.setWindowModality(QtCore.Qt.ApplicationModal)
|
||||
self.editor.show()
|
||||
|
||||
@QtCore.pyqtSlot(list)
|
||||
def extend_fit(self, sets: list):
|
||||
w = FitExtension(self)
|
||||
res = w.exec()
|
||||
print(res)
|
||||
if res:
|
||||
p = w.values
|
||||
x = linspace(p[0], p[1], num=p[2])
|
||||
self.management.extend_fits(sets, x)
|
||||
|
||||
@QtCore.pyqtSlot(name='on_action_create_fit_function_triggered')
|
||||
def open_fitmodel_wizard(self):
|
||||
from ..fit.function_creation_dialog import QUserFitCreator
|
||||
@ -931,7 +942,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
||||
|
||||
helper.show()
|
||||
|
||||
|
||||
@QtCore.pyqtSlot(name='on_actionShift_triggered')
|
||||
def shift_dialog(self):
|
||||
s = QShift(self)
|
||||
|
@ -4,6 +4,8 @@ import pathlib
|
||||
import re
|
||||
import uuid
|
||||
|
||||
import numpy as np
|
||||
|
||||
from nmreval.fit import data as fit_d
|
||||
from nmreval.fit.model import Model
|
||||
from nmreval.fit.result import FitResult
|
||||
@ -482,7 +484,7 @@ class UpperManagement(QtCore.QObject):
|
||||
parameter[set_id] = (new_values, set_parameter[1])
|
||||
self.start_fit(*self.__fit_options)
|
||||
|
||||
def make_fits(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: dict) -> None:
|
||||
def make_fits(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: bool, extrapolate: list) -> None:
|
||||
"""
|
||||
|
||||
Args:
|
||||
@ -491,6 +493,7 @@ class UpperManagement(QtCore.QObject):
|
||||
param_graph: None if no parameter to plot, '' for new graph, or id of existig graph
|
||||
show_fit: plot fit curve?
|
||||
parts: key is that of original data, value is list of subplots
|
||||
extrapolate:
|
||||
|
||||
"""
|
||||
f_id_list = []
|
||||
@ -503,6 +506,26 @@ class UpperManagement(QtCore.QObject):
|
||||
if reject:
|
||||
continue
|
||||
|
||||
if not all(e is None for e in extrapolate):
|
||||
spacefunc = np.geomspace if fit.islog else np.linspace
|
||||
|
||||
xmin = fit.x.min()
|
||||
xmax = fit.x.max()
|
||||
|
||||
len_data = len(fit.x_data)
|
||||
num_pts = 20*len_data-9 if len_data < 51 else 3*len_data
|
||||
|
||||
if extrapolate[0] is not None:
|
||||
xmin = extrapolate[0]
|
||||
if extrapolate[1] is not None:
|
||||
xmax = extrapolate[1]
|
||||
if extrapolate[2] is not None:
|
||||
num_pts = extrapolate[2]
|
||||
|
||||
_x = spacefunc(xmin, xmax, num=num_pts)
|
||||
|
||||
fit = fit.with_new_x(_x)
|
||||
|
||||
data_k = self.data[k]
|
||||
if delete_prev:
|
||||
tobedeleted.extend([f.id for f in data_k.get_fits()])
|
||||
@ -527,18 +550,16 @@ class UpperManagement(QtCore.QObject):
|
||||
f_id_list.append(f_id)
|
||||
data_k.set_fits(f_id)
|
||||
|
||||
if parts:
|
||||
color_scheme = available_cycles['colorblind']
|
||||
for subfunc, col in zip(fit.sub(fit.x), cycle(color_scheme)):
|
||||
subfunc.value = data_k.value
|
||||
subfunc.group = data_k.group
|
||||
subfunc.name += data_name
|
||||
sub_f_id = self.add(subfunc, color=col, linestyle=LineStyle.Dashed, symbol=SymbolStyle.No)
|
||||
|
||||
f_id_list.append(sub_f_id)
|
||||
gid = data_k.graph
|
||||
|
||||
if k in parts and show_fit:
|
||||
color_scheme = available_cycles['colorblind']
|
||||
for subfunc, col in zip(parts[k], cycle(color_scheme)):
|
||||
subfunc.value = data_k.value
|
||||
subfunc.group = data_k.group
|
||||
subfunc.name += data_name
|
||||
sub_f_id = self.add(subfunc, color=col, linestyle=LineStyle.Dashed, symbol=SymbolStyle.No)
|
||||
|
||||
f_id_list.append(sub_f_id)
|
||||
|
||||
self.delete_sets(tobedeleted)
|
||||
|
||||
if accepted and (param_graph != '-1'):
|
||||
@ -546,6 +567,27 @@ class UpperManagement(QtCore.QObject):
|
||||
|
||||
self.newData.emit(f_id_list, gid)
|
||||
|
||||
def extend_fits(self, set_id: list, x_range: np.ndarray):
|
||||
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)
|
||||
|
||||
graph_id = data.graph
|
||||
if graph_id not in graphs:
|
||||
graphs[graph_id] = []
|
||||
graphs[graph_id].append(self.add(fit))
|
||||
|
||||
color_scheme = available_cycles['colorblind']
|
||||
for subfunc, col in zip(fit.data.sub(fit.x), cycle(color_scheme)):
|
||||
subfunc.value = fit.value
|
||||
subfunc.group = fit.group
|
||||
graphs[graph_id].append(self.add(subfunc, color=col, linestyle=LineStyle.Dashed, symbol=SymbolStyle.No))
|
||||
|
||||
for k, v in graphs.items():
|
||||
self.newData.emit(v, k)
|
||||
|
||||
def make_fit_parameter(self, fit_sets: list[str | FitResult], graph_id: str = None):
|
||||
fit_dict = self._collect_fit_parameter(fit_sets)
|
||||
|
||||
|
@ -126,12 +126,12 @@ class Model(object):
|
||||
kwargs = self.fun_kwargs
|
||||
|
||||
if not self.is_multi:
|
||||
return [self.func(p, x, **kwargs)]
|
||||
return []
|
||||
else:
|
||||
return list(self._int_iter(x, *p, *self.fun_args, **kwargs))
|
||||
|
||||
def sub_name(self):
|
||||
if not self.is_multi:
|
||||
return [self.name]
|
||||
return []
|
||||
else:
|
||||
return list(self._iter_name())
|
||||
|
@ -9,6 +9,7 @@ import numpy as np
|
||||
from scipy.stats import f as fdist
|
||||
from scipy.interpolate import interp1d
|
||||
|
||||
from ._meta import MultiModel
|
||||
from .parameter import Parameter
|
||||
from ..data.points import Points
|
||||
from ..data.signals import Signal
|
||||
@ -17,7 +18,7 @@ from ..utils.text import convert
|
||||
|
||||
class FitResultCreator:
|
||||
@staticmethod
|
||||
def make_from_session(x_orig: np.ndarray, y_orig: np.ndarray, idx: int, kwargs: dict[Any]) -> (dict, list):
|
||||
def make_from_session(x_orig: np.ndarray, y_orig: np.ndarray, idx: int, kwargs: dict[Any]) -> FitResult:
|
||||
params = OrderedDict()
|
||||
|
||||
for key, pbest, err in zip(kwargs['pnames'], kwargs['parameter'], kwargs['error']):
|
||||
@ -37,10 +38,10 @@ class FitResultCreator:
|
||||
stats = FitResultCreator.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), []
|
||||
kwargs['name'], stats, idx)
|
||||
|
||||
@staticmethod
|
||||
def make_with_model(model, x_orig, y_orig, p, fun_kwargs, idx, nobs, nvar, corr, pcorr) -> (dict, list):
|
||||
def make_with_model(model, x_orig, y_orig, p, fun_kwargs, idx, nobs, nvar, corr, pcorr) -> FitResult:
|
||||
if np.all(x_orig > 0) and (np.max(x_orig) > 100 * np.min(x_orig)):
|
||||
islog = True
|
||||
else:
|
||||
@ -48,7 +49,7 @@ class FitResultCreator:
|
||||
|
||||
if len(x_orig) < 51:
|
||||
if islog:
|
||||
_x = np.logspace(np.log10(np.min(x_orig)), np.log10(np.max(x_orig)), num=10*x_orig.size-9)
|
||||
_x = np.geomspace(np.min(x_orig), np.max(x_orig), num=10*x_orig.size-9)
|
||||
else:
|
||||
_x = np.linspace(np.min(x_orig), np.max(x_orig), num=10*x_orig.size-9)
|
||||
else:
|
||||
@ -62,15 +63,6 @@ class FitResultCreator:
|
||||
parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)])
|
||||
p_final = [p.value for p in parameters.values()]
|
||||
|
||||
part_functions = []
|
||||
|
||||
if model.is_multi:
|
||||
for sub_name, sub_y in zip(model.sub_name(), model.sub(p_final, _x, **fun_kwargs)):
|
||||
if np.iscomplexobj(sub_y):
|
||||
part_functions.append(Signal(_x, sub_y, name=sub_name))
|
||||
else:
|
||||
part_functions.append(Points(_x, sub_y, name=sub_name))
|
||||
|
||||
_y = model.func(p_final, _x, **fun_kwargs)
|
||||
resid = model.func(p_final, x_orig, **fun_kwargs) - y_orig
|
||||
|
||||
@ -97,13 +89,10 @@ class FitResultCreator:
|
||||
correlation = corr
|
||||
partial_correlation = pcorr
|
||||
|
||||
return (
|
||||
FitResult(_x, _y, x_orig, y_orig, parameters, fun_kwargs, resid,
|
||||
nobs, nvar, model.name, stats,
|
||||
idx=idx, corr=correlation, pcorr=partial_correlation,
|
||||
islog=islog),
|
||||
part_functions,
|
||||
)
|
||||
return FitResult(_x, _y, x_orig, y_orig, parameters, fun_kwargs, resid,
|
||||
nobs, nvar, model.name, stats,
|
||||
idx=idx, corr=correlation, pcorr=partial_correlation,
|
||||
islog=islog, func=model)
|
||||
|
||||
@staticmethod
|
||||
def calc_statistics(y, residual, nobs=None, nvar=None):
|
||||
@ -141,8 +130,11 @@ class FitResultCreator:
|
||||
|
||||
class FitResult(Points):
|
||||
|
||||
def __init__(self, x, y, x_data, y_data, params, fun_kwargs, resid, nobs, nvar, name, stats,
|
||||
idx=None, corr=None, pcorr=None, islog=False,
|
||||
def __init__(self, x: np.ndarray, y: np.ndarray,
|
||||
x_data: np.ndarray, y_data: np.ndarray,
|
||||
params: dict, fun_kwargs: dict,
|
||||
resid: np.ndarray, nobs: int, nvar: int, name: str, stats: dict,
|
||||
idx=None, corr=None, pcorr=None, islog=False, func=None,
|
||||
**kwargs):
|
||||
|
||||
self.parameter, name = self._prepare_names(params, name)
|
||||
@ -162,6 +154,7 @@ class FitResult(Points):
|
||||
self.x_data = x_data
|
||||
self.y_data = y_data
|
||||
self._model_name = name
|
||||
self._func = func
|
||||
|
||||
@staticmethod
|
||||
def _prepare_names(parameter: dict, modelname: str):
|
||||
@ -200,6 +193,13 @@ class FitResult(Points):
|
||||
except AttributeError:
|
||||
return 'FitObject'
|
||||
|
||||
@property
|
||||
def func(self):
|
||||
if isinstance(self._func, MultiModel):
|
||||
return self._func.func
|
||||
else:
|
||||
return self._func
|
||||
|
||||
@property
|
||||
def p_final(self):
|
||||
return [pp.value for pp in self.parameter.values()]
|
||||
@ -215,6 +215,7 @@ class FitResult(Points):
|
||||
print(' #var :', self.nvar)
|
||||
print('\nParameter')
|
||||
print(self._parameter_string())
|
||||
|
||||
if statistics:
|
||||
print('Statistics')
|
||||
for k, v in self.statistics.items():
|
||||
@ -342,3 +343,24 @@ class FitResult(Points):
|
||||
data = FitResult(**state)
|
||||
|
||||
return data
|
||||
|
||||
def with_new_x(self, x_values):
|
||||
if self.func is None:
|
||||
raise ValueError('no fit function available to calcualate new y values')
|
||||
|
||||
new_fit = self.copy()
|
||||
y_values = self.func.func(self.p_final, x_values, **self.fun_kwargs)
|
||||
new_fit.set_data(x_values, y_values)
|
||||
|
||||
return new_fit
|
||||
|
||||
|
||||
def sub(self, x_values):
|
||||
part_functions = []
|
||||
for sub_name, sub_y in zip(self.func.sub_name(), self.func.sub(self.p_final, x_values, **self.fun_kwargs)):
|
||||
if np.iscomplexobj(sub_y):
|
||||
part_functions.append(Signal(x_values, sub_y, name=sub_name))
|
||||
else:
|
||||
part_functions.append(Points(x_values, sub_y, name=sub_name))
|
||||
|
||||
return part_functions
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>584</height>
|
||||
<width>864</width>
|
||||
<height>649</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -98,7 +98,37 @@
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<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">
|
||||
<widget class="QComboBox" name="graph_comboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" 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">
|
||||
@ -107,46 +137,88 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New graph</string>
|
||||
<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">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Leave empty to start at lowest point</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>min x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" rowspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="graph_comboBox">
|
||||
<widget class="QLineEdit" name="maxx_line">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="curve_checkbox">
|
||||
<property name="text">
|
||||
<string>Plot fit curve</string>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<property name="toolTip">
|
||||
<string>Leave empty to start at highest point</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>max x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="partial_checkBox">
|
||||
<property name="text">
|
||||
<string>Plot partial functions</string>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="numx_line">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string># pts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="parameter_checkbox">
|
||||
<property name="text">
|
||||
<string>Plot parameter</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="curve_checkbox">
|
||||
<property name="text">
|
||||
<string>Plot fit curve</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="partial_checkBox">
|
||||
<property name="text">
|
||||
<string>Plot partial functions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -180,7 +252,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="3">
|
||||
<widget class="QToolBox" name="stack">
|
||||
<widget class="QTabWidget" name="stack">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@ -190,19 +262,8 @@
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="tabSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>399</width>
|
||||
<height>346</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<widget class="QWidget" name="stackPage1" native="true">
|
||||
<attribute name="title">
|
||||
<string>Plot</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
@ -246,16 +307,8 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>399</width>
|
||||
<height>346</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<widget class="QWidget" name="stackPage2" native="true">
|
||||
<attribute name="title">
|
||||
<string>Statistics</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
@ -296,16 +349,8 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>399</width>
|
||||
<height>346</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<widget class="QWidget" name="stackPage3" native="true">
|
||||
<attribute name="title">
|
||||
<string>Correlations</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
|
Reference in New Issue
Block a user