This commit is contained in:
Maxim Slipenko 2023-12-26 18:26:56 +03:00
parent 10ce59f590
commit 64ce076f54
8 changed files with 193 additions and 134 deletions

View File

@ -3,5 +3,5 @@
<component name="Black">
<option name="sdkName" value="Poetry (statapp)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (statapp)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="statapp" project-jdk-type="Python SDK" />
</project>

View File

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Poetry (statapp)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="statapp" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

63
statapp/combo_delegate.py Normal file
View File

@ -0,0 +1,63 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from PySide2 import QtCore
from PySide2.QtWidgets import QComboBox, QItemDelegate
class ComboDelegate(QItemDelegate):
commitData = QtCore.Signal(object)
"""
A delegate that places a fully functioning QComboBox in every
cell of the column to which it's applied
"""
def __init__(self, parent, objects, object_names):
"""
Constructoe
:param parent: QTableView parent object
:param objects: List of objects to set. i.e. [True, False]
:param object_names: List of Object names to display. i.e. ['True', 'False']
"""
QItemDelegate.__init__(self, parent)
# objects to sent to the model associated to the combobox. i.e. [True, False]
self.objects = objects
# object description to display in the combobox. i.e. ['True', 'False']
self.object_names = object_names
@QtCore.Slot()
def currentIndexChanged(self):
self.commitData.emit(self.sender())
def createEditor(self, parent, option, index):
combo = QComboBox(parent)
combo.addItems(self.object_names)
combo.currentIndexChanged.connect(self.currentIndexChanged)
return combo
def setEditorData(self, editor, index):
editor.blockSignals(True)
val = index.model().data(index, role=QtCore.Qt.DisplayRole)
idx = self.objects.index(val)
editor.setCurrentIndex(idx)
editor.blockSignals(False)
def setModelData(self, editor, model, index):
model.setData(index, self.objects[editor.currentIndex()], QtCore.Qt.EditRole)

View File

@ -57,6 +57,7 @@ class MainWindow(QMainWindow):
self.ui.correlationAnalisisAction,
self.ui.linearPolynomAction,
self.ui.squaredPolynomAction,
self.ui.transformPolynomAction,
]
self.aboutWindow = None

View File

@ -0,0 +1,73 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import numpy as np
from PySide2.QtCore import Qt
from statapp.models.editable_table_model import EditableTableModel
from statapp.models.regression_result_model import RegressionResultModel
def defaultX(x):
return x
TRANSFORMS = {
'-': defaultX,
'sin(x)': np.sin,
'cos(x)': np.cos,
'log(x)': np.log,
'exp(x)': np.exp,
}
class TransformPolynomModel(RegressionResultModel, EditableTableModel):
def __init__(self, result):
super().__init__(result)
n = result.paramsAndImportance.shape[0]
self._transforms = ['-'] * n
def columnCount(self, index):
return 3
def updateAllData(self, data):
d = data.paramsAndImportance
self._monomials = data.monomials
super().updateAllData(d)
def flags(self, index):
if index.column() == 0 and index.row() != 0:
return EditableTableModel.flags(self, index)
return RegressionResultModel.flags(self, index)
def data(self, index, role):
if role == Qt.DisplayRole and index.column() == 0:
return self._transforms[index.row()]
return super().data(index, role)
def setData(self, index, value, role):
if role == Qt.EditRole and index.column() == 0:
self._transforms[index.row()] = value
topLeftIndex = self.createIndex(index.row(), 0)
bottomRightIndex = self.createIndex(index.row(), 0)
self.dataChanged.emit(topLeftIndex, bottomRightIndex)
return True
return super().setData(index, value, role)
def getHorizontalHeader(self):
return ['Преобразования'] + super().getHorizontalHeader()

View File

