Init Commit

This commit is contained in:
2022-01-07 15:42:08 +08:00
commit 0cd8e3e851
12 changed files with 696 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
cmake-build-*/
.idea/

55
CMakeLists.txt Normal file
View File

@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.21)
project(Pearson)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS
Core
Gui
Widgets
REQUIRED)
if (WIN32)
add_executable(Pearson WIN32 main.cpp mainwindow.cpp mainwindow.h mainwindow.ui Pearson.cpp Pearson.h DataTableModel.cpp DataTableModel.h)
target_sources(Pearson PRIVATE resource.rc)
else ()
add_executable(Pearson main.cpp mainwindow.cpp mainwindow.h mainwindow.ui Pearson.cpp Pearson.h DataTableModel.cpp DataTableModel.h)
endif ()
target_link_libraries(Pearson
Qt5::Core
Qt5::Gui
Qt5::Widgets
)
if (MSVC)
set(DEBUG_SUFFIX)
if (CMAKE_BUILD_TYPE MATCHES "Debug")
set(DEBUG_SUFFIX "d")
endif ()
set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
endif ()
endif ()
if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
endif ()
foreach (QT_LIB Core Gui Widgets)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll"
"$<TARGET_FILE_DIR:${PROJECT_NAME}>")
endforeach (QT_LIB)
endif ()

114
DataTableModel.cpp Normal file
View File

@@ -0,0 +1,114 @@
//
// Created by fly on 2021/11/25.
//
#include "DataTableModel.h"
#include <cmath>
#include <QFile>
DataTableModel::DataTableModel(QObject *parent) : QAbstractTableModel(parent) {
m_headerData << "Name" << "Pearson" << "Pearson.Abs";
}
QVariant DataTableModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
return m_headerData.at(section);
}
return QAbstractItemModel::headerData(section, orientation, role);
}
int DataTableModel::rowCount(const QModelIndex &parent) const {
return m_tableData.size();
}
int DataTableModel::columnCount(const QModelIndex &parent) const {
return m_headerData.size();
}
QVariant DataTableModel::data(const QModelIndex &index, int role) const {
if (!index.isValid())
return QVariant();
if (role == Qt::DisplayRole) {
auto const &row = m_tableData.at(index.row());
switch (index.column()) {
case 0:
return std::get<0>(row);
case 1:
return std::get<1>(row);
case 2:
return std::get<2>(row);
default:
break;
}
}
return QVariant();
}
void DataTableModel::clear() {
beginResetModel();
m_tableData.clear();
endResetModel();
}
void DataTableModel::InsertRow(QString name, double pearson) {
beginInsertRows(QModelIndex(), m_tableData.size(), m_tableData.size());
m_tableData.push_back({name, pearson, std::abs(pearson)});
endInsertRows();
}
void DataTableModel::sort(int column, Qt::SortOrder order) {
beginResetModel();
std::sort(m_tableData.begin(), m_tableData.end(), [&](auto first, auto last) {
if (order == Qt::AscendingOrder) {
switch (column) {
case 0:
return std::get<0>(first) > std::get<0>(last);
break;
case 1:
return std::get<1>(first) > std::get<1>(last);
break;
case 2:
return std::get<2>(first) > std::get<2>(last);
break;
default:
break;
}
} else {
switch (column) {
case 0:
return std::get<0>(first) < std::get<0>(last);
break;
case 1:
return std::get<1>(first) < std::get<1>(last);
break;
case 2:
return std::get<2>(first) < std::get<2>(last);
break;
default:
break;
}
}
return false;
});
endResetModel();
// QAbstractItemModel::sort(column, order);
}
bool DataTableModel::SaveFile(const QString &fileName) {
QFile saveFile(fileName);
if (saveFile.open(QFile::WriteOnly)) {
auto header = QString("%1,%2,%3\r\n").arg(m_headerData.at(0)).arg(m_headerData.at(1)).arg(m_headerData.at(2));
saveFile.write(header.toLocal8Bit());
for (auto const &data: m_tableData) {
auto strData = QString("%1,%2,%3\r\n").arg(std::get<0>(data)).arg(std::get<1>(data)).arg(std::get<2>(data));
saveFile.write(strData.toLocal8Bit());
}
saveFile.close();
return true;
}
return false;
}

