diff --git a/src/backend/generalTest/CorrelationCoefficient.h b/src/backend/generalTest/CorrelationCoefficient.h --- a/src/backend/generalTest/CorrelationCoefficient.h +++ b/src/backend/generalTest/CorrelationCoefficient.h @@ -56,13 +56,13 @@ QWidget* view() const override; - void performTest(int test, bool categoricalVariable = false); + void performTest(int test, bool categoricalVariable = false, bool calculateStats = true); private: void performPearson(bool categoricalVariable); void performKendall(); void performSpearman(); - void chiSquareIndpendence(); + void performChiSquareIndpendence(bool calculateStats); int findDiscordants(int* ranks, int start, int end); diff --git a/src/backend/generalTest/CorrelationCoefficient.cpp b/src/backend/generalTest/CorrelationCoefficient.cpp --- a/src/backend/generalTest/CorrelationCoefficient.cpp +++ b/src/backend/generalTest/CorrelationCoefficient.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -58,11 +59,13 @@ CorrelationCoefficient::~CorrelationCoefficient() { } -void CorrelationCoefficient::performTest(int test, bool categoricalVariable) { +void CorrelationCoefficient::performTest(int test, bool categoricalVariable, bool calculateStats) { m_statsTable = ""; m_correlationValue = 0; m_statisticValue.clear(); m_pValue.clear(); + m_inputStatsTableModel->clear(); + for (int i = 0; i < RESULTLINESCOUNT; i++) m_resultLine[i]->clear(); @@ -84,6 +87,7 @@ case CorrelationCoefficient::ChiSquare: switch (testSubtype(test)) { case CorrelationCoefficient::IndependenceTest: + performChiSquareIndpendence(calculateStats); break; } break; @@ -335,7 +339,8 @@ /***********************************************Chi Square Test for Indpendence******************************************************************/ -void CorrelationCoefficient::chiSquareIndpendence() { +void CorrelationCoefficient::performChiSquareIndpendence(bool calculateStats) { + Q_UNUSED(calculateStats); } /***********************************************Helper Functions******************************************************************/ diff --git a/src/backend/generalTest/GeneralTest.h b/src/backend/generalTest/GeneralTest.h --- a/src/backend/generalTest/GeneralTest.h +++ b/src/backend/generalTest/GeneralTest.h @@ -38,6 +38,8 @@ class Column; class QVBoxLayout; class QLabel; +class QStandardItemModel; +class QAbstractItemModel; class GeneralTest : public AbstractPart { Q_OBJECT @@ -79,6 +81,7 @@ QString statsTable(); QVBoxLayout* summaryLayout(); + QAbstractItemModel* inputStatsTableModel(); //virtual methods // QIcon icon() const override; @@ -110,6 +113,8 @@ QVBoxLayout* m_summaryLayout{nullptr}; QLabel* m_resultLine[RESULTLINESCOUNT]; + QStandardItemModel* m_inputStatsTableModel; + int testType(int test); int testSubtype(int test); diff --git a/src/backend/generalTest/GeneralTest.cpp b/src/backend/generalTest/GeneralTest.cpp --- a/src/backend/generalTest/GeneralTest.cpp +++ b/src/backend/generalTest/GeneralTest.cpp @@ -32,14 +32,9 @@ #include "backend/core/column/Column.h" #include "backend/lib/macros.h" -//#include -//#include -//#include #include #include -//#include -//#include -//#include +#include #include @@ -51,9 +46,9 @@ GeneralTest::GeneralTest(const QString& name, const AspectType& type) : AbstractPart(name, type), - m_summaryLayout(new QVBoxLayout()) { + m_summaryLayout(new QVBoxLayout()), + m_inputStatsTableModel(new QStandardItemModel) { - m_currTestName = i18n("Result Table"); for (int i = 0; i < RESULTLINESCOUNT; i++) { m_resultLine[i] = new QLabel(); m_summaryLayout->addWidget(m_resultLine[i]); @@ -90,6 +85,10 @@ return m_summaryLayout; } +QAbstractItemModel* GeneralTest::inputStatsTableModel() { + return m_inputStatsTableModel; +} + void GeneralTest::setColumns(QStringList cols) { m_columns.clear(); diff --git a/src/backend/generalTest/HypothesisTest.h b/src/backend/generalTest/HypothesisTest.h --- a/src/backend/generalTest/HypothesisTest.h +++ b/src/backend/generalTest/HypothesisTest.h @@ -56,8 +56,9 @@ void setSignificanceLevel(QVariant alpha); void setTail(HypothesisTailType tail); - void performTest(int test, bool categoricalVariable = true, bool equalVariance = true); + void performTest(int test, bool categoricalVariable = true, bool equalVariance = true, bool calculateStats = true); void performLeveneTest(bool categoricalVariable); + void initInputStatsTable(int test, bool calculateStats); QList& statisticValue(); QList& pValue(); @@ -66,7 +67,7 @@ double myTest; private: - void performTwoSampleIndependentTest(int test, bool categoricalVariable = false, bool equalVariance = true); + void performTwoSampleIndependentTest(int test, bool categoricalVariable = false, bool equalVariance = true, bool calculateStats = true); void performTwoSamplePairedTest(int test); void performOneSampleTest(int test); void performOneWayAnova(); diff --git a/src/backend/generalTest/HypothesisTest.cpp b/src/backend/generalTest/HypothesisTest.cpp --- a/src/backend/generalTest/HypothesisTest.cpp +++ b/src/backend/generalTest/HypothesisTest.cpp @@ -32,14 +32,11 @@ #include "backend/core/column/Column.h" #include "backend/lib/macros.h" -#include #include -#include #include +#include #include -#include -#include -#include +#include #include @@ -68,7 +65,7 @@ m_tail = tail; } -void HypothesisTest::performTest(int test, bool categoricalVariable, bool equalVariance) { +void HypothesisTest::performTest(int test, bool categoricalVariable, bool equalVariance, bool calculateStats) { m_pValue.clear(); m_statisticValue.clear(); m_statsTable = ""; @@ -77,10 +74,13 @@ m_resultLine[i]->setToolTip(QString()); } + if (calculateStats) + m_inputStatsTableModel->clear(); + switch (testSubtype(test)) { case TwoSampleIndependent: { m_currTestName = "

" + i18n("Two Sample Independent Test") + "

"; - performTwoSampleIndependentTest(testType(test), categoricalVariable, equalVariance); + performTwoSampleIndependentTest(testType(test), categoricalVariable, equalVariance, calculateStats); break; } case TwoSamplePaired: @@ -121,6 +121,29 @@ emit changed(); } +void HypothesisTest::initInputStatsTable(int test, bool calculateStats) { + m_inputStatsTableModel->clear(); + + if (!calculateStats) { + switch (testSubtype(test)) { + case TwoSampleIndependent: { + m_inputStatsTableModel->setRowCount(2); + m_inputStatsTableModel->setColumnCount(4); + m_inputStatsTableModel->setHorizontalHeaderLabels( + {i18n("N"), i18n("Sum"), i18n("Mean"), i18n("Standard Deviation")}); + break; + } + case TwoSamplePaired: + case OneSample: + case OneWay: + case TwoWay: + break; + } + } + + emit changed(); +} + QList& HypothesisTest::statisticValue() { return m_statisticValue; } @@ -135,20 +158,40 @@ //TODO: backend of z test; //TODO: use https://www.gnu.org/software/gsl/doc/html/statistics.html for basic statistic calculations - /**************************Two Sample Independent *************************************/ +// program is crashing on some input. +void HypothesisTest::performTwoSampleIndependentTest(int test, bool categoricalVariable, bool equalVariance, bool calculateStats) { + int n[2]; + double sum[2], mean[2], std[2]; + QString col1Name; + QString col2Name; + + if (!calculateStats) { + QString textValue; + QDEBUG("m_inputStatsTable row and column count " << m_inputStatsTableModel->rowCount() << m_inputStatsTableModel->columnCount()); -void HypothesisTest::performTwoSampleIndependentTest(int test, bool categoricalVariable, bool equalVariance) { + for (int i = 0; i < 2; i++) { + n[i] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 0)).toInt(); + sum[i] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 1)).toDouble(); + mean[i] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 2)).toDouble(); + std[i] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 3)).toDouble(); + + if (sum[i] == 0.0) + sum[i] = mean[i] * n[i]; + if (mean[i] == 0.0 && n[i] > 0) + mean[i] = sum[i] / n[i]; + + col1Name = "1"; + col2Name = "2"; + } + } else { if (m_columns.size() != 2) { printError("Inappropriate number of m_columns selected"); return; } - int n[2]; - double sum[2], mean[2], std[2]; - - QString col1Name = m_columns[0]->name(); - QString col2Name = m_columns[1]->name(); + col1Name = m_columns[0]->name(); + col2Name = m_columns[1]->name(); if (!categoricalVariable && m_columns[0]->isNumeric()) { for (int i = 0; i < 2; i++) { @@ -201,6 +244,7 @@ col2Name = baseColName + " " + iter.key(); } } + } QVariant rowMajor[] = {"", "N", "Sum", "Mean", "Std", col1Name, n[0], sum[0], mean[0], std[0], @@ -211,7 +255,10 @@ for (int i = 0; i < 2; i++) { if (n[i] == 0) { + if (calculateStats) printError("At least two values should be there in every column"); + else + printError("In Statistic Table you filled above, value of N for every row should be > 0"); return; } if (std[i] == 0.0) { @@ -250,6 +297,9 @@ printLine(9, "Assumption: UnEqual Variance b/w both population means"); } + printLine(6, i18n("Degree of Freedom is %1", df), "green"); + printTooltip(6, i18n("Number of independent Pieces of information that went into calculating the estimate")); + printLine(8, "Assumption: Both Populations approximately follow normal distribution"); break; } @@ -272,11 +322,8 @@ printTooltip(4, i18n("More is the |%1-value|, more safely we can reject the null hypothesis", testName)); printLine(5, i18n("P Value is %1 ", m_pValue[0]), "green"); - - printLine(6, i18n("Degree of Freedom is %1", df), "green"); - printTooltip(6, i18n("Number of independent Pieces of information that went into calculating the estimate")); - printTooltip(5, getPValueTooltip(m_pValue[0])); + return; } diff --git a/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.h b/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.h --- a/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.h +++ b/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.h @@ -89,6 +89,7 @@ void spreadsheetChanged(const QModelIndex&); void col1IndexChanged(int index); void changeCbCol2Label(); + void chbColumnStatisticsStateChanged(); // void connectionChanged(); diff --git a/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.cpp b/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.cpp --- a/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.cpp +++ b/src/kdefrontend/dockwidgets/CorrelationCoefficientDock.cpp @@ -77,6 +77,8 @@ ui.cbTestType->hide(); // adding item to tests and testtype combo box; // making all test blocks invisible at starting. + ui.lStatsFromSpreadsheet->hide(); + ui.chbStatsFromSpreadsheet->hide(); ui.lCategorical->hide(); ui.chbCategorical->hide(); ui.lCol1->hide(); @@ -126,13 +128,13 @@ connect(ui.cbTest, static_cast(&QComboBox::currentIndexChanged), this, &CorrelationCoefficientDock::showTestType); connect(ui.cbTestType, static_cast(&QComboBox::currentIndexChanged), this, &CorrelationCoefficientDock::showCorrelationCoefficient); connect(ui.chbCategorical, &QCheckBox::stateChanged, this, &CorrelationCoefficientDock::changeCbCol2Label); + connect(ui.chbStatsFromSpreadsheet, &QCheckBox::stateChanged, this, &CorrelationCoefficientDock::chbColumnStatisticsStateChanged); connect(ui.pbPerformTest, &QPushButton::clicked, this, &CorrelationCoefficientDock::findCorrelationCoefficient); connect(ui.cbCol1, static_cast(&QComboBox::currentIndexChanged), this, &CorrelationCoefficientDock::col1IndexChanged); ui.cbTest->setCurrentIndex(0); emit ui.cbTest->currentIndexChanged(0); - ui.cbTestType->setCurrentIndex(0); emit ui.cbTestType->currentIndexChanged(0); } @@ -180,6 +182,7 @@ m_test = ui.cbTest->currentData().toInt(); + ui.cbTestType->clear(); switch (m_test) { case CorrelationCoefficient::ChiSquare: ui.lTestType->show(); @@ -206,6 +209,10 @@ ui.lCol2->show(); ui.cbCol2->show(); + ui.lStatsFromSpreadsheet->setVisible(testType(m_test) == CorrelationCoefficient::ChiSquare); + ui.chbStatsFromSpreadsheet->setVisible(testType(m_test) == CorrelationCoefficient::ChiSquare); + ui.chbStatsFromSpreadsheet->setChecked(true); + ui.lCategorical->setVisible(testType(m_test) == CorrelationCoefficient::Pearson); ui.chbCategorical->setVisible(testType(m_test) == CorrelationCoefficient::Pearson); @@ -415,6 +422,16 @@ } } +void CorrelationCoefficientDock::chbColumnStatisticsStateChanged() { + bool chbChecked = ui.chbStatsFromSpreadsheet->isChecked(); + + ui.lVariables->setVisible(chbChecked); + ui.lCol1->setVisible(chbChecked); + ui.cbCol1->setVisible(chbChecked); + ui.lCol2->setVisible(chbChecked); + ui.cbCol2->setVisible(chbChecked); +} + ////************************************************************* ////******************** SETTINGS ******************************* ////************************************************************* diff --git a/src/kdefrontend/dockwidgets/HypothesisTestDock.h b/src/kdefrontend/dockwidgets/HypothesisTestDock.h --- a/src/kdefrontend/dockwidgets/HypothesisTestDock.h +++ b/src/kdefrontend/dockwidgets/HypothesisTestDock.h @@ -95,6 +95,7 @@ void changeCbCol2Label(); void chbPopulationSigmaStateChanged(); void col1IndexChanged(int index); + void chbCalculateStatsStateChanged(); void onRbH1OneTail1Toggled(bool checked); void onRbH1OneTail2Toggled(bool checked); diff --git a/src/kdefrontend/dockwidgets/HypothesisTestDock.cpp b/src/kdefrontend/dockwidgets/HypothesisTestDock.cpp --- a/src/kdefrontend/dockwidgets/HypothesisTestDock.cpp +++ b/src/kdefrontend/dockwidgets/HypothesisTestDock.cpp @@ -81,6 +81,8 @@ ui.pbLeveneTest->hide(); ui.lCategorical->hide(); ui.chbCategorical->hide(); + ui.lCalculateStats->hide(); + ui.chbCalculateStats->hide(); ui.lCol1->hide(); ui.cbCol1->hide(); ui.lCol2->hide(); @@ -211,6 +213,7 @@ connect(ui.rbH1TwoTail, &QRadioButton::toggled, this, &HypothesisTestDock::onRbH1TwoTailToggled); connect(ui.cbCol1, static_cast(&QComboBox::currentIndexChanged), this, &HypothesisTestDock::col1IndexChanged); + connect(ui.chbCalculateStats, &QCheckBox::stateChanged, this, &HypothesisTestDock::chbCalculateStatsStateChanged); connect(ui.chbCategorical, &QCheckBox::stateChanged, this, &HypothesisTestDock::changeCbCol2Label); connect(ui.chbPopulationSigma, &QCheckBox::stateChanged, this, &HypothesisTestDock::chbPopulationSigmaStateChanged); @@ -292,6 +295,10 @@ ui.lCol3->setVisible(m_test == (HypothesisTest::Anova | HypothesisTest::TwoWay)); ui.cbCol3->setVisible(m_test == (HypothesisTest::Anova | HypothesisTest::TwoWay)); + ui.lCalculateStats->show(); + ui.chbCalculateStats->show(); + ui.chbCalculateStats->setChecked(true); + ui.lEqualVariance->setVisible(m_test == (HypothesisTest::TTest | HypothesisTest::TwoSampleIndependent)); ui.chbEqualVariance->setVisible(m_test == (HypothesisTest::TTest | HypothesisTest::TwoSampleIndependent)); ui.chbEqualVariance->setChecked(true); @@ -355,7 +362,10 @@ m_hypothesisTest->setColumns(cols); - m_hypothesisTest->performTest(m_test, ui.chbCategorical->isChecked(), ui.chbEqualVariance->isChecked()); + m_hypothesisTest->performTest(m_test, + ui.chbCategorical->isChecked(), + ui.chbEqualVariance->isChecked(), + ui.chbCalculateStats->isChecked()); } void HypothesisTestDock::performLeveneTest() { @@ -567,6 +577,24 @@ changeCbCol2Label(); } +void HypothesisTestDock::chbCalculateStatsStateChanged() { + if (!ui.chbCalculateStats->isChecked()) { + ui.lVariables->hide(); + ui.lCol1->hide(); + ui.cbCol1->hide(); + ui.lCol2->hide(); + ui.cbCol2->hide(); + ui.lCol3->hide(); + ui.cbCol3->hide(); + } else { + ui.lVariables->show(); + showHypothesisTest(); + } + + if (m_hypothesisTest != nullptr) + m_hypothesisTest->initInputStatsTable(m_test, ui.chbCalculateStats->isChecked()); +} + //void HypothesisTestDock::connectionChanged() { // if (ui.cbConnection->currentIndex() == -1) { diff --git a/src/kdefrontend/generalTest/GeneralTestView.h b/src/kdefrontend/generalTest/GeneralTestView.h --- a/src/kdefrontend/generalTest/GeneralTestView.h +++ b/src/kdefrontend/generalTest/GeneralTestView.h @@ -42,6 +42,7 @@ class QToolBar; class QLabel; class MyTextEdit; +class QTableView; #define RESULTLINESCOUNT 10 @@ -73,6 +74,8 @@ QWidget* m_summaryResults{nullptr}; QLabel* m_resultLine[RESULTLINESCOUNT]; + QTableView* m_inputStatsTable; + QLabel* m_labelInputStatsTable; public slots: void createContextMenu(QMenu*); void fillToolBar(QToolBar*); diff --git a/src/kdefrontend/generalTest/GeneralTestView.cpp b/src/kdefrontend/generalTest/GeneralTestView.cpp --- a/src/kdefrontend/generalTest/GeneralTestView.cpp +++ b/src/kdefrontend/generalTest/GeneralTestView.cpp @@ -39,9 +39,8 @@ #include #include #include -//#include -#include -#include +#include +#include #include @@ -56,20 +55,34 @@ m_generalTest(GeneralTest), m_testName(new QLabel()), m_statsTable(new MyTextEdit()), - m_summaryResults(new QWidget()) { + m_summaryResults(new QWidget()), + m_inputStatsTable(new QTableView()), + m_labelInputStatsTable(new QLabel()) { m_statsTable->setReadOnly(true); m_testName->setStyleSheet("background-color: white"); m_statsTable->setStyleSheet("background-color: white"); m_summaryResults->setStyleSheet("QToolTip { color: black; background-color: yellow; border: 0px; }"); + m_inputStatsTable->setStyleSheet("background-color: white"); + m_labelInputStatsTable->setStyleSheet("backgroud-color: white"); m_testName->hide(); m_statsTable->hide(); m_summaryResults->hide(); + m_inputStatsTable->hide(); auto* layout = new QVBoxLayout(this); + m_labelInputStatsTable->setText("

" + i18n("Statistic Table")); + m_labelInputStatsTable->setToolTip(i18n("Fill this table with pre-calculated statistic value and then press recalculate") + + "

" + + i18n("You can leave one or more columns empty if you feel they are not useful") + + "hide(); + + layout->addWidget(m_labelInputStatsTable); + layout->addWidget(m_inputStatsTable); layout->addWidget(m_testName); layout->addWidget(m_statsTable); layout->addWidget(m_summaryResults); @@ -84,6 +97,13 @@ initActions(); initMenus(); + QHeaderView* horizontalHeaderView = m_inputStatsTable->horizontalHeader(); + horizontalHeaderView->setSectionResizeMode(QHeaderView::ResizeToContents); + horizontalHeaderView->setSectionsClickable(true); + horizontalHeaderView->setStyleSheet("backgroud-color: red"); + + m_inputStatsTable->setModel(m_generalTest->inputStatsTableModel()); + m_statsTable->setMouseTracking(true); connect(m_generalTest, &GeneralTest::changed, this, &GeneralTestView::changed); } @@ -165,6 +185,16 @@ } m_summaryResults->setLayout(m_generalTest->summaryLayout()); + + if (m_inputStatsTable->model()->rowCount() > 0 && + m_inputStatsTable->model()->columnCount() > 0) { + m_inputStatsTable->show(); + m_labelInputStatsTable->show(); + } + else { + m_inputStatsTable->hide(); + m_labelInputStatsTable->hide(); + } } void GeneralTestView::exportToFile(const QString& path, const bool exportHeader, const QString& separator, QLocale::Language language) const {