diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -245,6 +245,7 @@ ${BACKEND_DIR}/generalTest/CorrelationCoefficient.cpp ${BACKEND_DIR}/generalTest/GeneralTest.cpp ${BACKEND_DIR}/generalTest/HypothesisTest.cpp + ${BACKEND_DIR}/generalTest/MyTableModel.cpp ${BACKEND_DIR}/generalTest/MyTextEdit.cpp ${BACKEND_DIR}/matrix/Matrix.cpp ${BACKEND_DIR}/matrix/matrixcommands.cpp 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 @@ -57,6 +57,11 @@ QWidget* view() const override; void performTest(int test, bool categoricalVariable = false, bool calculateStats = true); + void initInputStatsTable(int test, bool calculateStats, int nRows, int nColumns); + void setInputStatsTableNRows(int nRows); + void setInputStatsTableNCols(int nColumns); + void exportStatTableToSpreadsheet(); + private: void performPearson(bool categoricalVariable); void performKendall(); 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 @@ -33,6 +33,8 @@ #include "backend/core/column/Column.h" #include "backend/lib/macros.h" +#include "backend/generalTest/MyTableModel.h" + #include #include #include @@ -64,7 +66,6 @@ m_correlationValue = 0; m_statisticValue.clear(); m_pValue.clear(); - m_inputStatsTableModel->clear(); for (int i = 0; i < RESULTLINESCOUNT; i++) m_resultLine[i]->clear(); @@ -85,10 +86,9 @@ break; } case CorrelationCoefficient::ChiSquare: - switch (testSubtype(test)) { - case CorrelationCoefficient::IndependenceTest: + if (testSubtype(test) == CorrelationCoefficient::IndependenceTest) { + m_currTestName = "

" + i18n("Chi Square Independence Test") + "