44
DataTableModel.h Normal file
View File

@@ -0,0 +1,44 @@
//
// Created by fly on 2021/11/25.
//
#ifndef PEARSON_DATATABLEMODEL_H
#define PEARSON_DATATABLEMODEL_H
#include <QAbstractTableModel>
#include <QVariant>
#include <QStringList>
#include <QList>
#include <tuple>
#include <list>
class DataTableModel : public QAbstractTableModel {
Q_OBJECT
public:
explicit DataTableModel(QObject *parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void sort(int column, Qt::SortOrder order) override;
void clear();
void InsertRow(QString name, double pearson);
bool SaveFile(QString const &fileName);
private:
QStringList m_headerData;
std::vector<std::tuple<QString, double, double>> m_tableData;
};
#endif //PEARSON_DATATABLEMODEL_H

39
Pearson.cpp Normal file
View File

@@ -0,0 +1,39 @@
//
// Created by fly on 2021/11/25.
//
#include "Pearson.h"
#include <numeric>
#include <cmath>
Pearson::Pearson(uint64_t index, const std::vector<double> &primary, const std::vector<double> &other, QObject *parent)
:
m_index(index),
m_primary(primary),
m_other(other),
QObject(parent) {
}
void Pearson::run() {
auto n = m_primary.size() * 1.0;
double pearson = n * std::inner_product(m_primary.begin(), m_primary.end(), m_other.begin(), 0.0) -
std::accumulate(m_primary.begin(), m_primary.end(), 0.0) *
std::accumulate(m_other.begin(), m_other.end(), 0.0);
double temp1 = n * std::inner_product(m_primary.begin(), m_primary.end(), m_primary.begin(), 0.0) -
std::pow(std::accumulate(m_primary.begin(), m_primary.end(), 0.0), 2.0);
double temp2 = n * std::inner_product(m_other.begin(), m_other.end(), m_other.begin(), 0.0) -
std::pow(std::accumulate(m_other.begin(), m_other.end(), 0.0), 2.0);
temp1 = std::sqrt(temp1);
temp2 = std::sqrt(temp2);
auto temp = (temp1 * temp2);
if (temp != 0) {
pearson = pearson / temp;
if (!std::isnan(pearson)) {
emit result(m_index, pearson);
}
}
emit finished();
}

33
Pearson.h Normal file
View File

@@ -0,0 +1,33 @@
//
// Created by fly on 2021/11/25.
//
#ifndef PEARSON_PEARSON_H
#define PEARSON_PEARSON_H
#include <QObject>
#include <QRunnable>
#include <vector>
class Pearson : public QObject, public QRunnable {
Q_OBJECT
public:
Pearson(uint64_t index, std::vector<double> const &primary, std::vector<double> const &other,
QObject *parent = nullptr);
void run() override;
signals:
void result(uint64_t index, double pearson);
void finished();
private:
std::vector<double> const &m_primary;
std::vector<double> const &m_other;
uint16_t m_index;
};
#endif //PEARSON_PEARSON_H

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

12
main.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
qRegisterMetaType<uint64_t>("uint64_t");
MainWindow w;
w.show();
return QApplication::exec();
}

175
mainwindow.cpp Normal file
View File