@ -18,14 +18,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import numpy as np
from PySide2.QtCore import Slot, QModelIndex
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import linearPolynom
from statapp.combo_delegate import ComboDelegate
from statapp.mathtex_header_view import MathTexHeaderView
from statapp.models.regression_result_model import RegressionResultModel
from statapp.models.transform_polynom_model import TransformPolynomModel, TRANSFORMS
from statapp.ui.ui_transform_polynom_window import Ui_PolynomWindow
from statapp.utils import addIcon, FloatDelegate
from statapp.utils import addIcon
class TransformPolynomWindow(QDialog):
@ -39,8 +40,20 @@ class TransformPolynomWindow(QDialog):
self.data = data
result = linearPolynom(data)
self.model = RegressionResultModel(result)
self.ui.tableView.setItemDelegate(FloatDelegate())
# Создание столбца из нулей
zeroCol = np.zeros((result.paramsAndImportance.shape[0], 1))
# Добавление столбца к исходному массиву
result.paramsAndImportance = np.column_stack((zeroCol, result.paramsAndImportance))
# self.ui.tableView.setItemDelegate(FloatDelegate())
self.ui.tableView.setItemDelegate(
ComboDelegate(
self.ui.tableView,
list(TRANSFORMS.keys()),
list(TRANSFORMS.keys()),
)
)
self.model = TransformPolynomModel(result)
self.ui.tableView.setModel(self.model)
self.ui.tableView.setVerticalHeader(MathTexHeaderView(self.ui.tableView))
header = self.ui.tableView.horizontalHeader()
@ -51,43 +64,24 @@ class TransformPolynomWindow(QDialog):
self.ui.fStatisticValueLabel.setText(str(result.fStatistic))
self.ui.rSquaredValueLabel.setText(str(result.scaledResidualVariance))
@Slot(QModelIndex)
def on_listTransforms_clicked(self, index):
item = self.ui.listTransforms.currentItem().text()
self.model.dataChanged.connect(self.on_data_changed)
def on_data_changed(self):
data = np.copy(self.data)
print(len(data[0:]))
for i in range(len(data[0:])):
for j in range(1, len(data[i])):
func = defaultX
if item == 'sin(x)':
func = np.sin
elif item == 'cos(x)':
func = np.cos
elif item == 'log(x)':
func = np.log
elif item == 'exp(x)':
func = np.exp
data[i][j] = func(data[i][j])
tr = self.model.data(self.model.createIndex(j, 0), Qt.DisplayRole)
data[i][j] = TRANSFORMS[tr](data[i][j])
self.rebuildData(data)
def rebuildData(self, data):
result = linearPolynom(data)
self.model = RegressionResultModel(result)
self.ui.tableView.setItemDelegate(FloatDelegate())
self.ui.tableView.setModel(self.model)
#self.ui.tableView.setVerticalHeader(MathTexHeaderView(self.ui.tableView))
header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
zeroCol = np.zeros((result.paramsAndImportance.shape[0], 1))
result.paramsAndImportance = np.column_stack((zeroCol, result.paramsAndImportance))
self.model.updateAllData(result)
self.ui.residualVarianceValueLabel.setText(str(result.residualVariance))
self.ui.scaledResidualVarianceValueLabel.setText(str(result.scaledResidualVariance))
self.ui.fStatisticValueLabel.setText(str(result.fStatistic))
self.ui.rSquaredValueLabel.setText(str(result.scaledResidualVariance))
def defaultX(x):
return x

View File

@ -14,24 +14,7 @@
<string>Полином</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="7">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<widget class="QTableView" name="tableView">
<attribute name="horizontalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>40</number>
</attribute>
</widget>
</item>
</layout>
</item>
<item row="1" column="7">
<item row="1" column="6">
<layout class="QGridLayout" name="polynomResult">
<property name="topMargin">
<number>10</number>
@ -94,49 +77,22 @@
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QListWidget" name="listTransforms">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
<item>
<property name="text">
<string>sin(x)</string>
</property>
<item row="0" column="6">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<widget class="QTableView" name="tableView">
<attribute name="horizontalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>40</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>40</number>
</attribute>
</widget>
</item>
<item>
<property name="text">
<string>cos(x)</string>
</property>
</item>
<item>
<property name="text">
<string>log(x)</string>
</property>
</item>
<item>
<property name="text">
<string>exp(x)</string>
</property>
</item>
</widget>
</layout>
</item>
</layout>
</widget>

