From 3a655178d4e262c7df42b9c1567dcaf997c58071 Mon Sep 17 00:00:00 2001 From: MisterMLiL <99662459+MisterMLiL@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:43:00 +0300 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=9A=D0=BE=D1=80=D1=80=D0=B5=D0=BB=D1=8F?= =?UTF-8?q?=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=B0=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #31 --- statapp/calculations.py | 7 +++- statapp/correlation_analysis.py | 18 +++++++++ statapp/main_window.py | 20 ++++++---- statapp/models/correlation_analysis_model.py | 23 +++++++++++ statapp/ui/correlation_analysis_window.ui | 28 +++++++++++++ statapp/ui/main_window.ui | 8 +++- statapp/ui/ui_correlation_analysis_window.py | 42 ++++++++++++++++++++ statapp/ui/ui_main_window.py | 7 +++- statapp/ui/ui_variance_analysis_window.py | 3 +- statapp/ui/variance_analysis_window.ui | 4 +- 10 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 statapp/correlation_analysis.py create mode 100644 statapp/models/correlation_analysis_model.py create mode 100644 statapp/ui/correlation_analysis_window.ui create mode 100644 statapp/ui/ui_correlation_analysis_window.py diff --git a/statapp/calculations.py b/statapp/calculations.py index 208eae9..54f1b9d 100644 --- a/statapp/calculations.py +++ b/statapp/calculations.py @@ -1,4 +1,5 @@ import numpy as np +import pandas as pd DIRECT_LINK = 0 INDIRECT_LINK = 1 @@ -24,4 +25,8 @@ def generate_x_values(mean, std, typeConnection, y): def variance_analysis(data): return np.array([ [np.mean(col), np.std(col), np.min(col), np.max(col)] for col in data.T - ]) \ No newline at end of file + ]) + + +def correlation_analysis(data): + return pd.DataFrame(data).corr().to_numpy() \ No newline at end of file diff --git a/statapp/correlation_analysis.py b/statapp/correlation_analysis.py new file mode 100644 index 0000000..c252a45 --- /dev/null +++ b/statapp/correlation_analysis.py @@ -0,0 +1,18 @@ +from PySide2.QtWidgets import QDialog, QHeaderView + +from statapp.calculations import correlation_analysis +from statapp.models.correlation_analysis_model import CorrelationAnalysisModel +from statapp.ui.ui_correlation_analysis_window import Ui_CorrelationAnalysisWindow + + +class СorrelationAnalysisWindow(QDialog): + def __init__(self, data): + super().__init__() + self.ui = Ui_CorrelationAnalysisWindow() + self.ui.setupUi(self) + + res = correlation_analysis(data) + self.model = CorrelationAnalysisModel(res.round(2)) + self.ui.tableView.setModel(self.model) + header = self.ui.tableView.horizontalHeader() + header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch) diff --git a/statapp/main_window.py b/statapp/main_window.py index e6e02f0..e13d473 100644 --- a/statapp/main_window.py +++ b/statapp/main_window.py @@ -1,10 +1,10 @@ import numpy as np -from PySide2.QtCore import Slot, QLocale, QSize +from PySide2.QtCore import Slot, QSize from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QMainWindow, QMessageBox, QApplication +from PySide2.QtWidgets import QMainWindow, QMessageBox from statapp.calculations import generate_x_values -from statapp.generate_factor_window import GenerateFactorWindow, INDIRECT_LINK +from statapp.generate_factor_window import GenerateFactorWindow from statapp.models.input_values_model import InputValuesModel from statapp.generate_window import GenerateWindow from statapp.about_window import AboutWindow @@ -12,6 +12,7 @@ from statapp.models.fileslc_model import FileSLCModel from statapp.ui.ui_main_window import Ui_MainWindow from statapp.utils import resource_path, buildMessageBox from statapp.variance_analysis import VarianceAnalysisWindow +from statapp.correlation_analysis import СorrelationAnalysisWindow class MainWindow(QMainWindow): @@ -36,7 +37,7 @@ class MainWindow(QMainWindow): if current_data.size > 1: file = '' if self.fileModel.file_name: - file = '\nФайл сохранения:' + self.fileModel.file_name + file = '\nФайл сохранения: ' + self.fileModel.file_name msgBox = buildMessageBox \ ('Сохранение данных', @@ -54,12 +55,12 @@ class MainWindow(QMainWindow): data = self.fileModel.loadFile() if data is not None: self.model.updateAllData(data) - self.isDataChanged = True + self.isDataChanged = False else: data = self.fileModel.loadFile() if data is not None: self.model.updateAllData(data) - self.isDataChanged = True + self.isDataChanged = False @Slot() def on_savefileaction_triggered(self): @@ -103,11 +104,16 @@ class MainWindow(QMainWindow): dw = VarianceAnalysisWindow(self.model.getData()) dw.exec() + @Slot() + def on_correlationAnalisisAction_triggered(self): + dw = СorrelationAnalysisWindow(self.model.getData()) + dw.exec() + def closeEvent(self, event): if self.isDataChanged: file = '' if self.fileModel.file_name: - file = '\nФайл сохранения:' + self.fileModel.file_name + file = '\nФайл сохранения: ' + self.fileModel.file_name msgBox = buildMessageBox \ ('Завершение работы', diff --git a/statapp/models/correlation_analysis_model.py b/statapp/models/correlation_analysis_model.py new file mode 100644 index 0000000..3b8403d --- /dev/null +++ b/statapp/models/correlation_analysis_model.py @@ -0,0 +1,23 @@ +from PySide2.QtCore import QModelIndex, Qt + +from statapp.models.ro_table_model import ROTableModel +from statapp.models.utils import yx_header + + +class CorrelationAnalysisModel(ROTableModel): + def __init__(self, data): + super().__init__(data) + + def getHorizontalHeader(self): + return yx_header(self.columnCount(QModelIndex())) + + def getVerticalHeader(self): + return yx_header(self.rowCount(QModelIndex())) + + def data(self, index, role): + if role == Qt.DisplayRole: + if (index.column() <= index.row()): + return float(self._data[index.row(), index.column()]) + else: + None + return None diff --git a/statapp/ui/correlation_analysis_window.ui b/statapp/ui/correlation_analysis_window.ui new file mode 100644 index 0000000..83e3b08 --- /dev/null +++ b/statapp/ui/correlation_analysis_window.ui @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CorrelationAnalysisWindow</class> + <widget class="QDialog" name="CorrelationAnalysisWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>630</width> + <height>400</height> + </rect> + </property> + <property name="windowTitle"> + <string>Корреляционный анализ</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QTableView" name="tableView"/> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/statapp/ui/main_window.ui b/statapp/ui/main_window.ui index 850ad4c..37a6252 100644 --- a/statapp/ui/main_window.ui +++ b/statapp/ui/main_window.ui @@ -40,7 +40,7 @@ <x>0</x> <y>0</y> <width>800</width> - <height>27</height> + <height>21</height> </rect> </property> <widget class="QMenu" name="filemenu"> @@ -63,6 +63,7 @@ <string>Анализ данных</string> </property> <addaction name="varianceAnalysisAction"/> + <addaction name="correlationAnalisisAction"/> </widget> <widget class="QMenu" name="modelmenu"> <property name="title"> @@ -117,6 +118,11 @@ <string>Дисперсионный анализ</string> </property> </action> + <action name="correlationAnalisisAction"> + <property name="text"> + <string>Корреляционный анализ</string> + </property> + </action> </widget> <resources/> <connections/> diff --git a/statapp/ui/ui_correlation_analysis_window.py b/statapp/ui/ui_correlation_analysis_window.py new file mode 100644 index 0000000..b71840a --- /dev/null +++ b/statapp/ui/ui_correlation_analysis_window.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'correlation_analysis_window.ui' +## +## Created by: Qt User Interface Compiler version 5.15.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_CorrelationAnalysisWindow(object): + def setupUi(self, CorrelationAnalysisWindow): + if not CorrelationAnalysisWindow.objectName(): + CorrelationAnalysisWindow.setObjectName(u"CorrelationAnalysisWindow") + CorrelationAnalysisWindow.resize(630, 400) + self.gridLayout_2 = QGridLayout(CorrelationAnalysisWindow) + self.gridLayout_2.setObjectName(u"gridLayout_2") + self.gridLayout = QGridLayout() + self.gridLayout.setObjectName(u"gridLayout") + self.tableView = QTableView(CorrelationAnalysisWindow) + self.tableView.setObjectName(u"tableView") + + self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1) + + + self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1) + + + self.retranslateUi(CorrelationAnalysisWindow) + + QMetaObject.connectSlotsByName(CorrelationAnalysisWindow) + # setupUi + + def retranslateUi(self, CorrelationAnalysisWindow): + CorrelationAnalysisWindow.setWindowTitle(QCoreApplication.translate("CorrelationAnalysisWindow", u"\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) + # retranslateUi + diff --git a/statapp/ui/ui_main_window.py b/statapp/ui/ui_main_window.py index bfd7bfd..2759c89 100644 --- a/statapp/ui/ui_main_window.py +++ b/statapp/ui/ui_main_window.py @@ -32,6 +32,8 @@ class Ui_MainWindow(object): self.closefileaction.setObjectName(u"closefileaction") self.varianceAnalysisAction = QAction(MainWindow) self.varianceAnalysisAction.setObjectName(u"varianceAnalysisAction") + self.correlationAnalisisAction = QAction(MainWindow) + self.correlationAnalisisAction.setObjectName(u"correlationAnalisisAction") self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) @@ -51,7 +53,7 @@ class Ui_MainWindow(object): MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 800, 27)) + self.menubar.setGeometry(QRect(0, 0, 800, 21)) self.filemenu = QMenu(self.menubar) self.filemenu.setObjectName(u"filemenu") self.generatemenu = QMenu(self.menubar) @@ -78,6 +80,7 @@ class Ui_MainWindow(object): self.generatemenu.addAction(self.generateYaction) self.generatemenu.addAction(self.generateXaction) self.analyzemenu.addAction(self.varianceAnalysisAction) + self.analyzemenu.addAction(self.correlationAnalisisAction) self.helpmenu.addAction(self.aboutmenuaction) self.retranslateUi(MainWindow) @@ -94,6 +97,7 @@ class Ui_MainWindow(object): self.savefileaction.setText(QCoreApplication.translate("MainWindow", u"\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", None)) self.closefileaction.setText(QCoreApplication.translate("MainWindow", u"\u0417\u0430\u043a\u0440\u044b\u0442\u044c", None)) self.varianceAnalysisAction.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) + self.correlationAnalisisAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) self.label.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0422\u0410\u0422\u0418\u0421\u0422\u0418\u0427\u0415\u0421\u041a\u0418\u0415 \u0414\u0410\u041d\u041d\u042b\u0415", None)) self.filemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0424\u0430\u0439\u043b", None)) self.generatemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439", None)) @@ -101,3 +105,4 @@ class Ui_MainWindow(object): self.modelmenu.setTitle(QCoreApplication.translate("MainWindow", u"\u041c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", None)) self.helpmenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0421\u043f\u0440\u0430\u0432\u043a\u0430", None)) # retranslateUi + diff --git a/statapp/ui/ui_variance_analysis_window.py b/statapp/ui/ui_variance_analysis_window.py index 7cea5c2..07988a2 100644 --- a/statapp/ui/ui_variance_analysis_window.py +++ b/statapp/ui/ui_variance_analysis_window.py @@ -17,7 +17,7 @@ class Ui_VarianceAnalysisWindow(object): def setupUi(self, VarianceAnalysisWindow): if not VarianceAnalysisWindow.objectName(): VarianceAnalysisWindow.setObjectName(u"VarianceAnalysisWindow") - VarianceAnalysisWindow.resize(942, 606) + VarianceAnalysisWindow.resize(630, 400) self.gridLayout_2 = QGridLayout(VarianceAnalysisWindow) self.gridLayout_2.setObjectName(u"gridLayout_2") self.gridLayout = QGridLayout() @@ -39,3 +39,4 @@ class Ui_VarianceAnalysisWindow(object): def retranslateUi(self, VarianceAnalysisWindow): VarianceAnalysisWindow.setWindowTitle(QCoreApplication.translate("VarianceAnalysisWindow", u"\u0414\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) # retranslateUi + diff --git a/statapp/ui/variance_analysis_window.ui b/statapp/ui/variance_analysis_window.ui index 80de4a0..c4d9546 100644 --- a/statapp/ui/variance_analysis_window.ui +++ b/statapp/ui/variance_analysis_window.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>942</width> - <height>606</height> + <width>630</width> + <height>400</height> </rect> </property> <property name="windowTitle"> From 023a4a514221ab22bb29f87aeccd20b5595d1b2e Mon Sep 17 00:00:00 2001 From: MisterMLiL <99662459+MisterMLiL@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:49:10 +0300 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BE=D0=BA=D0=BD=D0=B0=20"=D0=9E=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B5"=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #45. --- statapp/main_window.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/statapp/main_window.py b/statapp/main_window.py index e13d473..f24ecbc 100644 --- a/statapp/main_window.py +++ b/statapp/main_window.py @@ -97,6 +97,11 @@ class MainWindow(QMainWindow): def on_aboutmenuaction_triggered(self): global about_window about_window = AboutWindow() + + icon = QIcon() + icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) + about_window.setWindowIcon(icon) + about_window.show() @Slot() From fbf359e515f962dd5e079d7a13b5b7dc39339764 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko <no-reply@maxim.slipenko.com> Date: Tue, 3 Oct 2023 13:38:33 +0300 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B1=D0=B0=D0=B3=D0=B8=20=D1=81=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=D0=BC=20=D0=B8=20=D1=81=D1=87=D0=B8=D1=82=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=B8=D1=81=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20(#5?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сloses #56, #57. --- statapp/models/fileslc_model.py | 3 ++- statapp/models/input_values_model.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/statapp/models/fileslc_model.py b/statapp/models/fileslc_model.py index 104a292..8a41b01 100644 --- a/statapp/models/fileslc_model.py +++ b/statapp/models/fileslc_model.py @@ -19,12 +19,13 @@ class FileSLCModel: self.file_name, _ = QFileDialog.getOpenFileName(None, "Загрузить файл", "", "Files (*.txt *.csv)") if self.file_name: try: - content = np.genfromtxt(self.file_name, delimiter=',', invalid_raise=True) + content = np.genfromtxt(self.file_name, delimiter=',', invalid_raise=True, ndmin=2) except ValueError as e: QMessageBox.warning \ (None, 'Ошибка', "Ошибка чтения файла!\nФайл нельзя открыть или файл неверного формата") + self.file_name = None return None return content diff --git a/statapp/models/input_values_model.py b/statapp/models/input_values_model.py index 6f5629c..0d770ea 100644 --- a/statapp/models/input_values_model.py +++ b/statapp/models/input_values_model.py @@ -10,7 +10,7 @@ class InputValuesModel(EditableTableModel): super().__init__(data) def getHorizontalHeader(self): - return yx_header(self.rowCount(QModelIndex())) + return yx_header(self.columnCount(QModelIndex())) def getY(self): return self._data[:, 0] From 15825c22007baeceebee98d19515ff038c1c2ae4 Mon Sep 17 00:00:00 2001 From: MisterMLiL <99662459+MisterMLiL@users.noreply.github.com> Date: Tue, 3 Oct 2023 13:54:47 +0300 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=B1=D0=B0=D0=B3=20"index=200=20is=20out?= =?UTF-8?q?=20of=20bounds"=20(#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #43 --- statapp/main_window.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/statapp/main_window.py b/statapp/main_window.py index f24ecbc..9acd5ae 100644 --- a/statapp/main_window.py +++ b/statapp/main_window.py @@ -1,7 +1,7 @@ import numpy as np from PySide2.QtCore import Slot, QSize from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QMainWindow, QMessageBox +from PySide2.QtWidgets import QMainWindow, QMessageBox, QAction from statapp.calculations import generate_x_values from statapp.generate_factor_window import GenerateFactorWindow @@ -24,7 +24,10 @@ class MainWindow(QMainWindow): icon = QIcon() icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) - self.setWindowIcon(icon) + + self.ui.generateXaction.setEnabled(False) + self.ui.varianceAnalysisAction.setEnabled(False) + self.ui.correlationAnalisisAction.setEnabled(False) self.isDataChanged = False self.model = InputValuesModel() @@ -34,6 +37,7 @@ class MainWindow(QMainWindow): @Slot() def on_openfileaction_triggered(self): current_data = self.model.getData() + data = np.array([]) if current_data.size > 1: file = '' if self.fileModel.file_name: @@ -53,15 +57,28 @@ class MainWindow(QMainWindow): return else: data = self.fileModel.loadFile() - if data is not None: + if data is not None and data.shape[0] > 0: self.model.updateAllData(data) self.isDataChanged = False else: data = self.fileModel.loadFile() - if data is not None: + if data is not None and data.shape[0] > 0: self.model.updateAllData(data) self.isDataChanged = False + if data.shape[1] == 1: + self.ui.generateXaction.setEnabled(True) + self.ui.varianceAnalysisAction.setEnabled(False) + self.ui.correlationAnalisisAction.setEnabled(False) + elif data.shape[1] > 1: + self.ui.generateXaction.setEnabled(True) + self.ui.varianceAnalysisAction.setEnabled(True) + self.ui.correlationAnalisisAction.setEnabled(True) + else: + self.ui.generateXaction.setEnabled(False) + self.ui.varianceAnalysisAction.setEnabled(False) + self.ui.correlationAnalisisAction.setEnabled(False) + @Slot() def on_savefileaction_triggered(self): self.isDataChanged = not self.fileModel.saveFile(self.model.getData()) @@ -78,6 +95,7 @@ class MainWindow(QMainWindow): y = np.random.normal(gw.mat, gw.deviation, size=(gw.count, 1)) self.model.updateAllData(y.round(2)) self.isDataChanged = True + self.generateXaction_action.setEnabled(True) @Slot() def on_generateXaction_triggered(self): @@ -91,6 +109,8 @@ class MainWindow(QMainWindow): # dd = dd.reshape(len(dd), 1) data = np.concatenate((data, x_arr), axis=1) self.model.updateAllData(data) + self.varianceAnalysisAction_action.setEnabled(True) + self.correlationAnalisisAction_action.setEnabled(True) self.isDataChanged = True @Slot()