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