@@ -0,0 +1,175 @@
//
// Created by fly on 2021/11/25.
//
// You may need to build the project (run Qt uic code generator) to get "ui_MainWindow.h" resolved
#include "mainwindow.h"
#include "ui_MainWindow.h"
#include <QFileDialog>
#include <QRegExp>
#include <QStringList>
#include <QDebug>
#include <QList>
#include <QProgressBar>
#include <cmath>
#include <QMessageBox>
#include "Pearson.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
m_threadPool.setMaxThreadCount(1);
InitWidgetEnableState();
InitThreadCountComboBox();
InitTableView();
}
void MainWindow::InitHeaderComboBox() {
ui->primaryColComboBox->setEnabled(true);
ui->dropColComboBox->setEnabled(true);
ui->primaryColComboBox->clear();
ui->dropColComboBox->clear();
for (uint64_t i = 0; i < m_dataHeader.size(); ++i) {
ui->primaryColComboBox->addItem(m_dataHeader.at(i), i);
ui->dropColComboBox->addItem(m_dataHeader.at(i));
}
}
void MainWindow::InitThreadCountComboBox() {
auto count = QThread::idealThreadCount();
for (int i = 1; i <= count; ++i) {
ui->threadCountComboBox->addItem(QString("%1").arg(i), i);
}
ui->threadCountComboBox->setCurrentIndex(0);
}
void MainWindow::InitTableView() {
ui->tableView->setModel(&m_dataTableModel);
ui->tableView->setSelectionMode(QTableView::SingleSelection);
ui->tableView->setSelectionBehavior(QTableView::SelectRows);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableView->setSortingEnabled(true);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::InitWidgetEnableState() {
ui->primaryColComboBox->setEnabled(false);
ui->dropColComboBox->setEnabled(false);
ui->progressBar->setValue(0);
ui->threadCountComboBox->setEnabled(false);
ui->exportDataButton->setEnabled(false);
ui->startAnalysisButton->setEnabled(false);
}
void MainWindow::on_exploreButton_clicked() {
m_fileName = QFileDialog::getOpenFileName(this, "请选择要分析的csv文件", "", "CSV File (*.csv)");
if (m_fileName.size()) {
ui->openFileButton->setEnabled(true);
ui->filePathEdit->setText(m_fileName);
InitWidgetEnableState();
}
}
void MainWindow::on_openFileButton_clicked() {
static QRegExp split("\\s?,\\s?");
static QRegExp remove("[ \\r\\n]");
QFile file(m_fileName);
if (file.open(QFile::ReadOnly)) {
m_dataHeader.clear();
m_dataVector.clear();
QString headerLine = file.readLine();
headerLine.remove(remove);
auto headers = headerLine.split(split);
for (const auto &header: headers) {
m_dataHeader.emplace_back(header);
m_dataVector.emplace_back();
}
while (!file.atEnd()) {
QString dataLine = file.readLine();
dataLine.remove(remove);
auto strData = dataLine.split(split);
for (int i = 0; i < strData.size(); ++i) {
m_dataVector[i].push_back(strData[i].toDouble());
}
}
InitHeaderComboBox();
}
}
void MainWindow::on_primaryColComboBox_currentIndexChanged(int index) {
if (0 <= index) {
ui->threadCountComboBox->setEnabled(true);
ui->exportDataButton->setEnabled(true);
ui->startAnalysisButton->setEnabled(true);
m_primaryIndex = ui->primaryColComboBox->currentData().toULongLong();
}
}
void MainWindow::on_dropColComboBox_currentIndexChanged(int index) {
if (index == -1) return;
auto colName = ui->dropColComboBox->currentText();
auto items = ui->dropListWidget->findItems(colName, Qt::MatchFixedString);
if (!items.size()) {
ui->dropListWidget->addItem(colName);
}
ui->dropColComboBox->setCurrentIndex(-1);
}
void MainWindow::on_dropListWidget_itemDoubleClicked(QListWidgetItem *item) {
ui->dropListWidget->removeItemWidget(item);
ui->dropListWidget->takeItem(ui->dropListWidget->currentRow());
}
void MainWindow::on_threadCountComboBox_currentIndexChanged(int index) {
if (0 <= index) {
m_threadPool.setMaxThreadCount(ui->threadCountComboBox->currentData().toInt());
}
}
void MainWindow::on_startAnalysisButton_clicked() {
auto const &primaryData = m_dataVector.at(m_primaryIndex);
ui->progressBar->setMaximum(m_dataHeader.size() - 1 - ui->dropListWidget->count());
ui->progressBar->setValue(0);
m_dataTableModel.clear();
for (int i = 0; i < m_dataHeader.size(); ++i) {
if (i == m_primaryIndex || !ui->dropListWidget->findItems(m_dataHeader[i], Qt::MatchFixedString).empty()) {
continue;
}
auto *pearson = new Pearson(i, primaryData, m_dataVector.at(i), this);
connect(pearson, SIGNAL(result(uint64_t, double)), this, SLOT(PearsonResult(uint64_t, double)));
connect(pearson, SIGNAL(finished()), this, SLOT(PearsonFinished()));
//pearson->run();
m_threadPool.start(pearson);
}
}
void MainWindow::on_exportDataButton_clicked() {
auto saveFileName = QFileDialog::getSaveFileName(this, "文件保存", "", "CSV File (*.csv)");
if (m_dataTableModel.SaveFile(saveFileName)) {
QMessageBox::information(this, "保存成功", "文件保存成功", "确定");
} else {
QMessageBox::warning(this, "保存失败", "文件保存失败", "确定");
}
}
void MainWindow::PearsonResult(uint64_t index, double pearson) {
qDebug() << m_dataHeader[index] << " " << pearson;
m_dataTableModel.InsertRow(m_dataHeader[index], pearson);
}
void MainWindow::PearsonFinished() {
// delete sender();
ui->progressBar->setValue(ui->progressBar->value() + 1);
}

72
mainwindow.h Normal file
View File

@@ -0,0 +1,72 @@
//
// Created by fly on 2021/11/25.
//
#ifndef PEARSON_MAINWINDOW_H
#define PEARSON_MAINWINDOW_H
#include <QMainWindow>
#include <QMap>
#include <QString>
#include <vector>
#include <QThreadPool>
#include <QThread>
#include <QListWidgetItem>
#include "DataTableModel.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
void InitWidgetEnableState();
void InitHeaderComboBox();
void InitThreadCountComboBox();
void InitTableView();
protected slots:
void on_exploreButton_clicked();
void on_openFileButton_clicked();
void on_primaryColComboBox_currentIndexChanged(int index);
void on_dropColComboBox_currentIndexChanged(int index);
void on_threadCountComboBox_currentIndexChanged(int index);
void on_dropListWidget_itemDoubleClicked(QListWidgetItem *item);
void on_startAnalysisButton_clicked();
void on_exportDataButton_clicked();
void PearsonResult(uint64_t index, double pearson);
void PearsonFinished();
private:
Ui::MainWindow *ui;
QThreadPool m_threadPool;
QString m_fileName;
uint64_t m_primaryIndex;
std::vector<QString> m_dataHeader;
std::vector<std::vector<double>> m_dataVector;
DataTableModel m_dataTableModel;
};
#endif //PEARSON_MAINWINDOW_H

149
mainwindow.ui Normal file
View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>642</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Pearson分析工具 v0.1.0</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QGridLayout" name="gridLayout_2" columnstretch="2,3,2">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>③ 选择丢弃数据列(双击删除)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="dropColComboBox">
<property name="placeholderText">
<string>请选择无需分析列</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="dropListWidget"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>① 选择文件并打开</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLineEdit" name="filePathEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>请选择文件...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exploreButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openFileButton">
<property name="text">
<string>打开文件</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>② 选择主要数据列</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="primaryColComboBox">
<property name="placeholderText">
<string>请选择主要数据列</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>④ 分析操作(先选择工作线程数量再分析)</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="threadCountComboBox">
<property name="placeholderText">
<string>请选择分析线程数</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="startAnalysisButton">
<property name="text">
<string>开始分析</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="exportDataButton">
<property name="text">
<string>导出数据</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QTableView" name="tableView"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

1
resource.rc Normal file
View File

@@ -0,0 +1 @@
IDI_ICON1 ICON "icon.ico"