"; performChiSquareIndpendence(calculateStats); - break; } break; } @@ -96,6 +96,25 @@ emit changed(); } +void CorrelationCoefficient::initInputStatsTable(int test, bool calculateStats, int nRows, int nColumns) { + m_inputStatsTableModel->clear(); + + if (!calculateStats) { + if (testSubtype(test) == IndependenceTest) { + m_inputStatsTableModel->setRowCount(nRows + 1); + m_inputStatsTableModel->setColumnCount(nColumns + 1); + } + } + + for (int i = 1; i < nRows + 1; i++) + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(i, 0), i18n("Row %1", i)); + + for (int i = 1; i < nColumns + 1; i++) + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(0, i), i18n("Column %1", i)); + + emit changed(); +} + double CorrelationCoefficient::correlationValue() const { return m_correlationValue; @@ -109,6 +128,60 @@ return m_pValue; } +void CorrelationCoefficient::setInputStatsTableNRows(int nRows) { + int nRows_old = m_inputStatsTableModel->rowCount(); + m_inputStatsTableModel->setRowCount(nRows + 1); + + for (int i = nRows_old; i < nRows + 1; i++) + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(i, 0), i18n("Row %1", i)); +} + +void CorrelationCoefficient::setInputStatsTableNCols(int nColumns) { + int nColumns_old = m_inputStatsTableModel->columnCount(); + m_inputStatsTableModel->setColumnCount(nColumns + 1); + + for (int i = nColumns_old; i < nColumns + 1; i++) + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(0, i), i18n("Column %1", i)); +} + +void CorrelationCoefficient::exportStatTableToSpreadsheet() { + if (m_dataSourceSpreadsheet == nullptr) + return; + + int rowCount = m_inputStatsTableModel->rowCount(); + int columnCount = m_inputStatsTableModel->columnCount(); + + int spreadsheetColCount = m_dataSourceSpreadsheet->columnCount(); + + m_dataSourceSpreadsheet->insertColumns(spreadsheetColCount, 3); + + Column* col1 = m_dataSourceSpreadsheet->column(spreadsheetColCount); + Column* col2 = m_dataSourceSpreadsheet->column(spreadsheetColCount + 1); + Column* col3 = m_dataSourceSpreadsheet->column(spreadsheetColCount + 2); + + col1->setName("Independent Var. 1"); + col2->setName("Independent Var. 2"); + col3->setName("Data Values"); + + col1->setColumnMode(AbstractColumn::Text); + col2->setColumnMode(AbstractColumn::Text); + col3->setColumnMode(AbstractColumn::Numeric); + + int index = 0; + for (int i = 1; i < rowCount; i++) + for (int j = 1; j < columnCount; j++) { + col1->setTextAt(index, m_inputStatsTableModel->data( + m_inputStatsTableModel->index(i, 0)).toString()); + + col2->setTextAt(index, m_inputStatsTableModel->data( + m_inputStatsTableModel->index(0, j)).toString()); + + col3->setValueAt(index, m_inputStatsTableModel->data( + m_inputStatsTableModel->index(i, j)).toDouble()); + index++; + } +} + /*************************************************************************************************************************** * Private Implementations * ************************************************************************************************************************/ @@ -339,9 +412,172 @@ /***********************************************Chi Square Test for Indpendence******************************************************************/ -// TODO: Implement this function +// TODO: Find P value from chi square test statistic: void CorrelationCoefficient::performChiSquareIndpendence(bool calculateStats) { - Q_UNUSED(calculateStats); + int rowCount; + int columnCount; + + QVector sumRows; + QVector sumColumns; + int overallTotal = 0; + QVector> observedValues; + + QStringList horizontalHeader; + QStringList verticalHeader; + + if (!calculateStats) { + rowCount = m_inputStatsTableModel->rowCount() - 1; + columnCount = m_inputStatsTableModel->columnCount() - 1; + + sumRows.resize(rowCount); + sumColumns.resize(columnCount); + observedValues.resize(rowCount); + + for (int i = 1; i <= rowCount; i++) { + observedValues[i - 1].resize(columnCount); + for (int j = 1; j <= columnCount; j++) { + int cellValue = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, j)).toInt(); + sumRows[i - 1] += cellValue; + sumColumns[j - 1] += cellValue; + overallTotal += cellValue; + observedValues[i - 1][j - 1] = cellValue; + } + } + + for (int i = 0; i < columnCount + 1; i++) + horizontalHeader.append(m_inputStatsTableModel->data(m_inputStatsTableModel->index(0, i)).toString()); + + for (int i = 0; i < rowCount + 1; i++) + verticalHeader.append(m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 0)).toString()); + } else { + if (m_columns.count() != 3) { + printError("Select only 3 columns "); + return; + } + + int nRows = findCount(m_columns[0]); + + rowCount = 0; + columnCount = 0; + + horizontalHeader.append(QString()); + verticalHeader.append(QString()); + + QMap independentVar1; + QMap independentVar2; + for (int i = 0; i < nRows; i++) { + QString cell1Text = m_columns[0]->textAt(i); + QString cell2Text = m_columns[1]->textAt(i); + + if (independentVar1[cell1Text] == 0) { + independentVar1[cell1Text] = ++columnCount; + horizontalHeader.append(cell1Text); + } + + if (independentVar2[cell2Text] == 0) { + independentVar2[cell2Text] = ++rowCount; + verticalHeader.append(cell2Text); + } + } + + sumRows.resize(rowCount); + sumColumns.resize(columnCount); + observedValues.resize(rowCount); + for (int i = 0; i < rowCount; i++) + observedValues[i].resize(columnCount); + + + for (int i = 0; i < nRows; i++) { + QString cell1Text = m_columns[0]->textAt(i); + QString cell2Text = m_columns[1]->textAt(i); + int cellValue = int(m_columns[2]->valueAt(i)); + + int partition1Number = independentVar1[cell1Text] - 1; + int partition2Number = independentVar2[cell2Text] - 1; + + sumRows[partition1Number] += cellValue; + sumColumns[partition2Number] += cellValue; + overallTotal += cellValue; + observedValues[partition1Number][partition2Number] = cellValue; + } + } + + if (overallTotal == 0) + printError("Enter some data: All columns are empty"); + + QVector> expectedValues(rowCount, QVector(columnCount)); + + for (int i = 0; i < rowCount; i++) + for (int j = 0; j < columnCount; j++) + expectedValues[i][j] = (double(sumRows[i]) * double(sumColumns[j])) / overallTotal; + + m_statsTable += "