View File

@ -40,19 +40,6 @@ class Ui_PolynomWindow(object):
PolynomWindow.resize(537, 444)
self.gridLayout_2 = QGridLayout(PolynomWindow)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.tableView = QTableView(PolynomWindow)
self.tableView.setObjectName(u"tableView")
self.tableView.horizontalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setDefaultSectionSize(40)
self.gridLayout.addWidget(self.tableView, 1, 3, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 7, 1, 1)
self.polynomResult = QGridLayout()
self.polynomResult.setObjectName(u"polynomResult")
self.polynomResult.setContentsMargins(-1, 10, -1, -1)
@ -97,22 +84,20 @@ class Ui_PolynomWindow(object):
self.polynomResult.addWidget(self.rSquaredValueLabel, 3, 1, 1, 1)
self.gridLayout_2.addLayout(self.polynomResult, 1, 7, 1, 1)
self.gridLayout_2.addLayout(self.polynomResult, 1, 6, 1, 1)
self.listTransforms = QListWidget(PolynomWindow)
QListWidgetItem(self.listTransforms)
QListWidgetItem(self.listTransforms)
QListWidgetItem(self.listTransforms)
QListWidgetItem(self.listTransforms)
self.listTransforms.setObjectName(u"listTransforms")
self.listTransforms.setMinimumSize(QSize(100, 0))
self.listTransforms.setMaximumSize(QSize(100, 16777215))
font = QFont()
font.setPointSize(12)
self.listTransforms.setFont(font)
self.listTransforms.setViewMode(QListView.ListMode)
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.tableView = QTableView(PolynomWindow)
self.tableView.setObjectName(u"tableView")
self.tableView.horizontalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setMinimumSectionSize(40)
self.tableView.verticalHeader().setDefaultSectionSize(40)
self.gridLayout_2.addWidget(self.listTransforms, 0, 0, 1, 1)
self.gridLayout.addWidget(self.tableView, 1, 3, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 6, 1, 1)
self.retranslateUi(PolynomWindow)
@ -130,17 +115,4 @@ class Ui_PolynomWindow(object):
self.rSquaredLabel.setText(QCoreApplication.translate("PolynomWindow", u"\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0434\u0435\u0440\u0435\u043c\u0438\u043d\u0438\u0437\u0430\u0446\u0438\u0438", None))
self.fStatisticValueLabel.setText(QCoreApplication.translate("PolynomWindow", u"undefined", None))
self.rSquaredValueLabel.setText(QCoreApplication.translate("PolynomWindow", u"undefined", None))
__sortingEnabled = self.listTransforms.isSortingEnabled()
self.listTransforms.setSortingEnabled(False)
___qlistwidgetitem = self.listTransforms.item(0)
___qlistwidgetitem.setText(QCoreApplication.translate("PolynomWindow", u"sin(x)", None));
___qlistwidgetitem1 = self.listTransforms.item(1)
___qlistwidgetitem1.setText(QCoreApplication.translate("PolynomWindow", u"cos(x)", None));
___qlistwidgetitem2 = self.listTransforms.item(2)
___qlistwidgetitem2.setText(QCoreApplication.translate("PolynomWindow", u"log(x)", None));
___qlistwidgetitem3 = self.listTransforms.item(3)
___qlistwidgetitem3.setText(QCoreApplication.translate("PolynomWindow", u"exp(x)", None));
self.listTransforms.setSortingEnabled(__sortingEnabled)
# retranslateUi