1 /***************************************************************************
2 File : StudentTestDialog.cpp
3 Project : QtiPlot
4 --------------------------------------------------------------------
5 Copyright : (C) 2010 by Ion Vasilief
6 Email (use @ for *) : ion_vasilief*yahoo.fr
7 Description : Student's t-Test dialog
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 * You should have received a copy of the GNU General Public License *
24 * along with this program; if not, write to the Free Software *
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26 * Boston, MA 02110-1301 USA *
27 * *
28 ***************************************************************************/
29 #include "StudentTestDialog.h"
30 #include <ApplicationWindow.h>
31 #include <DoubleSpinBox.h>
32 #include <CollapsiveGroupBox.h>
33 #include <tTest.h>
34 #include <ChiSquareTest.h>
35 #include <Note.h>
36
37 #include <QGroupBox>
38 #include <QComboBox>
39 #include <QLayout>
40 #include <QPushButton>
41 #include <QRadioButton>
42 #include <QLabel>
43 #include <QLineEdit>
44 #include <QSpinBox>
45
StudentTestDialog(const StatisticTest::TestType & type,Table * t,bool twoSamples,QWidget * parent)46 StudentTestDialog::StudentTestDialog(const StatisticTest::TestType& type, Table *t, bool twoSamples, QWidget* parent)
47 : QDialog( parent),
48 d_test_type(type),
49 d_two_samples(twoSamples)
50 {
51 ApplicationWindow *app = (ApplicationWindow *)parent;
52 d_table = 0;
53 d_note = 0;
54
55 setObjectName( "StudentTestDialog" );
56 QHBoxLayout *hl = 0;
57
58 if (type == StatisticTest::ChiSquareTest)
59 setWindowTitle(tr("Chi-square Test for Variance"));
60 else {
61 if (twoSamples){
62 setWindowTitle(tr("Two sample t-Test"));
63
64 independentTestBtn = new QRadioButton(tr("In&dependent Test"));
65 independentTestBtn->setChecked(true);
66 pairedTestBtn = new QRadioButton(tr("Pai&red Test"));
67 hl = new QHBoxLayout();
68 hl->addWidget(independentTestBtn);
69 hl->addWidget(pairedTestBtn);
70 hl->addStretch();
71 } else
72 setWindowTitle(tr("One sample t-Test"));
73 }
74
75 setSizeGripEnabled( true );
76 setAttribute(Qt::WA_DeleteOnClose);
77 #ifdef Q_OS_WIN
78 setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint);
79 #endif
80
81 QGridLayout *gl1 = new QGridLayout();
82 gl1->setColumnStretch(1, 1);
83
84 QLabel *sample1Label = new QLabel(tr("Sample") + ":");
85 gl1->addWidget(sample1Label, 0, 0);
86
87 QStringList columnsList = t->applicationWindow()->columnsList();
88 boxSample1 = new QComboBox();
89 boxSample1->addItems(columnsList);
90 gl1->addWidget(boxSample1, 0, 1);
91
92 QStringList lst = t->selectedColumns();
93 int selectedColumns = lst.size();
94 if (selectedColumns)
95 boxSample1->setCurrentIndex(boxSample1->findText(lst[0]));
96 else
97 boxSample1->setCurrentIndex(boxSample1->findText(t->colName(0)));
98
99 QString mean = tr("Mean");
100 if (type == StatisticTest::ChiSquareTest)
101 mean = tr("Variance");
102 else {
103 if (twoSamples){
104 mean = mean + "1 - " + mean + "2";
105 sample1Label->setText(tr("Sample") + "1:");
106 gl1->addWidget(new QLabel(tr("Sample") + "2:"), 1, 0);
107
108 boxSample2 = new QComboBox();
109 boxSample2->addItems(columnsList);
110 gl1->addWidget(boxSample2, 1, 1);
111
112 if (selectedColumns > 1)
113 boxSample2->setCurrentIndex(boxSample2->findText(lst[1]));
114 }
115 }
116
117 QGroupBox *gb2 = new QGroupBox(tr("Hypotheses"));
118 QGridLayout *gl2 = new QGridLayout(gb2);
119 gl2->setColumnStretch(2, 1);
120
121 gl2->addWidget(new QLabel(tr("Null") + ":"), 0, 0);
122
123 meanLabel = new QLabel(mean + " = ");
124 gl2->addWidget(meanLabel, 0, 1);
125
126 boxMean = new DoubleSpinBox();
127 gl2->addWidget(boxMean, 0, 2);
128
129 gl2->addWidget(new QLabel(tr("Alternate") + ":"), 1, 0);
130
131 bothTailButton = new QRadioButton(mean + " <>");
132 bothTailButton->setChecked(true);
133 gl2->addWidget(bothTailButton, 1, 1);
134 bothTailLabel = new QLabel();
135 bothTailLabel->setText("0");
136 gl2->addWidget(bothTailLabel, 1, 2);
137
138 rightTailButton = new QRadioButton(mean + " >");
139 gl2->addWidget(rightTailButton, 2, 1);
140 rightTailLabel = new QLabel();
141 rightTailLabel->setText("0");
142 gl2->addWidget(rightTailLabel, 2, 2);
143
144 leftTailButton = new QRadioButton(mean + " <");
145 gl2->addWidget(leftTailButton, 3, 1);
146 leftTailLabel = new QLabel();
147 leftTailLabel->setText("0");
148 gl2->addWidget(leftTailLabel, 3, 2);
149
150 gl2->addWidget(new QLabel(tr("Significance Level")), 4, 0);
151 boxSignificance = new DoubleSpinBox();
152 boxSignificance->setRange(0.0, 1.0);
153 boxSignificance->setDecimals(2);
154 boxSignificance->setSingleStep(0.01);
155 boxSignificance->setValue(app->d_stats_significance_level);
156 gl2->addWidget(boxSignificance, 4, 1);
157
158 boxConfidenceInterval = new CollapsiveGroupBox(tr("Confidence &Interval(s)"));
159
160 DoubleSpinBox *sbox = new DoubleSpinBox();
161 sbox->setRange(0.01, 99.99);
162 sbox->setSingleStep(1.0);
163 sbox->setValue(90);
164
165 QGridLayout *gl3 = new QGridLayout(boxConfidenceInterval);
166 gl3->setColumnStretch(1, 1);
167 gl3->addWidget(new QLabel(tr("Level(s) in %")), 0, 0);
168 gl3->addWidget(sbox, 0, 1);
169
170 buttonAddLevel = new QPushButton(tr("&Add Level"));
171 gl3->addWidget(buttonAddLevel, 0, 2);
172 boxConfidenceInterval->setChecked(app->d_stats_confidence);
173
174 if (type == StatisticTest::StudentTest){
175 boxPowerAnalysis = new CollapsiveGroupBox(tr("&Power Analysis"));
176 QGridLayout *gl4 = new QGridLayout(boxPowerAnalysis);
177
178 boxPowerLevel = new DoubleSpinBox();
179 boxPowerLevel->setRange(0.01, 0.99);
180 boxPowerLevel->setSingleStep(0.01);
181 boxPowerLevel->setValue(0.05);
182
183 gl4->addWidget(new QLabel(tr("Alpha")), 0, 0);
184 gl4->addWidget(boxPowerLevel, 0, 1);
185
186 boxOtherSampleSize = new QCheckBox(tr("Sample &Size"));
187 boxOtherSampleSize->setChecked(false);
188 gl4->addWidget(boxOtherSampleSize, 1, 0);
189
190 boxSampleSize = new QSpinBox();
191 boxSampleSize->setRange(1, INT_MAX);
192 boxSampleSize->setValue(50);
193 boxSampleSize->setEnabled(false);
194 gl4->addWidget(boxSampleSize, 1, 1);
195
196 connect(boxOtherSampleSize, SIGNAL(toggled(bool)), boxSampleSize, SLOT(setEnabled(bool)));
197 boxPowerAnalysis->setChecked(app->d_stats_power);
198 }
199
200 outputSettingsBox = new CollapsiveGroupBox("&" + tr("Output Settings"));
201 QGridLayout *gl4 = new QGridLayout(outputSettingsBox);
202
203 boxResultsTable = new QCheckBox(tr("&Table"));
204 boxResultsTable->setChecked(app->d_stats_result_table);
205 gl4->addWidget(boxResultsTable, 0, 0);
206
207 tableNameLineEdit = new QLineEdit();
208 tableNameLineEdit->setEnabled(false);
209 gl4->addWidget(tableNameLineEdit, 0, 1);
210
211 boxNoteWindow = new QCheckBox(tr("&Notes Window"));
212 boxNoteWindow->setChecked(app->d_stats_result_notes);
213 gl4->addWidget(boxNoteWindow, 1, 0);
214
215 noteNameLineEdit = new QLineEdit();
216 noteNameLineEdit->setEnabled(false);
217 gl4->addWidget(noteNameLineEdit, 1, 1);
218
219 boxResultsLog = new QCheckBox(tr("Results &Log"));
220 boxResultsLog->setChecked(app->d_stats_result_log);
221 gl4->addWidget(boxResultsLog, 2, 0);
222
223 showStatisticsBox = new QCheckBox(tr("&Descriptive Statistics" ));
224 showStatisticsBox->setChecked(app->d_descriptive_stats);
225 enableDescriptiveStatistics();
226 gl4->addWidget(showStatisticsBox, 2, 1);
227 outputSettingsBox->setChecked(app->d_stats_output);
228
229 buttonOk = new QPushButton(tr( "&Compute" ));
230
231 QHBoxLayout *hl2 = new QHBoxLayout();
232 hl2->addStretch();
233 hl2->addWidget(buttonOk);
234 hl2->addStretch();
235
236 QVBoxLayout *vl = new QVBoxLayout(this);
237 if (twoSamples){
238 boxOtherSampleSize->hide();
239 boxSampleSize->hide();
240 vl->addLayout(hl);
241 }
242 vl->addLayout(gl1);
243 vl->addWidget(gb2);
244 vl->addWidget(boxConfidenceInterval);
245 if (type == StatisticTest::StudentTest)
246 vl->addWidget(boxPowerAnalysis);
247 vl->addWidget(outputSettingsBox);
248 vl->addStretch();
249 vl->addLayout(hl2);
250
251 connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
252 connect(buttonAddLevel, SIGNAL(clicked()), this, SLOT(addConfidenceLevel()));
253 connect(leftTailButton, SIGNAL(toggled(bool)), this, SLOT(updateMeanLabel()));
254 connect(rightTailButton, SIGNAL(toggled(bool)), this, SLOT(updateMeanLabel()));
255 connect(bothTailButton, SIGNAL(toggled(bool)), this, SLOT(updateMeanLabel()));
256 connect(boxMean, SIGNAL(valueChanged(double)), this, SLOT(updateMeanLabels(double)));
257 connect(boxResultsTable, SIGNAL(toggled(bool)), tableNameLineEdit, SLOT(setEnabled(bool)));
258 connect(boxNoteWindow, SIGNAL(toggled(bool)), noteNameLineEdit, SLOT(setEnabled(bool)));
259 connect(boxNoteWindow, SIGNAL(toggled(bool)), this, SLOT(enableDescriptiveStatistics()));
260 connect(boxResultsLog, SIGNAL(toggled(bool)), this, SLOT(enableDescriptiveStatistics()));
261 }
262
enableDescriptiveStatistics()263 void StudentTestDialog::enableDescriptiveStatistics()
264 {
265 showStatisticsBox->setEnabled(boxNoteWindow->isChecked() || boxResultsLog->isChecked());
266 }
267
addConfidenceLevel()268 void StudentTestDialog::addConfidenceLevel()
269 {
270 QGridLayout *gl = (QGridLayout *)boxConfidenceInterval->layout();
271 if (!gl)
272 return;
273
274 int rows = gl->rowCount();
275
276 DoubleSpinBox *sbox = new DoubleSpinBox();
277 sbox->setRange(0.01, 99.999);
278 sbox->setSingleStep(1.0);
279
280 DoubleSpinBox *sb = (DoubleSpinBox *)gl->itemAtPosition (rows - 1, 1)->widget();
281 sbox->setValue(floor(0.5*(100 + sb->value())));
282
283 gl->addWidget(sbox, rows, 1);
284 }
285
updateMeanLabel()286 void StudentTestDialog::updateMeanLabel()
287 {
288 QString s = tr("Mean");
289 if (d_test_type == StatisticTest::ChiSquareTest)
290 s = tr("Variance");
291 else if (d_two_samples)
292 s = s + "1 - " + s + "2";
293
294 if (bothTailButton->isChecked())
295 s += " = ";
296 else if (rightTailButton->isChecked())
297 s += " <= ";
298 else if (leftTailButton->isChecked())
299 s += " >= ";
300
301 meanLabel->setText(s);
302 }
303
updateMeanLabels(double val)304 void StudentTestDialog::updateMeanLabels(double val)
305 {
306 ApplicationWindow *app = (ApplicationWindow *)parent();
307 QString s = app->locale().toString(val, 'g', app->d_decimal_digits);
308 leftTailLabel->setText(s);
309 rightTailLabel->setText(s);
310 bothTailLabel->setText(s);
311 }
312
accept()313 void StudentTestDialog::accept()
314 {
315 if (d_test_type == StatisticTest::ChiSquareTest)
316 acceptChiSquareTest();
317 else if (d_test_type == StatisticTest::StudentTest)
318 acceptStudentTest();
319 }
320
acceptStudentTest()321 void StudentTestDialog::acceptStudentTest()
322 {
323 ApplicationWindow *app = (ApplicationWindow *)parent();
324
325 tTest stats(app, boxMean->value(), boxSignificance->value());
326 if (!stats.setData(boxSample1->currentText()))
327 return;
328
329 if (d_two_samples){
330 if (!stats.setSample2(boxSample2->currentText(), pairedTestBtn->isChecked()))
331 return;
332 }
333
334 StatisticTest::Tail tail = StatisticTest::Left;
335 if (bothTailButton->isChecked())
336 tail = StatisticTest::Both;
337 else if (rightTailButton->isChecked())
338 tail = StatisticTest::Right;
339 stats.setTail(tail);
340
341 stats.showDescriptiveStatistics(showStatisticsBox->isEnabled() && showStatisticsBox->isChecked());
342
343 int p = app->d_decimal_digits;
344 QLocale l = app->locale();
345
346 QString sep = "\t\t";
347 QString sep1 = "-----------------------------------------------------------------------------------------------------------------------------\n";
348 QString s = stats.logInfo();
349
350 if (boxConfidenceInterval->isChecked()){
351 QGridLayout *gl = (QGridLayout *)boxConfidenceInterval->layout();
352 int rows = gl->rowCount();
353
354 s += "\n";
355 if (d_two_samples)
356 s += tr("Confidence Interval for Difference of Means");
357 else
358 s += tr("Confidence Interval for Mean");
359 s += "\n\n";
360 s += tr("Level") + sep + tr("Lower Limit") + sep + tr("Upper Limit") + "\n";
361 s += sep1;
362 for (int i = 0; i < rows; i++){
363 DoubleSpinBox *sb = (DoubleSpinBox *)gl->itemAtPosition (i, 1)->widget();
364 double level = sb->value();
365 s += l.toString(level) + sep + l.toString(stats.lcl(level), 'g', p);
366 s += sep + l.toString(stats.ucl(level),'g', p) + "\n";
367 }
368 s += sep1;
369 }
370
371 if (boxPowerAnalysis->isChecked()){
372 double power = stats.power(boxPowerLevel->value());
373 s += "\n" + tr("Power Analysis") + "\n\n";
374 s += tr("Alpha") + sep + tr("Sample Size") + sep + tr("Power") + "\n";
375 s += sep1;
376 s += l.toString(boxPowerLevel->value(), 'g', 6) + sep + QString::number(stats.dataSize()) + sep + l.toString(power, 'g', p) + " (" + tr("actual") + ")\n";
377 if (!d_two_samples && boxOtherSampleSize->isChecked()){
378 int size = boxSampleSize->value();
379 power = stats.power(boxPowerLevel->value(), size);
380 s += l.toString(boxPowerLevel->value(), 'g', 6) + sep + QString::number(size) + sep + l.toString(power, 'g', p) + "\n";
381 }
382 s += sep1;
383 }
384
385 outputResults(&stats, s);
386 }
387
acceptChiSquareTest()388 void StudentTestDialog::acceptChiSquareTest()
389 {
390 ApplicationWindow *app = (ApplicationWindow *)parent();
391
392 ChiSquareTest stats(app, boxMean->value(), boxSignificance->value());
393 if (!stats.setData(boxSample1->currentText()))
394 return;
395
396 StatisticTest::Tail tail = StatisticTest::Left;
397 if (bothTailButton->isChecked())
398 tail = StatisticTest::Both;
399 else if (rightTailButton->isChecked())
400 tail = StatisticTest::Right;
401
402 stats.setTail(tail);
403 stats.showDescriptiveStatistics(showStatisticsBox->isEnabled() && showStatisticsBox->isChecked());
404
405 int p = app->d_decimal_digits;
406 QLocale l = app->locale();
407
408 QString sep = "\t\t";
409 QString sep1 = "-----------------------------------------------------------------------------------------------------------------------------\n";
410 QString s = stats.logInfo();
411
412 if (boxConfidenceInterval->isChecked()){
413 QGridLayout *gl = (QGridLayout *)boxConfidenceInterval->layout();
414 int rows = gl->rowCount();
415
416 s += "\n";
417 s += tr("Confidence Intervals for Variance");
418 s += "\n\n";
419 s += tr("Level") + sep + tr("Lower Limit") + sep + tr("Upper Limit") + "\n";
420 s += sep1;
421 for (int i = 0; i < rows; i++){
422 DoubleSpinBox *sb = (DoubleSpinBox *)gl->itemAtPosition (i, 1)->widget();
423 double level = sb->value();
424 s += l.toString(level) + sep + l.toString(stats.lcl(level), 'g', p);
425 s += sep + l.toString(stats.ucl(level),'g', p) + "\n";
426 }
427 s += sep1;
428 }
429
430 outputResults(&stats, s);
431 }
432
outputResults(StatisticTest * stats,const QString & s)433 void StudentTestDialog::outputResults(StatisticTest* stats, const QString& s)
434 {
435 if (!stats)
436 return;
437
438 ApplicationWindow *app = (ApplicationWindow *)parent();
439 if (boxResultsLog->isChecked())
440 app->updateLog(s);
441
442 if (boxResultsTable->isChecked()){
443 QString name = tableNameLineEdit->text();
444 if (!d_table)
445 d_table = stats->resultTable(name);
446 else {
447 if (d_table->objectName() != name){
448 Table *t = app->table(name);
449 if (t){
450 d_table = t;
451 stats->outputResultsTo(d_table);
452 } else
453 d_table = stats->resultTable(name);
454 } else
455 stats->outputResultsTo(d_table);
456 }
457
458 if (d_table && name.isEmpty())
459 tableNameLineEdit->setText(d_table->objectName());
460 }
461
462 if (boxNoteWindow->isChecked()){
463 QString name = noteNameLineEdit->text();
464 if (!d_note){
465 d_note = app->newNote(name);
466 d_note->setText(s);
467 } else {
468 if (d_note->objectName() != name){
469 Note *n = qobject_cast<Note *>(app->window(name));
470 if (n){
471 d_note = n;
472 d_note->currentEditor()->append(s);
473 } else {
474 d_note = app->newNote(name);
475 d_note->setText(s);
476 }
477 } else
478 d_note->currentEditor()->append(s);
479 }
480
481 if (d_note && name.isEmpty())
482 noteNameLineEdit->setText(d_note->objectName());
483 }
484 }
485
closeEvent(QCloseEvent * e)486 void StudentTestDialog::closeEvent(QCloseEvent* e)
487 {
488 ApplicationWindow *app = (ApplicationWindow *)this->parent();
489 if (app){
490 app->d_stats_significance_level = boxSignificance->value();
491 app->d_stats_result_table = boxResultsTable->isChecked();
492 app->d_stats_result_log = boxResultsLog->isChecked();
493 app->d_stats_result_notes = boxNoteWindow->isChecked();
494 app->d_descriptive_stats = showStatisticsBox->isChecked();
495 app->d_stats_output = outputSettingsBox->isChecked();
496 app->d_stats_confidence = boxConfidenceInterval->isChecked();
497 if (d_test_type == StatisticTest::StudentTest)
498 app->d_stats_power = boxPowerAnalysis->isChecked();
499 }
500
501 e->accept();
502 }
503