" + i18n("Observed Value Table") + "

"; + QList rowMajor; + int level = 0; + // horizontal header + for (int i = 0; i < columnCount + 1; i++) + rowMajor.append(new HtmlCell(horizontalHeader[i], level, true)); + + rowMajor.append(new HtmlCell("Total", level, true)); + + //data with vertical header. + for (int i = 1; i < rowCount + 1; i++) { + level++; + rowMajor.append(new HtmlCell(verticalHeader[i], level, true)); + for (int j = 0; j < columnCount; j++) + rowMajor.append(new HtmlCell(round(observedValues[i - 1][j]), level)); + + rowMajor.append(new HtmlCell(round(sumRows[i - 1]), level)); + } + + level++; + rowMajor.append(new HtmlCell("Total", level, true)); + for (int i = 0; i < columnCount; i++) + rowMajor.append(new HtmlCell(round(sumColumns[i]), level)); + + rowMajor.append(new HtmlCell(round(overallTotal), level)); + m_statsTable += getHtmlTable3(rowMajor); + + m_statsTable += "
"; + + m_statsTable += "

" + i18n("Expected Value Table") + "

"; + rowMajor.clear(); + level = 0; + // horizontal header + for (int i = 0; i < columnCount + 1; i++) + rowMajor.append(new HtmlCell(horizontalHeader[i], level, true)); + + rowMajor.append(new HtmlCell("Total", level, true)); + + //data with vertical header. + for (int i = 1; i < rowCount + 1; i++) { + level++; + rowMajor.append(new HtmlCell(verticalHeader[i], level, true)); + for (int j = 0; j < columnCount; j++) + rowMajor.append(new HtmlCell(round(expectedValues[i - 1][j]), level)); + + rowMajor.append(new HtmlCell(round(sumRows[i - 1]), level)); + } + + level++; + rowMajor.append(new HtmlCell("Total", level, true)); + for (int i = 0; i < columnCount; i++) + rowMajor.append(new HtmlCell(round(sumColumns[i]), level)); + + rowMajor.append(new HtmlCell(round(overallTotal), level)); + + m_statsTable += getHtmlTable3(rowMajor); + + double chiSquareVal = 0; + // finding chi-square value; + for (int i = 0; i < rowCount; i++) + for (int j = 0; j < columnCount; j++) + chiSquareVal += gsl_pow_2(observedValues[i][j] - expectedValues[i][j]) / expectedValues[i][j]; + + m_statisticValue.append(chiSquareVal); + int df = (rowCount - 1) * (columnCount - 1); + printLine(0, "Degree of Freedom is " + QString::number(df), "blue"); + printLine(1, "Chi Square Statistic Value is " + round(chiSquareVal), "green"); } /***********************************************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,8 +38,8 @@ class Column; class QVBoxLayout; class QLabel; -class QStandardItemModel; class QAbstractItemModel; +class MyTableModel; class GeneralTest : public AbstractPart { Q_OBJECT @@ -95,6 +95,9 @@ void save(QXmlStreamWriter*) const override; bool load(XmlStreamReader*, bool preview) override; +public slots: + void clearInputStatsTable(); + signals: void changed(); void requestProjectContextMenu(QMenu*); @@ -113,7 +116,7 @@ QVBoxLayout* m_summaryLayout{nullptr}; QLabel* m_resultLine[RESULTLINESCOUNT]; - QStandardItemModel* m_inputStatsTableModel; + MyTableModel* 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,6 +32,8 @@ #include "backend/core/column/Column.h" #include "backend/lib/macros.h" +#include "backend/generalTest/MyTableModel.h" + #include #include #include @@ -47,7 +49,7 @@ GeneralTest::GeneralTest(const QString& name, const AspectType& type) : AbstractPart(name, type), m_summaryLayout(new QVBoxLayout()), - m_inputStatsTableModel(new QStandardItemModel) { + m_inputStatsTableModel(new MyTableModel()) { for (int i = 0; i < RESULTLINESCOUNT; i++) { m_resultLine[i] = new QLabel(); @@ -440,7 +442,7 @@ table = ""; table += ""; @@ -533,11 +535,24 @@ return !reader->hasError(); } +void GeneralTest::clearInputStatsTable() { +// int rowCount = m_inputStatsTableModel->rowCount(); +// int columnCount = m_inputStatsTableModel->columnCount(); + + QList horizontalHeader = m_inputStatsTableModel->takeRow(0); + QList verticalHeader = m_inputStatsTableModel->takeColumn(0); + + m_inputStatsTableModel->clear(); + m_inputStatsTableModel->appendRow(horizontalHeader); + + verticalHeader.push_front(m_inputStatsTableModel->takeColumn(0)[0]); + m_inputStatsTableModel->insertColumn(0, verticalHeader); +} + Spreadsheet *GeneralTest::dataSourceSpreadsheet() const { return m_dataSourceSpreadsheet; } - bool GeneralTest::exportView() const { return true; } 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 @@ -64,8 +64,6 @@ QList& pValue(); QWidget* view() const override; - double myTest; - private: void performTwoSampleIndependentTest(int test, bool categoricalVariable = false, bool equalVariance = true, bool calculateStats = true); void performTwoSamplePairedTest(int test); 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,6 +32,8 @@ #include "backend/core/column/Column.h" #include "backend/lib/macros.h" +#include "backend/generalTest/MyTableModel.h" + #include #include #include @@ -126,10 +128,19 @@ if (!calculateStats) { if (testSubtype(test) == TwoSampleIndependent) { - m_inputStatsTableModel->setRowCount(2); - m_inputStatsTableModel->setColumnCount(4); - m_inputStatsTableModel->setHorizontalHeaderLabels( - {i18n("N"), i18n("Sum"), i18n("Mean"), i18n("Standard Deviation")}); + m_inputStatsTableModel->setRowCount(3); + m_inputStatsTableModel->setColumnCount(5); + + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(0, 1), i18n("N")); + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(0, 2), i18n("Sum")); + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(0, 3), i18n("Mean")); + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(0, 4), i18n("Standard Deviation")); + + for (int i = 1; i < 5; i++) + m_inputStatsTableModel->item(0, i)->setEditable(false); + + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(1, 0), i18n("Row 1")); + m_inputStatsTableModel->setData(m_inputStatsTableModel->index(2, 0), i18n("Row 2")); } } @@ -162,20 +173,20 @@ QString textValue; QDEBUG("m_inputStatsTable row and column count " << m_inputStatsTableModel->rowCount() << m_inputStatsTableModel->columnCount()); - 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(); + for (int i = 1; i < 3; i++) { + n[i - 1] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 1)).toInt(); + sum[i - 1] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 2)).toDouble(); + mean[i - 1] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 3)).toDouble(); + std[i - 1] = m_inputStatsTableModel->data(m_inputStatsTableModel->index(i, 4)).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"; } + col1Name = m_inputStatsTableModel->data(m_inputStatsTableModel->index(1, 0)).toString(); + col2Name = m_inputStatsTableModel->data(m_inputStatsTableModel->index(2, 0)).toString(); } else { if (m_columns.size() != 2) { printError("Inappropriate number of m_columns selected"); diff --git a/src/backend/generalTest/MyTableModel.h b/src/backend/generalTest/MyTableModel.h new file mode 100644 --- /dev/null +++ b/src/backend/generalTest/MyTableModel.h @@ -0,0 +1,44 @@ +/*************************************************************************** + File : MyTableModel.h + Project : LabPlot + Description : Derived class of QStandardItemModel + -------------------------------------------------------------------- + Copyright : (C) 2019 Devanshu Agarwal(agarwaldevanshu8@gmail.com) + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + ***************************************************************************/ + +#ifndef MYTABLEMODEL_H +#define MYTABLEMODEL_H + +#include + +class MyTableModel : public QStandardItemModel { + Q_OBJECT + +public: + typedef QStandardItemModel inherited; + explicit MyTableModel(QObject* parent = nullptr); + +public slots: + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; +}; +#endif // MYTABLEMODEL_H diff --git a/src/backend/generalTest/MyTableModel.cpp b/src/backend/generalTest/MyTableModel.cpp new file mode 100644 --- /dev/null +++ b/src/backend/generalTest/MyTableModel.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + File : MyTableModel.cpp + Project : LabPlot + Description : Derived class of QStandardItemModel + -------------------------------------------------------------------- + Copyright : (C) 2019 Devanshu Agarwal(agarwaldevanshu8@gmail.com) + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + ***************************************************************************/ + +#include "backend/generalTest/MyTableModel.h" + +#include + +MyTableModel::MyTableModel(QObject* parent) : QStandardItemModel(parent) { +} + +QVariant MyTableModel::data(const QModelIndex &index, int role) const { + if (role == Qt::FontRole && (index.column() == 0 || index.row() == 0)) { + QFont font; + font.setBold(true); + return font; + } else if (role == Qt::ForegroundRole) { + if (index.row() == 0) + return QColor(Qt::white); + if (index.column() == 0) + return QColor(Qt::black); + } + else if (role == Qt::BackgroundRole) { + if (index.row() == 0) + return QColor(0x008b8b); + if (index.column() == 0) + return QColor(Qt::cyan); + } + + return inherited::data(index, role); +} + + + 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,7 +89,10 @@ void spreadsheetChanged(const QModelIndex&); void col1IndexChanged(int index); void changeCbCol2Label(); - void chbColumnStatisticsStateChanged(); + void chbColumnStatsStateChanged(); + void leNRowsChanged(); + void leNColumnsChanged(); + void exportStatsTableToSpreadsheet(); // 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 @@ -73,18 +73,28 @@ ui.cbTest->addItem( i18n("Spearman"), CorrelationCoefficient::Spearman); ui.cbTest->addItem( i18n("Chi Square"), CorrelationCoefficient::ChiSquare); + ui.leNRows->setText("2"); + ui.leNColumns->setText("2"); + + ui.leNRows->setValidator(new QIntValidator(this)); + ui.leNColumns->setValidator(new QIntValidator(this)); + ui.lTestType->hide(); 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.lCalculateStats->hide(); + ui.chbCalculateStats->hide(); + ui.lNRows->hide(); + ui.leNRows->hide(); + ui.lNColumns->hide(); + ui.leNColumns->hide(); ui.lCategorical->hide(); ui.chbCategorical->hide(); ui.lCol1->hide(); ui.cbCol1->hide(); ui.lCol2->hide(); ui.cbCol2->hide(); + ui.lCol3->hide(); + ui.cbCol3->hide(); ui.lAlpha->hide(); ui.leAlpha->hide(); ui.pbPerformTest->setEnabled(false); @@ -128,7 +138,10 @@ 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.chbCalculateStats, &QCheckBox::stateChanged, this, &CorrelationCoefficientDock::chbColumnStatsStateChanged); + connect(ui.leNRows, &QLineEdit::textChanged, this, &CorrelationCoefficientDock::leNRowsChanged); + connect(ui.leNColumns, &QLineEdit::textChanged, this, &CorrelationCoefficientDock::leNColumnsChanged); + connect(ui.pbExportToSpreadsheet, &QPushButton::clicked, this, &CorrelationCoefficientDock::exportStatsTableToSpreadsheet); connect(ui.pbPerformTest, &QPushButton::clicked, this, &CorrelationCoefficientDock::findCorrelationCoefficient); connect(ui.cbCol1, static_cast(&QComboBox::currentIndexChanged), this, &CorrelationCoefficientDock::col1IndexChanged); @@ -203,38 +216,29 @@ void CorrelationCoefficientDock::showCorrelationCoefficient() { m_test |= ui.cbTestType->currentData().toInt(); - ui.lCol1->show(); - ui.cbCol1->show(); - - 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.lCalculateStats->setVisible(testType(m_test) == CorrelationCoefficient::ChiSquare); + ui.chbCalculateStats->setVisible(testType(m_test) == CorrelationCoefficient::ChiSquare); - ui.lCategorical->setVisible(testType(m_test) == CorrelationCoefficient::Pearson); - ui.chbCategorical->setVisible(testType(m_test) == CorrelationCoefficient::Pearson); - - ui.lAlpha->setVisible(m_test == (CorrelationCoefficient::ChiSquare | CorrelationCoefficient::IndependenceTest)); - ui.leAlpha->setVisible(m_test == (CorrelationCoefficient::ChiSquare | CorrelationCoefficient::IndependenceTest)); - - setColumnsComboBoxView(); + if (testType(m_test) != CorrelationCoefficient::ChiSquare) + ui.chbCalculateStats->setChecked(true); - ui.pbPerformTest->setEnabled(nonEmptySelectedColumns()); + chbColumnStatsStateChanged(); } void CorrelationCoefficientDock::findCorrelationCoefficient() { QVector cols; - if (ui.cbCol1->count() == 0) + if (ui.chbCategorical->isChecked() && ui.cbCol1->count() == 0) return; cols << reinterpret_cast(ui.cbCol1->currentData().toLongLong()); cols << reinterpret_cast(ui.cbCol2->currentData().toLongLong()); + if (testSubType(m_test) == CorrelationCoefficient::IndependenceTest) + cols << reinterpret_cast(ui.cbCol3->currentData().toLongLong()); + m_correlationCoefficient->setColumns(cols); - m_correlationCoefficient->performTest(m_test, ui.chbCategorical->isChecked()); + m_correlationCoefficient->performTest(m_test, ui.chbCategorical->isChecked(), ui.chbCalculateStats->isChecked()); } void CorrelationCoefficientDock::setModelIndexFromAspect(TreeViewComboBox* cb, const AbstractAspect* aspect) { @@ -422,14 +426,50 @@ } } -void CorrelationCoefficientDock::chbColumnStatisticsStateChanged() { - bool chbChecked = ui.chbStatsFromSpreadsheet->isChecked(); +void CorrelationCoefficientDock::chbColumnStatsStateChanged() { + bool chbChecked = ui.chbCalculateStats->isChecked(); ui.lVariables->setVisible(chbChecked); ui.lCol1->setVisible(chbChecked); ui.cbCol1->setVisible(chbChecked); ui.lCol2->setVisible(chbChecked); ui.cbCol2->setVisible(chbChecked); + ui.lCol3->setVisible(chbChecked); + ui.cbCol3->setVisible(chbChecked); + + ui.lCategorical->setVisible(chbChecked && testType(m_test) == CorrelationCoefficient::Pearson); + ui.chbCategorical->setVisible(chbChecked && testType(m_test) == CorrelationCoefficient::Pearson); + + ui.lNRows->setVisible(!chbChecked); + ui.leNRows->setVisible(!chbChecked); + + ui.lNColumns->setVisible(!chbChecked); + ui.leNColumns->setVisible(!chbChecked); + ui.pbExportToSpreadsheet->setVisible(!chbChecked); + + if (chbChecked) { + setColumnsComboBoxView(); + ui.pbPerformTest->setEnabled(nonEmptySelectedColumns()); + } else + ui.pbPerformTest->setEnabled(true); + + if (m_correlationCoefficient != nullptr) + m_correlationCoefficient->initInputStatsTable(m_test, chbChecked, ui.leNRows->text().toInt(), ui.leNColumns->text().toInt()); +} + +void CorrelationCoefficientDock::leNRowsChanged() { + if (m_correlationCoefficient != nullptr) + m_correlationCoefficient->setInputStatsTableNRows(ui.leNRows->text().toInt()); +} + +void CorrelationCoefficientDock::leNColumnsChanged() { + if (m_correlationCoefficient != nullptr) + m_correlationCoefficient->setInputStatsTableNCols(ui.leNColumns->text().toInt()); +} + +void CorrelationCoefficientDock::exportStatsTableToSpreadsheet() { + if (ui.chbCalculateStats->isVisible() && !ui.chbCalculateStats->isChecked()) + m_correlationCoefficient->exportStatTableToSpreadsheet(); } ////************************************************************* @@ -485,6 +525,7 @@ void CorrelationCoefficientDock::setColumnsComboBoxView() { ui.cbCol1->clear(); ui.cbCol2->clear(); + ui.cbCol3->clear(); QList::iterator i; @@ -523,8 +564,7 @@ break; } case CorrelationCoefficient::ChiSquare: { - switch (testSubType(m_test)) { - case CorrelationCoefficient::IndependenceTest: + if (testSubType(m_test) == CorrelationCoefficient::IndependenceTest) { for (i = m_twoCategoricalCols.begin(); i != m_twoCategoricalCols.end(); i++) { ui.cbCol1->addItem( (*i)->name(), qint64(*i)); ui.cbCol2->addItem( (*i)->name(), qint64(*i)); @@ -533,7 +573,9 @@ ui.cbCol1->addItem( (*i)->name(), qint64(*i)); ui.cbCol2->addItem( (*i)->name(), qint64(*i)); } - break; + for (i = m_onlyValuesCols.begin(); i != m_onlyValuesCols.end(); i++) { + ui.cbCol3->addItem( (*i)->name(), qint64(*i)); + } } break; } 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 @@ -77,6 +77,8 @@ ui.lPopulationSigma->setText( UTF8_QSTRING("σ")); + ui.chbCalculateStats->setChecked(true); + // making all test blocks invisible at starting. ui.pbLeveneTest->hide(); ui.lCategorical->hide(); @@ -286,26 +288,12 @@ m_test |= ui.cbTestType->currentData().toInt(); - ui.lCol1->show(); - ui.cbCol1->show(); - - ui.lCol2->setVisible(testSubtype(m_test) != HypothesisTest::OneSample); - ui.cbCol2->setVisible(testSubtype(m_test) != HypothesisTest::OneSample); - - 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); - - ui.lCategorical->setVisible(m_test == (HypothesisTest::TTest | HypothesisTest::TwoSampleIndependent)); - ui.chbCategorical->setVisible(m_test == (HypothesisTest::TTest | HypothesisTest::TwoSampleIndependent)); - ui.lPopulationSigma->setVisible(m_test == (HypothesisTest::TTest | HypothesisTest::OneSample) || m_test == (HypothesisTest::ZTest | HypothesisTest::OneSample)); @@ -578,18 +566,20 @@ } 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(); - } + bool calculateStats = ui.chbCalculateStats->isChecked(); + + ui.lVariables->setVisible(calculateStats); + ui.lCol1->setVisible(calculateStats); + ui.cbCol1->setVisible(calculateStats); + + ui.lCol2->setVisible(calculateStats && testSubtype(m_test) != HypothesisTest::OneSample); + ui.cbCol2->setVisible(calculateStats && testSubtype(m_test) != HypothesisTest::OneSample); + + ui.lCol3->setVisible(calculateStats && m_test == (HypothesisTest::Anova | HypothesisTest::TwoWay)); + ui.cbCol3->setVisible(calculateStats && m_test == (HypothesisTest::Anova | HypothesisTest::TwoWay)); + + ui.lCategorical->setVisible(calculateStats && m_test == (HypothesisTest::TTest | HypothesisTest::TwoSampleIndependent)); + ui.chbCategorical->setVisible(calculateStats && m_test == (HypothesisTest::TTest | HypothesisTest::TwoSampleIndependent)); if (m_hypothesisTest != nullptr) m_hypothesisTest->initInputStatsTable(m_test, ui.chbCalculateStats->isChecked()); diff --git a/src/kdefrontend/generalTest/CorrelationCoefficientView.cpp b/src/kdefrontend/generalTest/CorrelationCoefficientView.cpp --- a/src/kdefrontend/generalTest/CorrelationCoefficientView.cpp +++ b/src/kdefrontend/generalTest/CorrelationCoefficientView.cpp @@ -31,9 +31,11 @@ #include "backend/lib/macros.h" #include "backend/lib/trace.h" +#include +#include /*! \class CorrelationCoefficientView - \brief View class for Hypothesis Test + \brief View class for Correlation Coefficient Test \ingroup kdefrontend */ 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 @@ -43,6 +43,7 @@ class QLabel; class MyTextEdit; class QTableView; +class QPushButton; #define RESULTLINESCOUNT 10 @@ -74,8 +75,10 @@ QWidget* m_summaryResults{nullptr}; QLabel* m_resultLine[RESULTLINESCOUNT]; - QTableView* m_inputStatsTable; + QWidget* m_inputStatsWidget; QLabel* m_labelInputStatsTable; + QTableView* m_inputStatsTable; + QPushButton* m_clearInputStats; 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 @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include @@ -56,21 +58,27 @@ m_testName(new QLabel()), m_statsTable(new MyTextEdit()), m_summaryResults(new QWidget()), + m_inputStatsWidget(new QWidget()), + m_labelInputStatsTable(new QLabel()), m_inputStatsTable(new QTableView()), - m_labelInputStatsTable(new QLabel()) { + m_clearInputStats(new QPushButton()) { + + QVBoxLayout * inputStatsLayout = new QVBoxLayout(m_inputStatsWidget); + inputStatsLayout->addWidget(m_labelInputStatsTable); + inputStatsLayout->addWidget(m_inputStatsTable); + inputStatsLayout->addWidget(m_clearInputStats); 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_inputStatsWidget->setStyleSheet("background-color: white"); m_testName->hide(); m_statsTable->hide(); m_summaryResults->hide(); - m_inputStatsTable->hide(); + m_inputStatsWidget->hide(); auto* layout = new QVBoxLayout(this); @@ -79,10 +87,10 @@ "

" + i18n("You can leave one or more columns empty if you feel they are not useful") + ""); - m_labelInputStatsTable->hide(); + m_clearInputStats->setText(i18n("Clear")); + m_clearInputStats->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - layout->addWidget(m_labelInputStatsTable); - layout->addWidget(m_inputStatsTable); + layout->addWidget(m_inputStatsWidget); layout->addWidget(m_testName); layout->addWidget(m_statsTable); layout->addWidget(m_summaryResults); @@ -97,15 +105,15 @@ 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_inputStatsTable->horizontalHeader()->setVisible(false); + m_inputStatsTable->verticalHeader()->setVisible(false); + m_inputStatsTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_statsTable->setMouseTracking(true); connect(m_generalTest, &GeneralTest::changed, this, &GeneralTestView::changed); + connect(m_clearInputStats, &QPushButton::clicked, m_generalTest, &GeneralTest::clearInputStatsTable); } void GeneralTestView::initActions() { @@ -187,14 +195,10 @@ 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(); - } + m_inputStatsTable->model()->columnCount() > 0) + m_inputStatsWidget->show(); + else + m_inputStatsWidget->hide(); } void GeneralTestView::exportToFile(const QString& path, const bool exportHeader, const QString& separator, QLocale::Language language) const { diff --git a/src/kdefrontend/generalTest/HypothesisTestView.cpp b/src/kdefrontend/generalTest/HypothesisTestView.cpp --- a/src/kdefrontend/generalTest/HypothesisTestView.cpp +++ b/src/kdefrontend/generalTest/HypothesisTestView.cpp @@ -31,6 +31,8 @@ #include "backend/lib/macros.h" #include "backend/lib/trace.h" +#include +#include /*! \class HypothesisTestView \brief View class for Hypothesis Test