diff --git a/src/backend/hypothesis_test/HypothesisTest.h b/src/backend/hypothesis_test/HypothesisTest.h --- a/src/backend/hypothesis_test/HypothesisTest.h +++ b/src/backend/hypothesis_test/HypothesisTest.h @@ -36,9 +36,9 @@ class HypothesisTestPrivate; class HypothesisTestView; class Spreadsheet; -class QAbstractItemModel; class QString; class Column; +class QLayout; class HypothesisTest : public AbstractPart { Q_OBJECT @@ -48,17 +48,29 @@ ~HypothesisTest() override; enum DataSourceType {DataSourceSpreadsheet, DataSourceDatabase}; + enum TailType {TailPositive, TailNegative, TailTwo}; - QAbstractItemModel* dataModel(); - QAbstractItemModel *horizontalHeaderModel(); - QString testName(); + void setDataSourceType(DataSourceType type); + DataSourceType dataSourceType() const; void setDataSourceSpreadsheet(Spreadsheet* spreadsheet); + void setColumns(QVector cols); void setColumns(QStringList cols); - void performTwoSampleTTest(); - DataSourceType dataSourceType() const; - + QStringList allColumns(); + void setTailType(TailType tailType); + TailType tailType(); + void setPopulationMean(QVariant populationMean); + void setSignificanceLevel(QVariant alpha); + QString testName(); + QString statsTable(); + void performTwoSampleTTest(); + void performTwoSampleIndependentTTest(bool equal_variance); + void performTwoSamplePairedTTest(); + void PerformOneSampleTTest(); + void performTwoSampleIndependentZTest(); + void performTwoSamplePairedZTest(); + void PerformOneSampleZTest(); //virtual methods // QIcon icon() const override; QMenu* createContextMenu() override; @@ -72,10 +84,6 @@ bool load(XmlStreamReader*, bool preview) override; Spreadsheet* dataSourceSpreadsheet() const; - - void setDataSourceType(DataSourceType type); - QStringList allColumns(); - private: HypothesisTestPrivate* const d; mutable HypothesisTestView* m_view{nullptr}; diff --git a/src/backend/hypothesis_test/HypothesisTest.cpp b/src/backend/hypothesis_test/HypothesisTest.cpp --- a/src/backend/hypothesis_test/HypothesisTest.cpp +++ b/src/backend/hypothesis_test/HypothesisTest.cpp @@ -44,39 +44,32 @@ #include #include #include +#include +#include HypothesisTest::HypothesisTest(const QString &name) : AbstractPart(name), -d(new HypothesisTestPrivate(this)) { + d(new HypothesisTestPrivate(this)) { } HypothesisTest::~HypothesisTest() { delete d; } -QAbstractItemModel* HypothesisTest::dataModel() { - return d->dataModel; -} - -QAbstractItemModel* HypothesisTest::horizontalHeaderModel() { - return d->horizontalHeaderModel; -} - void HypothesisTest::setDataSourceType(DataSourceType type) { if (type != d->dataSourceType) { d->dataSourceType = type; } } +HypothesisTest::DataSourceType HypothesisTest::dataSourceType() const { + return d->dataSourceType; +} + void HypothesisTest::setDataSourceSpreadsheet(Spreadsheet *spreadsheet) { if (spreadsheet != d->dataSourceSpreadsheet) d->setDataSourceSpreadsheet(spreadsheet); } -QStringList HypothesisTest::allColumns() -{ - return d->all_columns; -} - void HypothesisTest::setColumns(QVector cols) { d->m_columns = cols; } @@ -85,25 +78,73 @@ return d->setColumns(cols); } -HypothesisTest::DataSourceType HypothesisTest::dataSourceType() const { - return d->dataSourceType; +QStringList HypothesisTest::allColumns() { + return d->all_columns; } -void HypothesisTest::performTwoSampleTTest() { - d->performTwoSampleTTest(); +void HypothesisTest::setTailType(HypothesisTest::TailType tailType) { + d->tail_type = tailType; } +HypothesisTest::TailType HypothesisTest::tailType() { + return d->tail_type; +} + +void HypothesisTest::setPopulationMean(QVariant populationMean) { + d->m_population_mean = populationMean.toDouble(); +} + +void HypothesisTest::setSignificanceLevel(QVariant alpha) { + d->m_significance_level = alpha.toDouble(); +} + + QString HypothesisTest::testName() { return d->m_currTestName; } +QString HypothesisTest::statsTable() { + return d->m_stats_table; +} + +void HypothesisTest::performTwoSampleIndependentTTest(bool equal_variance) { + d->m_currTestName = "

Two Sample Independent T Test

"; + d->performTwoSampleIndependentTest(HypothesisTestPrivate::TestT, equal_variance); +} + +void HypothesisTest::performTwoSamplePairedTTest() { + d->m_currTestName = "

Two Sample Paried T Test

"; + d->performTwoSamplePairedTest(HypothesisTestPrivate::TestT); +} + +void HypothesisTest::PerformOneSampleTTest() { + d->m_currTestName = "

One Sample T Test

"; + d->PerformOneSampleTest(HypothesisTestPrivate::TestT); +} + +void HypothesisTest::performTwoSampleIndependentZTest() { + d->m_currTestName = "

Two Sample Independent Z Test

"; + d->performTwoSampleIndependentTest(HypothesisTestPrivate::TestZ); +} + +void HypothesisTest::performTwoSamplePairedZTest() { + d->m_currTestName = "

Two Sample Paired Z Test

"; + d->performTwoSamplePairedTest(HypothesisTestPrivate::TestZ); +} + +void HypothesisTest::PerformOneSampleZTest() { + d->m_currTestName = "

One Sample Z Test

"; + d->PerformOneSampleTest(HypothesisTestPrivate::TestZ); +} + + + + /****************************************************************************** * Private Implementations * ****************************************************************************/ -HypothesisTestPrivate::HypothesisTestPrivate(HypothesisTest* owner) : q(owner) , - dataModel(new QStandardItemModel) , - horizontalHeaderModel(new QStandardItemModel) { +HypothesisTestPrivate::HypothesisTestPrivate(HypothesisTest* owner) : q(owner) { } HypothesisTestPrivate::~HypothesisTestPrivate() { @@ -126,103 +167,284 @@ m_columns.clear(); Column* column = new Column("column"); for (QString col : cols) { - if (col != "") { + if (!cols.isEmpty()) { column = dataSourceSpreadsheet->column(col); -// qDebug() << "col is " << col; m_columns.append(column); } } } -void HypothesisTestPrivate::performTwoSampleTTest() { - dataModel->clear(); - horizontalHeaderModel->clear(); - m_currTestName = i18n("Independent Two Sample T Test"); - DEBUG("performing two sample test :DEBUG MACRO"); - qDebug() << "performing two sample test: qDebug()"; +/**************************Two Sample Independent *************************************/ + +void HypothesisTestPrivate::performTwoSampleIndependentTest(TestType test, bool equal_variance) { + QString test_name; + + double value; + int df = 0; + double p_value = 0; + clearGlobalVariables(); - QMessageBox* msg_box = new QMessageBox(); - // checking for cols; if (m_columns.size() != 2) { - msg_box->setText(i18n("Inappropriate number of columns selected")); - msg_box->exec(); + printError("Inappropriate number of columns selected"); + emit q->changed(); + return; + } + + int n[2]; + double sum[2], mean[2], std[2]; + + QString col1_name = m_columns[0]->name(); + QString col2_name = m_columns[1]->name(); + + if (m_columns[0]->columnMode() == AbstractColumn::Integer || m_columns[0]->columnMode() == AbstractColumn::Numeric) { + for (int i = 0; i < 2; i++) { + findStats(m_columns[i], n[i], sum[i], mean[i], std[i]); + + if (n[i] < 1) { + printError("At least one of selected column is empty"); + emit q->changed(); + return; + } + } + } else { + ErrorType error_code = findStatsCategorical(m_columns[0], m_columns[1], n, sum, mean, std, col1_name, col2_name); + switch (error_code) { + case ErrorUnqualSize: { + printError( i18n("Unequal size between Column %1 and Column %2", m_columns[0]->name(), m_columns[1]->name())); + emit q->changed(); + return; + } case ErrorNotTwoCategoricalVariables: { + printError( i18n("Number of Categorical Variable in Column %1 is not equal to 2", m_columns[0]->name())); + emit q->changed(); + return; + } case ErrorEmptyColumn: { + printError("At least one of selected column is empty"); + emit q->changed(); + return; + } case NoError: + break; + } + } + + QVariant row_major[] = {"", "N", "Sum", "Mean", "Std", + col1_name, n[0], sum[0], mean[0], std[0], + col2_name, n[1], sum[1], mean[1], std[1]}; + + m_stats_table = getHtmlTable(3, 5, row_major); + + switch (test) { + case TestT: { + test_name = "T"; + + if (equal_variance) { + df = n[0] + n[1] - 2; + double sp = qSqrt( ((n[0]-1)*qPow(std[0],2) + (n[1]-1)*qPow(std[1],2))/df); + value = (mean[0] - mean[1])/(sp*qSqrt(1.0/n[0] + 1.0/n[1])); + printLine(9, "Assumption: Equal Variance b/w both population means"); + } else { + double temp_val; + temp_val = qPow( qPow(std[0], 2)/n[0] + qPow(std[1], 2)/n[1], 2); + temp_val = temp_val / ( (qPow( (qPow(std[0], 2)/n[0]), 2)/(n[0]-1)) + (qPow( (qPow(std[1], 2)/n[1]), 2)/(n[1]-1))); + df = qRound(temp_val); + + value = (mean[0] - mean[1]) / (qSqrt( (qPow(std[0], 2)/n[0]) + (qPow(std[1], 2)/n[1]))); + printLine(9, "Assumption: UnEqual Variance b/w both population means"); + } + break; + } case TestZ: { + test_name = "Z"; + df = n[0] + n[1] - 2; + + double sp = qSqrt( ((n[0]-1)*qPow(std[0],2) + (n[1]-1)*qPow(std[1],2))/df); + value = (mean[0] - mean[1])/(sp*qSqrt(1.0/n[0] + 1.0/n[1])); + } + } + + m_currTestName = i18n("

Two Sample Independent %1 Test for %2 vs %3

", test_name, col1_name, col2_name); + p_value = getPValue(test, value, col1_name, col2_name, df); + + printLine(2, i18n("Significance level is %1", m_significance_level), "blue"); + printLine(4, i18n("%1 Value is %2 ", test_name, value), "green"); + printLine(5, i18n("P Value is %1 ", p_value), "green"); + printLine(6, i18n("Degree of Freedom is %1", df), "green"); + + if (p_value <= m_significance_level) + q->m_view->setResultLine(5, i18n("We can safely reject Null Hypothesis for significance level %1", m_significance_level), Qt::ToolTipRole); + else + q->m_view->setResultLine(5, i18n("There is a plausibility for Null Hypothesis to be true"), Qt::ToolTipRole); + + emit q->changed(); + return; +} + +/********************************Two Sample Paired ***************************************/ + +void HypothesisTestPrivate::performTwoSamplePairedTest(TestType test) { + QString test_name; + int n; + double sum, mean, std; + double value; + int df = 0; + double p_value = 0; + clearGlobalVariables(); + + if (m_columns.size() != 2) { + printError("Inappropriate number of columns selected"); + emit q->changed(); return; } - bool modeOk = true; - bool allColumnsValid = true; for (int i = 0; i < 2; i++) { - if(m_columns[i]->columnMode() == AbstractColumn::Numeric || m_columns[i]->columnMode() == AbstractColumn::Integer) - continue; - modeOk = false; + if (!(m_columns[i]->columnMode() == AbstractColumn::Numeric || m_columns[i]->columnMode() == AbstractColumn::Integer)) { + printError("select only columns with numbers"); + emit q->changed(); + return; + } } - if(!allColumnsValid) { - msg_box->setText(i18n("one of the selected columns is invalid")); - msg_box->exec(); + ErrorType error_code = findStatsPaired(m_columns[0], m_columns[1], n, sum, mean, std); + + switch (error_code) { + case ErrorUnqualSize: { + printError("both columns are having different sizes"); + emit q->changed(); + return; + } case ErrorEmptyColumn: { + printError("columns are empty"); + emit q->changed(); + return; + } case NoError: + break; + default: + emit q->changed(); + return; + } + + if (n == -1) { + printError("both columns are having different sizes"); + emit q->changed(); return; } - if (!modeOk) { - msg_box->setText(i18n("select only columns with numbers")); - msg_box->exec(); + if (n < 1) { + printError("columns are empty"); + emit q->changed(); return; } - dataModel->setRowCount(1); - dataModel->setColumnCount(3); + QVariant row_major[] = {"", "N", "Sum", "Mean", "Std", + "difference", n, sum, mean, std}; + + m_stats_table = getHtmlTable(2, 5, row_major); + + switch (test) { + case TestT: { + value = mean / (std/qSqrt(n)); + df = n - 1; + test_name = "T"; + printLine(6, i18n("Degree of Freedom is %1name(), i18n("%1",m_population_mean), df); + m_currTestName = i18n("

One Sample %1 Test for %2 vs %3

", test_name, m_columns[0]->name(), m_columns[1]->name()); + + printLine(2, i18n("Significance level is %1 ", m_significance_level), "blue"); + printLine(4, i18n("%1 Value is %2 ", test_name, value), "green"); + printLine(5, i18n("P Value is %1 ", p_value), "green"); + + if (p_value <= m_significance_level) + q->m_view->setResultLine(5, i18n("We can safely reject Null Hypothesis for significance level %1", m_significance_level), Qt::ToolTipRole); + else + q->m_view->setResultLine(5, i18n("There is a plausibility for Null Hypothesis to be true"), Qt::ToolTipRole); - horizontalHeaderModel->setColumnCount(3); + emit q->changed(); + return; - int n[2]; - double sum[2], mean[2], std[2]; +} - for (int i = 0; i < 2; i++) { - findStats(m_columns[i], n[i], sum[i], mean[i], std[i]); - DEBUG( "for " << i); - DEBUG( "n is " << n[i]); - DEBUG( "mean is " << mean[i]); - DEBUG( "std is " << std[i]); - - if (n[i] < 1) { - msg_box->setText(i18n("atleast one of selected column is empty")); - msg_box->exec(); - return; - } +/******************************** One Sample ***************************************/ + +void HypothesisTestPrivate::PerformOneSampleTest(TestType test) { + QString test_name; + double value; + int df = 0; + double p_value = 0; + clearGlobalVariables(); + + if (m_columns.size() != 1) { + printError("Inappropriate number of columns selected"); + emit q->changed(); + return; + } + + if ( !(m_columns[0]->columnMode() == AbstractColumn::Numeric || m_columns[0]->columnMode() == AbstractColumn::Integer)) { + printError("select only columns with numbers"); + emit q->changed(); + return; } - int df = n[0] + n[1] - 2; - //Assuming equal variance - double sp = qSqrt( ((n[0]-1)*qPow(std[0],2) + (n[1]-1)*qPow(std[1],2))/df); + int n; + double sum, mean, std; + ErrorType error_code = findStats(m_columns[0], n, sum, mean, std); - QDEBUG("sp is " << sp); + switch (error_code) { + case ErrorUnqualSize: { + printError("column is empty"); + emit q->changed(); + return; + } case NoError: + break; + default: { + emit q->changed(); + return; + } + } - double t = (mean[0] - mean[1])/(sp*qSqrt(1.0/n[0] + 1.0/n[1])); + QVariant row_major[] = {"", "N", "Sum", "Mean", "Std", + m_columns[0]->name(), n, sum, mean, std}; - // now finding p value from t value - double p_value = nsl_stats_tdist_p(t, df); + m_stats_table = getHtmlTable(2, 5, row_major); -// QString text = i18n("T value for test is %1 and\n p value is %2",t, p_value); -// msg_box->setText(text); -// msg_box->exec(); + switch (test) { + case TestT: { + test_name = "T"; + value = (mean - m_population_mean) / (std/qSqrt(n)); + df = n - 1; + printLine(6, i18n("Degree of Freedom is %1", df), "blue"); + break; + } case TestZ: { + test_name = "Z"; + df = 0; + value = (mean - m_population_mean) / (std/qSqrt(n)); + }} - //setting dataModel - dataModel->setItem(0, 0, new QStandardItem(QString::number(t))); - dataModel->setItem(0, 1, new QStandardItem(QString::number(df))); - dataModel->setItem(0, 2, new QStandardItem(QString::number(p_value))); + p_value = getPValue(test, value, m_columns[0]->name(), i18n("%1",m_population_mean), df); + m_currTestName = i18n("

One Sample %1 Test for %2

", test_name, m_columns[0]->name()); + printLine(2, i18n("Significance level is %1", m_significance_level), "blue"); + printLine(4, i18n("%1 Value is %2", test_name, value), "green"); + printLine(5, i18n("P Value is %1", p_value), "green"); - //setting horizontal header model - horizontalHeaderModel->setHeaderData(0, Qt::Horizontal, "t value"); - horizontalHeaderModel->setHeaderData(1, Qt::Horizontal, "dof"); - horizontalHeaderModel->setHeaderData(2, Qt::Horizontal, "p value"); + if (p_value <= m_significance_level) + q->m_view->setResultLine(5, i18n("We can safely reject Null Hypothesis for significance level %1", m_significance_level), Qt::ToolTipRole); + else + q->m_view->setResultLine(5, i18n("There is a plausibility for Null Hypothesis to be true"), Qt::ToolTipRole); emit q->changed(); return; + } -void HypothesisTestPrivate::findStats(Column* column, int &count, double &sum, double &mean, double &std) { +/***************************************Helper Functions*************************************/ + +HypothesisTestPrivate::ErrorType HypothesisTestPrivate::findStats(const Column* column, int &count, double &sum, double &mean, double &std) { sum = 0; mean = 0; std = 0; @@ -237,7 +459,7 @@ sum += row; } - if (count < 1) return; + if (count < 1) return HypothesisTestPrivate::ErrorEmptyColumn; mean = sum/count; for (int i = 0; i < count; i++) { @@ -248,9 +470,253 @@ if (count > 1) std = std / (count-1); std = qSqrt(std); + + return HypothesisTestPrivate::NoError; +} + +HypothesisTestPrivate::ErrorType HypothesisTestPrivate::findStatsPaired(const Column* column1, const Column* column2, int &count, double &sum, double &mean, double &std) { + sum = 0; + mean = 0; + std = 0; + + int count1 = column1->rowCount(); + int count2 = column2->rowCount(); + + count = qMin(count1, count2); + double cell1, cell2; + for (int i = 0; i < count; i++) { + cell1 = column1->valueAt(i); + cell2 = column2->valueAt(i); + + if (std::isnan(cell1) || std::isnan(cell2)) { + if (std::isnan(cell1) && std::isnan(cell2)) + count = i; + else + return HypothesisTestPrivate::ErrorUnqualSize; + break; + } + + sum += cell1 - cell2; + } + + if (count < 1) + return HypothesisTestPrivate::ErrorEmptyColumn; + + mean = sum/count; + + double row; + for (int i = 0; i < count; i++) { + cell1 = column1->valueAt(i); + cell2 = column2->valueAt(i); + row = cell1 - cell2; + std += qPow( (row - mean), 2); + } + + if (count > 1) + std = std / (count-1); + + std = qSqrt(std); + return HypothesisTestPrivate::NoError; +} + +HypothesisTestPrivate::ErrorType HypothesisTestPrivate::findStatsCategorical(const Column *column1, const Column *column2, int n[], double sum[], double mean[], double std[], QString &col1_name, QString &col2_name) { + // clearing and initialising variables; + + const Column* columns[] = {column1, column2}; + + for (int i = 0; i < 2; i++) { + sum[i] = 0; + mean[i] = 0; + std[i] = 0; + n[i] = 0; + } + + int count_temp = columns[0]->rowCount(); + col1_name = ""; + col2_name = ""; + for (int i = 0; i < count_temp; i++) { + QString name = columns[0]->textAt(i); + double value = columns[1]->valueAt(i); + + if (name.isEmpty() || std::isnan(value)) { + if (name.isEmpty() && std::isnan(value)) + break; + else + return HypothesisTestPrivate::ErrorUnqualSize; + } + + if (name == col1_name) { + n[0]++; + sum[0] += value; + } else if (name == col2_name) { + n[1]++; + sum[1] += value; + } else if (col1_name.isEmpty()) { + n[0]++; + sum[0] += value; + col1_name = name; + } else if (col2_name.isEmpty()) { + n[1]++; + sum[1] += value; + col2_name = name; + } + else + return HypothesisTestPrivate::ErrorNotTwoCategoricalVariables; + } + + if (col1_name.isEmpty() || col2_name.isEmpty()) + return HypothesisTestPrivate::ErrorNotTwoCategoricalVariables; + + + mean[0] = sum[0]/n[0]; + mean[1] = sum[1]/n[1]; + + + for (int i = 0; i < n[0]+n[1]; i++) { + QString name = columns[0]->textAt(i); + double value = columns[1]->valueAt(i); + + if (name == col1_name) + std[0] += qPow( (value - mean[0]), 2); + else + std[1] += qPow( (value - mean[1]), 2); + } + + for (int i = 0; i < 2; i++) { + if (n[i] > 1) + std[i] = std[i] / (n[i] - 1); + std[i] = qSqrt(std[i]); + } + + return HypothesisTestPrivate::NoError; +} + + +double HypothesisTestPrivate::getPValue(const HypothesisTestPrivate::TestType &test, double &value, const QString &col1_name, const QString &col2_name, const int df) { + double p_value = 0; + + //TODO change ("⋖") symbol to ("<"), currently macro UTF8_QSTRING is not working properly if used "<" symbol; + switch (test) { + case TestT: { + switch (tail_type) { + case HypothesisTest::TailNegative: + p_value = nsl_stats_tdist_p(value, df); + printLine(0, i18n("Null Hypothesis: Population mean of %1 %2 Population mean of %3", col1_name, UTF8_QSTRING("≥"), col2_name), "blue"); + printLine(1, i18n("Alternate Hypothesis: Population mean of %1 %2 Population mean of %3", col1_name, UTF8_QSTRING("⋖"), col2_name), "blue"); + break; + case HypothesisTest::TailPositive: + value *= -1; + p_value = nsl_stats_tdist_p(value, df); + printLine(0, i18n("Null Hypothesis: Population mean of %1 %2 Population mean of %3", col1_name, UTF8_QSTRING("≤"), col2_name), "blue"); + printLine(1, i18n("Alternate Hypothesis: Population mean of %1 %2 Population mean of %3", col1_name, UTF8_QSTRING(">"), col2_name), "blue"); + break; + case HypothesisTest::TailTwo: + p_value = nsl_stats_tdist_p(value, df) + nsl_stats_tdist_p(-1*value, df); + + printLine(0, i18n("Null Hypothesis: Population mean of %1 %2 Population mean of %3", col1_name, UTF8_QSTRING("="), col2_name), "blue"); + printLine(1, i18n("Alternate Hypothesis: Population mean of %1 %2 Population mean of %3", col1_name, UTF8_QSTRING("≠"), col2_name), "blue"); + break; + } + break; + } case TestZ: { + switch (tail_type) { + case HypothesisTest::TailNegative: + p_value = nsl_stats_tdist_p(value, df); + printLine(0, i18n("Null Hypothesis: Population mean of %1 %2 Population mean of %3 ", col1_name, UTF8_QSTRING("≥"), col2_name), "blue"); + printLine(1, i18n("Alternate Hypothesis: Population mean of %1 %2 Population mean of %3 ", col1_name, UTF8_QSTRING("⋖"), col2_name), "blue"); + break; + case HypothesisTest::TailPositive: + value *= -1; + p_value = nsl_stats_tdist_p(value, df); + printLine(0, i18n("Null Hypothesis: Population mean of %1 %2 Population mean of %3 ", col1_name, UTF8_QSTRING("≤"), col2_name), "blue"); + printLine(1, i18n("Alternate Hypothesis: Population mean of %1 %2 Population mean of %3 ", col1_name, UTF8_QSTRING(">"), col2_name), "blue"); + break; + case HypothesisTest::TailTwo: + p_value = nsl_stats_tdist_p(value, df) + nsl_stats_tdist_p(-1*value, df); + + printLine(0, i18n("Null Hypothesis: Population mean of %1 %2 Population mean of %3 ", col1_name, UTF8_QSTRING("="), col2_name), "blue"); + printLine(1, i18n("Alternate Hypothesis: Population mean of %1 %2 Population mean of %3 ", col1_name, UTF8_QSTRING("≠"), col2_name), "blue"); + break; + } + break; + } + } + + if (p_value > 1) + return 1; + return p_value; +} + +QString HypothesisTestPrivate::getHtmlTable(int row, int column, QVariant *row_major) { + if (row < 1 || column < 1) + return QString(); + + QString table = ""; + table = "" + "" + " "; + + QString bg = "tg-0pky"; + bool pky = true; + + QString element; + table += " "; + for (int j = 0; j < column; j++) { + element = row_major[j].toString(); + table += i18n(" ", bg, element); + } + table += " "; + + if (pky) + bg = "tg-0pky"; + else + bg = "tg-btxf"; + pky = !pky; + + for (int i = 1; i < row; i++) { + table += " "; + + QString element = row_major[i*column].toString(); + table += i18n(" ", bg, element); + for (int j = 1; j < column; j++) { + QString element = row_major[i*column+j].toString(); + table += i18n(" ", bg, element); + } + + table += " "; + if (pky) + bg = "tg-0pky"; + else + bg = "tg-btxf"; + pky = !pky; + } + table += "
%2
%2%2
"; + + return table; +} + + +void HypothesisTestPrivate::printLine(const int &index, const QString &msg, const QString &color) { + q->m_view->setResultLine(index, i18n("

%2

", color, msg)); return; } +void HypothesisTestPrivate::printError(const QString &error_msg) { + printLine(0, error_msg, "red"); + emit q->changed(); +} + + +void HypothesisTestPrivate::clearGlobalVariables() { + m_stats_table = ""; + q->m_view->clearResult(); +} /********************************************************************************** * virtual functions implementations @@ -315,7 +781,7 @@ */ QMenu* HypothesisTest::createContextMenu() { QMenu* menu = AbstractPart::createContextMenu(); -// Q_ASSERT(menu); -// emit requestProjectContextMenu(menu); + // Q_ASSERT(menu); + // emit requestProjectContextMenu(menu); return menu; } diff --git a/src/backend/hypothesis_test/HypothesisTestPrivate.h b/src/backend/hypothesis_test/HypothesisTestPrivate.h --- a/src/backend/hypothesis_test/HypothesisTestPrivate.h +++ b/src/backend/hypothesis_test/HypothesisTestPrivate.h @@ -35,34 +35,47 @@ class HypothesisTestPrivate { public: + explicit HypothesisTestPrivate(HypothesisTest*); virtual ~HypothesisTestPrivate(); + enum TestType {TestT, TestZ}; + enum ErrorType {ErrorUnqualSize, ErrorNotTwoCategoricalVariables, ErrorEmptyColumn, NoError}; + QString name() const; + void setDataSourceSpreadsheet(Spreadsheet* spreadsheet); + void setColumns(QStringList cols); + void performTwoSampleIndependentTest(TestType test, bool equal_variance = true); + void performTwoSamplePairedTest(TestType test); + void PerformOneSampleTest(TestType test); - HypothesisTest* const q; + HypothesisTest* const q; HypothesisTest::DataSourceType dataSourceType{HypothesisTest::DataSourceSpreadsheet}; Spreadsheet* dataSourceSpreadsheet{nullptr}; - - void setDataSourceSpreadsheet(Spreadsheet* spreadsheet); - void setColumns(QStringList cols); QVector m_columns; - QStringList all_columns; - QStandardItemModel* dataModel{nullptr}; - QStandardItemModel* horizontalHeaderModel{nullptr}; - bool m_dbCreated{false}; int m_rowCount{0}; int m_columnCount{0}; QString m_currTestName{"Result Table"}; - - void performTwoSampleTTest(); + double m_population_mean; + double m_significance_level; + QString m_stats_table; + HypothesisTest::TailType tail_type; private: - void findStats(Column* column, int &count, double &sum, double &mean, double &std); -// QMap m_members; + ErrorType findStats(const Column* column,int &count, double &sum, double &mean, double &std); + ErrorType findStatsPaired(const Column *column1, const Column *column2, int &count, double &sum, double &mean, double &std); + ErrorType findStatsCategorical(const Column *column1, const Column *column2, int n[2], double sum[2], double mean[2], double std[2], QString &col1_name, QString &col2_name); + + double getPValue(const TestType &test, double &value, const QString &col1_name, const QString &col2_name, const int df); + QString getHtmlTable(int row, int column, QVariant *row_major); + + void printLine(const int &index, const QString &msg, const QString &color = "black"); + void printError(const QString &error_msg); + void clearGlobalVariables(); + }; #endif 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 @@ -38,6 +38,7 @@ class HypothesisTest; class TreeViewComboBox; class KConfig; +class QScrollArea; class HypothesisTestDock : public QWidget { Q_OBJECT @@ -46,6 +47,11 @@ explicit HypothesisTestDock(QWidget*); void setHypothesisTest(HypothesisTest*); +private slots: + void onRbH1OneTail1Toggled(bool checked); + void onRbH1OneTail2Toggled(bool checked); + void onRbH1TwoTailToggled(bool checked); + private slots: private: @@ -56,21 +62,31 @@ //// AspectTreeModel* m_aspectTreeModel{nullptr}; QSqlDatabase m_db; QString m_configPath; - + double population_mean{0}; + double significance_level{0.05}; // void load(); // void loadConfig(KConfig&); // void setModelIndexFromAspect(TreeViewComboBox*, const AbstractAspect*); // void readConnections(); // void updateFields(); // bool fieldSelected(const QString&); + bool ttest{false}; + bool ztest{false}; + bool two_sample_independent{false}; + bool two_sample_paired{false}; + bool one_sample{false}; + QScrollArea* scroll_dock; + private slots: //SLOTs for changes triggered in PivotTableDock // void nameChanged(); // void commentChanged(); void dataSourceTypeChanged(int); - void doTTest(); + void doHypothesisTest(); + void showHypothesisTest(); void spreadsheetChanged(const QModelIndex&); + void col1CatIndexChanged(int index); // void connectionChanged(); // void tableChanged(); // void showDatabaseManager(); 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 @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -50,6 +51,8 @@ \ingroup kdefrontend */ +//TOOD: Make this dock widget scrollable and automatic resizeable for different screens. + HypothesisTestDock::HypothesisTestDock(QWidget* parent) : QWidget(parent) { ui.setupUi(this); @@ -57,12 +60,74 @@ ui.cbDataSourceType->addItem(i18n("Database")); cbSpreadsheet = new TreeViewComboBox; - ui.gridLayout->addWidget(cbSpreadsheet, 5, 3, 1, 4); + ui.gridLayout->addWidget(cbSpreadsheet, 1, 1); ui.bDatabaseManager->setIcon(QIcon::fromTheme("network-server-database")); ui.bDatabaseManager->setToolTip(i18n("Manage connections")); m_configPath = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).constFirst() + "sql_connections"; -// readConnections(); + + + + + // adding item to tests and testtype combo box; + ui.cbTest->addItem(i18n("T Test")); + ui.cbTest->addItem(i18n("Z Test")); + + ui.cbTestType->addItem(i18n("Two Sample Independent")); + ui.cbTestType->addItem(i18n("Two Sample Paired")); + ui.cbTestType->addItem(i18n("One Sample")); + + // making all test blocks invisible at starting. + ui.lCol1Categorical->setVisible(false); + ui.cbCol1Categorical->setVisible(false); + ui.lCol1->setVisible(false); + ui.cbCol1->setVisible(false); + ui.lCol2->setVisible(false); + ui.cbCol2->setVisible(false); + ui.chbEqualVariance->setVisible(false); + ui.chbEqualVariance->setChecked(true); + ui.pbPerformTest->setEnabled(false); + ui.rbH1OneTail2->setVisible(false); + ui.rbH1OneTail1->setVisible(false); + ui.rbH1TwoTail->setVisible(false); + ui.rbH0OneTail1->setVisible(false); + ui.rbH0OneTail2->setVisible(false); + ui.rbH0TwoTail->setVisible(false); + ui.lH0->setVisible(false); + ui.lH1->setVisible(false); + + QString mu = UTF8_QSTRING("μ"); + QString mu0 = UTF8_QSTRING("μₒ"); + + // radio button for null and alternate hypothesis + // for alternative hypothesis (h1) + // one_tail_1 is mu > mu0; one_tail_2 is mu < mu0; two_tail = mu != mu0; + + ui.rbH1OneTail1->setText( i18n("%1 %2 %3", mu, UTF8_QSTRING(">"), mu0)); + ui.rbH1OneTail2->setText( i18n("%1 %2 %3", mu, UTF8_QSTRING("<"), mu0)); + ui.rbH1TwoTail->setText( i18n("%1 %2 %3", mu, UTF8_QSTRING("≠"), mu0)); + + ui.rbH0OneTail1->setText( i18n("%1 %2 %3",mu, UTF8_QSTRING("≤"), mu0)); + ui.rbH0OneTail2->setText( i18n("%1 %2 %3", mu, UTF8_QSTRING("≥"), mu0)); + ui.rbH0TwoTail->setText( i18n("%1 %2 %3", mu, UTF8_QSTRING("="), mu0)); + + ui.rbH0TwoTail->setEnabled(false); + ui.rbH0OneTail1->setEnabled(false); + ui.rbH0OneTail2->setEnabled(false); + + + // setting muo and alpha buttons + ui.lMuo->setText( i18n("%1", mu0)); + ui.lAlpha->setText( i18n("%1", UTF8_QSTRING("α"))); + ui.leMuo->setText( i18n("%1", population_mean)); + ui.leAlpha->setText( i18n("%1", significance_level)); + + ui.lMuo->setVisible(false); + ui.lAlpha->setVisible(false); + ui.leMuo->setVisible(false); + ui.leAlpha->setVisible(false); + + // readConnections(); // auto* style = ui.bAddRow->style(); // ui.bAddRow->setIcon(style->standardIcon(QStyle::SP_ArrowRight)); @@ -117,7 +182,18 @@ // ui.bRemoveColumn->setEnabled(!ui.lwColumns->selectedItems().isEmpty()); // }); - connect(ui.pbPerformTest, &QPushButton::clicked, this, &HypothesisTestDock::doTTest); + connect(ui.cbTest, static_cast(&QComboBox::activated), this, &HypothesisTestDock::showHypothesisTest); + connect(ui.cbTestType, static_cast(&QComboBox::activated), this, &HypothesisTestDock::showHypothesisTest); +// connect(ui.cbTest, static_cast(&QComboBox::currentIndexChanged), this, &HypothesisTestDock::showHypothesisTest); +// connect(ui.cbTestType, static_cast(&QComboBox::currentIndexChanged), this, &HypothesisTestDock::showHypothesisTest); + connect(ui.pbPerformTest, &QPushButton::clicked, this, &HypothesisTestDock::doHypothesisTest); + + //connecting null hypothesis and alternate hypothesis radio button + connect(ui.rbH1OneTail1, &QRadioButton::toggled, this, &HypothesisTestDock::onRbH1OneTail1Toggled); + connect(ui.rbH1OneTail2, &QRadioButton::toggled, this, &HypothesisTestDock::onRbH1OneTail2Toggled); + connect(ui.rbH1TwoTail, &QRadioButton::toggled, this, &HypothesisTestDock::onRbH1TwoTailToggled); + + connect(ui.cbCol1Categorical, QOverload::of(&QComboBox::currentIndexChanged), this, &HypothesisTestDock::col1CatIndexChanged); } void HypothesisTestDock::setHypothesisTest(HypothesisTest* HypothesisTest) { @@ -145,13 +221,16 @@ // else // ui.cbConnection->setCurrentIndex(ui.cbConnection->findText(m_hypothesisTest->dataSourceConnection())); - //clearing all cbCol* ui.cbCol1->clear(); ui.cbCol2->clear(); + ui.cbCol1Categorical->clear(); for (auto* col : m_hypothesisTest->dataSourceSpreadsheet()->children()) { - ui.cbCol1->addItem(col->name()); - ui.cbCol2->addItem(col->name()); + ui.cbCol1Categorical->addItem(col->name()); + if (col->columnMode() == AbstractColumn::Integer || col->columnMode() == AbstractColumn::Numeric) { + ui.cbCol2->addItem(col->name()); + ui.cbCol1->addItem(col->name()); + } } this->dataSourceTypeChanged(ui.cbDataSourceType->currentIndex()); @@ -174,12 +253,90 @@ // m_initializing = false; } -void HypothesisTestDock::doTTest() { +void HypothesisTestDock::showHypothesisTest() { + ttest = ui.cbTest->currentText() == "T Test"; + ztest = ui.cbTest->currentText() == "Z Test"; + + two_sample_independent = ui.cbTestType->currentText() == "Two Sample Independent"; + two_sample_paired = ui.cbTestType->currentText() == "Two Sample Paired"; + one_sample = ui.cbTestType->currentText() == "One Sample"; + + ui.lCol1Categorical->setVisible(two_sample_independent); + ui.cbCol1Categorical->setVisible(two_sample_independent); + ui.lCol1->setVisible(two_sample_paired); + ui.cbCol1->setVisible(two_sample_paired); + ui.lCol2->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.cbCol2->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.chbEqualVariance->setVisible(ttest && two_sample_independent); + ui.chbEqualVariance->setChecked(true); + ui.pbPerformTest->setEnabled(two_sample_independent || two_sample_paired || one_sample); + + ui.rbH1OneTail2->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.rbH1OneTail1->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.rbH1TwoTail->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.rbH0OneTail1->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.rbH0OneTail2->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.rbH0TwoTail->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.lH0->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.lH1->setVisible(two_sample_independent || two_sample_paired || one_sample); + + ui.rbH1TwoTail->setChecked(true); + + ui.lMuo->setVisible(one_sample); + ui.leMuo->setVisible(one_sample); + ui.lAlpha->setVisible(two_sample_independent || two_sample_paired || one_sample); + ui.leAlpha->setVisible(two_sample_independent || two_sample_paired || one_sample); + + ui.leMuo->setText( i18n("%1", population_mean)); + ui.leAlpha->setText( i18n("%1", significance_level)); + + if (two_sample_independent) + ui.lCol2->setText( i18n("Independent Variable")); +} + +void HypothesisTestDock::doHypothesisTest() { + + m_hypothesisTest->setPopulationMean(ui.leMuo->text()); + m_hypothesisTest->setSignificanceLevel(ui.leAlpha->text()); + QStringList cols; - cols << ui.cbCol1->currentText(); - cols << ui.cbCol2->currentText(); - m_hypothesisTest->setColumns(cols); - m_hypothesisTest->performTwoSampleTTest(); + if(ttest) { + if(two_sample_independent) { + cols << ui.cbCol1Categorical->currentText() << ui.cbCol2->currentText(); + m_hypothesisTest->setColumns(cols); + m_hypothesisTest->performTwoSampleIndependentTTest( ui.chbEqualVariance->isChecked()); + } + else if(two_sample_paired) { + cols << ui.cbCol1->currentText(); + cols << ui.cbCol2->currentText(); + m_hypothesisTest->setColumns(cols); + m_hypothesisTest->performTwoSamplePairedTTest(); + } + else if(one_sample){ + cols << ui.cbCol1->currentText(); + m_hypothesisTest->setColumns(cols); + m_hypothesisTest->PerformOneSampleTTest(); + } + } + else if(ztest) { + if(two_sample_independent) { + cols << ui.cbCol1Categorical->currentText(); + cols << ui.cbCol2->currentText(); + m_hypothesisTest->setColumns(cols); + m_hypothesisTest->performTwoSampleIndependentZTest(); + } + else if(two_sample_paired) { + cols << ui.cbCol1->currentText(); + cols << ui.cbCol2->currentText(); + m_hypothesisTest->setColumns(cols); + m_hypothesisTest->performTwoSamplePairedZTest(); + } + else if(one_sample){ + cols << ui.cbCol1->currentText(); + m_hypothesisTest->setColumns(cols); + m_hypothesisTest->PerformOneSampleZTest(); + } + } } //void HypothesisTestDock::setModelIndexFromAspect(TreeViewComboBox* cb, const AbstractAspect* aspect) { @@ -333,20 +490,42 @@ Spreadsheet* spreadsheet = dynamic_cast(aspect); //clear the previous definitions of combo-box columns + //clearing all cbCol* ui.cbCol1->clear(); ui.cbCol2->clear(); - //TODO: - //rows, columns, values - - //show all spreadsheet columns as available dimensions - for (const auto* col : spreadsheet->children()) { - ui.cbCol1->addItem(col->name()); - ui.cbCol2->addItem(col->name()); + ui.cbCol1Categorical->clear(); + for (auto* col : m_hypothesisTest->dataSourceSpreadsheet()->children()) { + ui.cbCol1Categorical->addItem(col->name()); + if (col->columnMode() == AbstractColumn::Integer || col->columnMode() == AbstractColumn::Numeric) { + ui.cbCol2->addItem(col->name()); + ui.cbCol1->addItem(col->name()); + } } m_hypothesisTest->setDataSourceSpreadsheet(spreadsheet); } +// currently no need of this slot +void HypothesisTestDock::col1CatIndexChanged(int index) { + if (index < 0) return; + + if (two_sample_paired) { + ui.lCol2->setText( i18n("Independent Variable")); + return; + } + + QString selected_text = ui.cbCol1Categorical->currentText(); + Column* col1 = m_hypothesisTest->dataSourceSpreadsheet()->column(selected_text); + + if (col1->columnMode() == AbstractColumn::Integer || col1->columnMode() == AbstractColumn::Numeric) { + ui.lCol2->setText( i18n("Independent Variable")); + } + else { + ui.lCol2->setText( i18n("Dependent Variable")); + } + +} + //void HypothesisTestDock::connectionChanged() { // if (ui.cbConnection->currentIndex() == -1) { @@ -478,3 +657,24 @@ // Q_UNUSED(config); //} +//TODO: Rather than inbuilt slots use own decided slots for checked rather than clicked + +// for alternate hypothesis +// one_tail_1 is mu > mu0; one_tail_2 is mu < mu0; two_tail = mu != mu0; +void HypothesisTestDock::onRbH1OneTail1Toggled(bool checked) { + if (!checked) return; + ui.rbH0OneTail1->setChecked(true); + m_hypothesisTest->setTailType(HypothesisTest::TailPositive); +} + +void HypothesisTestDock::onRbH1OneTail2Toggled(bool checked) { + if (!checked) return; + ui.rbH0OneTail2->setChecked(true); + m_hypothesisTest->setTailType(HypothesisTest::TailNegative); +} + +void HypothesisTestDock::onRbH1TwoTailToggled(bool checked) { + if (!checked) return; + ui.rbH0TwoTail->setChecked(true); + m_hypothesisTest->setTailType(HypothesisTest::TailTwo); +} diff --git a/src/kdefrontend/hypothesis_test/HypothesisTestView.h b/src/kdefrontend/hypothesis_test/HypothesisTestView.h --- a/src/kdefrontend/hypothesis_test/HypothesisTestView.h +++ b/src/kdefrontend/hypothesis_test/HypothesisTestView.h @@ -40,6 +40,7 @@ class AbstractAspect; class QTableView; class QHeaderView; +class QListView; class QPrinter; class QMenu; @@ -47,6 +48,8 @@ class QModelIndex; class QItemSelection; class QLabel; +class QTextEdit; +class QLineEdit; class HypothesisTestView : public QWidget { Q_OBJECT @@ -70,10 +73,11 @@ const bool gridLines, const bool captions, const bool latexHeaders, const bool skipEmptyRows,const bool exportEntire) const; - HypothesisTest* m_hypothesisTest; - QTableView* m_tableView; - QHeaderView* m_horizontalHeaderView; - QLabel* m_testName; + HypothesisTest* m_hypothesisTest; + QLabel* m_testName; + QLabel* m_statsTable; + QWidget* m_summaryResults; + QLabel* m_resultLine[10]; public slots: void createContextMenu(QMenu*); @@ -81,9 +85,9 @@ void print(QPrinter*) const; void changed(); + void setResultLine(int index, QVariant data, Qt::ItemDataRole role = Qt::DisplayRole); + void clearResult(); private slots: - void goToCell(); - void goToCell(int row, int col); }; #endif diff --git a/src/kdefrontend/hypothesis_test/HypothesisTestView.cpp b/src/kdefrontend/hypothesis_test/HypothesisTestView.cpp --- a/src/kdefrontend/hypothesis_test/HypothesisTestView.cpp +++ b/src/kdefrontend/hypothesis_test/HypothesisTestView.cpp @@ -39,9 +39,8 @@ #include #include #include -#include -#include #include +#include #include #include @@ -59,41 +58,16 @@ HypothesisTestView::HypothesisTestView(HypothesisTest* hypothesisTest) : QWidget(), m_hypothesisTest(hypothesisTest), - m_tableView(new QTableView(this)), - m_horizontalHeaderView(new QHeaderView(Qt::Horizontal, m_tableView)), - m_testName(new QLabel()) { - - //setting alignments and fonts of testname label; - m_testName->setText(m_hypothesisTest->testName()); -// m_testName->setAlignment(Qt::AlignCenter); - QFont font = m_testName->font(); - font.setPointSize(15); - m_testName->setFont(font); - - //setting properties for table view - m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); -// m_tableView->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - -// QHBoxLayout* tableLayout = new QHBoxLayout(m_tableView); -// m_tableView->setLayout(tableLayout); -// m_tableView->setLayout(Qt::ho) + m_testName(new QLabel()), + m_statsTable(new QLabel()), + m_summaryResults(new QWidget()){ + m_summaryResults->setMouseTracking(true); auto* layout = new QVBoxLayout(this); - layout->setContentsMargins(0,0,0,0); layout->addWidget(m_testName); - layout->addSpacing(5); - layout->addWidget(m_tableView); -// layout->setAlignment(m_testName, Qt::AlignHCenter); -// layout->setAlignment(m_tableView, Qt::AlignJustify); - - - m_horizontalHeaderView->setVisible(true); - m_horizontalHeaderView->setEnabled(true); - m_horizontalHeaderView->setSectionsClickable(true); - - m_tableView->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_tableView->setHorizontalHeader(m_horizontalHeaderView); - m_tableView->verticalHeader()->setVisible(false); + layout->addWidget(m_statsTable); + layout->addWidget(m_summaryResults); + layout->addWidget(m_summaryResults); init(); } @@ -103,12 +77,19 @@ initActions(); initMenus(); - m_tableView->setModel(m_hypothesisTest->dataModel()); - m_horizontalHeaderView->setModel(m_hypothesisTest->horizontalHeaderModel()); +// m_summaryResults->setStyleSheet("background-color:white; border: 0px; margin: 0px; padding 0px;qproperty-frame: false;"); + QVBoxLayout* summary_layout = new QVBoxLayout(m_summaryResults); + + for (int i = 0; i < 10; i++) { + m_resultLine[i] = new QLabel(); + summary_layout->addWidget(m_resultLine[i]); + } connect(m_hypothesisTest, &HypothesisTest::changed, this, &HypothesisTestView::changed); } + + void HypothesisTestView::initActions() { } @@ -117,6 +98,20 @@ } +void HypothesisTestView::setResultLine(int index, QVariant data, Qt::ItemDataRole role) { + if (index < 0 || index >= 10) return; + + if (role == Qt::DisplayRole) + m_resultLine[index]->setText(data.toString()); + else if (role == Qt::ToolTipRole) + m_resultLine[index]->setToolTip(data.toString()); +} + +void HypothesisTestView::clearResult() { + for (int i = 0; i < 10; i++) + m_resultLine[i]->clear(); +} + void HypothesisTestView::connectActions() { } @@ -136,24 +131,6 @@ Q_ASSERT(menu); } -void HypothesisTestView::goToCell() { - bool ok; - - int col = QInputDialog::getInt(nullptr, i18n("Go to Cell"), i18n("Enter column"), 1, 1, m_tableView->model()->columnCount(), 1, &ok); - if (!ok) return; - - int row = QInputDialog::getInt(nullptr, i18n("Go to Cell"), i18n("Enter row"), 1, 1, m_tableView->model()->rowCount(), 1, &ok); - if (!ok) return; - - goToCell(row-1, col-1); -} - -void HypothesisTestView::goToCell(int row, int col) { - QModelIndex index = m_tableView->model()->index(row, col); - m_tableView->scrollTo(index); - m_tableView->setCurrentIndex(index); -} - bool HypothesisTestView::exportView() { return true; } @@ -189,6 +166,7 @@ void HypothesisTestView::changed() { m_testName->setText(m_hypothesisTest->testName()); + m_statsTable->setText(m_hypothesisTest->statsTable()); } void HypothesisTestView::exportToFile(const QString& path, const bool exportHeader, const QString& separator, QLocale::Language language) const { @@ -216,5 +194,5 @@ if (!file.open(QFile::WriteOnly | QFile::Truncate)) return; - PERFTRACE("export pivot table to latex"); + PERFTRACE("export pivot table to latex"); } diff --git a/src/kdefrontend/ui/dockwidgets/hypothesistestdock.ui b/src/kdefrontend/ui/dockwidgets/hypothesistestdock.ui --- a/src/kdefrontend/ui/dockwidgets/hypothesistestdock.ui +++ b/src/kdefrontend/ui/dockwidgets/hypothesistestdock.ui @@ -13,282 +13,397 @@ Form - - - - - - Tests - - + + + + 9 + 255 + 73 + 17 + + + + + 75 + true + + + + Structure: + + + + + + 280 + 710 + 77 + 23 + + + + Do Test + + + + + + 10 + 480 + 341 + 106 + + + + Qt::Horizontal + + + - - T Test - - + + + Alternate Hypothesis + + + + + + + mu > muo + + + + + + + mu < muo + + + + + + + mu != muo + + + + + + + + + + + Null Hypothesis + + + + + + + mu <= muo + + + + + + + mu >= muo + + + + + - Independent Sample T-Test + mu == muo - + - - - - - - - - - - 0 - 0 - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 13 - - - - - - - - Source: - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 13 - 23 - - - - - - - - Table: - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Comment: - - - - - - - Connection: - - - - - - - Spreadsheet: - - - - - - - - 75 - true - - - - Data - - - - - - - - 75 - true - - - - Structure: - - - - - - - - - - - 0 - 0 - - - - Name: - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Column 1 - - - Qt::AlignCenter - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - true - - - Column 2 - - - Qt::AlignCenter - - - - - - - OK - - - - + + + + + + + 10 + 610 + 217 + 81 + + + + + + + muo + + + + + + + + + + alpha + + + + + + + + + + + + 15 + 12 + 90 + 25 + + + + + 0 + 0 + + + + Name: + + + + + + 15 + 43 + 90 + 25 + + + + Comment: + + + + + + 130 + 43 + 401 + 25 + + + + + + + 130 + 12 + 401 + 25 + + + + + + + 15 + 93 + 42 + 17 + + + + + 75 + true + + + + Data + + + + + + 15 + 116 + 531 + 112 + + + + + + + Source: + + + + + + + + 0 + 0 + + + + + + + + Spreadsheet: + + + + + + + Connection: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + + + Table: + + + + + + + + + + + + 12 + 433 + 125 + 23 + + + + Equal Variance + + + + + + 13 + 288 + 341 + 50 + + + + + + + + + + Test + + + + + + + Test type + + + + + + + + + + + + 16 + 373 + 394 + 50 + + + + + + + Independent Variable + + + Qt::AlignCenter + + + + + + + Independent Variable + + + + + + + Variable + + + + + + + + + + + + + + + + + + 570 + 10 + 16 + 981 + + + + Qt::Vertical + +