Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / StatisticsDialogs / AnalysisOfVarianceDialog.cxx
bloba764c1397321cdc2598aa0903d005cbdcd0d41f3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <sfx2/dispatch.hxx>
12 #include <svl/zforlist.hxx>
13 #include <svl/undo.hxx>
15 #include "formulacell.hxx"
16 #include "rangelst.hxx"
17 #include "scitems.hxx"
18 #include "docsh.hxx"
19 #include "document.hxx"
20 #include "uiitems.hxx"
21 #include "reffact.hxx"
22 #include "strload.hxx"
23 #include "docfunc.hxx"
24 #include "StatisticsDialogs.hrc"
25 #include "TableFillingAndNavigationTools.hxx"
27 #include "AnalysisOfVarianceDialog.hxx"
29 namespace
32 struct StatisticCalculation {
33 sal_Int16 aLabelId;
34 const char* aFormula;
35 const char* aResultRangeName;
38 static StatisticCalculation lclBasicStatistics[] =
40 { STR_ANOVA_LABEL_GROUPS, NULL, NULL },
41 { STRID_CALC_COUNT, "=COUNT(%RANGE%)", "COUNT_RANGE" },
42 { STRID_CALC_SUM, "=SUM(%RANGE%)", "SUM_RANGE" },
43 { STRID_CALC_MEAN, "=AVERAGE(%RANGE%)", "MEAN_RANGE" },
44 { STRID_CALC_VARIANCE, "=VAR(%RANGE%)", "VAR_RANGE" },
45 { 0, NULL, NULL }
48 static sal_Int16 lclAnovaLabels[] =
50 STR_ANOVA_LABEL_SOURCE_OF_VARIATION,
51 STR_ANOVA_LABEL_SS,
52 STR_ANOVA_LABEL_DF,
53 STR_ANOVA_LABEL_MS,
54 STR_ANOVA_LABEL_F,
55 STR_ANOVA_LABEL_P_VALUE,
56 STR_ANOVA_LABEL_F_CRITICAL,
60 static const OUString strWildcardRange("%RANGE%");
61 static const OUString strWildcardNumber("%NUMBER%");
63 OUString lclCreateMultiParameterFormula(
64 ScRangeList& aRangeList, const OUString& aFormulaTemplate,
65 const OUString& aWildcard, ScDocument* pDocument,
66 ScAddress::Details& aAddressDetails)
68 OUString aResult;
69 for (size_t i = 0; i < aRangeList.size(); i++)
71 OUString aRangeString(aRangeList[i]->Format(SCR_ABS, pDocument, aAddressDetails));
72 OUString aFormulaString = aFormulaTemplate.replaceAll(aWildcard, aRangeString);
73 aResult += aFormulaString;
74 if(i != aRangeList.size() - 1) // Not Last
75 aResult+= ";";
77 return aResult;
80 void lclMakeSubRangesList(ScRangeList& rRangeList, ScRange& rInputRange, ScStatisticsInputOutputDialog::GroupedBy aGroupedBy)
82 boost::scoped_ptr<DataRangeIterator> pIterator;
83 if (aGroupedBy == ScStatisticsInputOutputDialog::BY_COLUMN)
84 pIterator.reset(new DataRangeByColumnIterator(rInputRange));
85 else
86 pIterator.reset(new DataRangeByRowIterator(rInputRange));
88 for( ; pIterator->hasNext(); pIterator->next() )
90 ScRange aRange = pIterator->get();
91 rRangeList.Append(aRange);
97 ScAnalysisOfVarianceDialog::ScAnalysisOfVarianceDialog(
98 SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
99 Window* pParent, ScViewData* pViewData ) :
100 ScStatisticsInputOutputDialog(
101 pSfxBindings, pChildWindow, pParent, pViewData,
102 "AnalysisOfVarianceDialog", "modules/scalc/ui/analysisofvariancedialog.ui" ),
103 meFactor(SINGLE_FACTOR)
105 get(mpAlphaField, "alpha-spin");
106 get(mpSingleFactorRadio, "radio-single-factor");
107 get(mpTwoFactorRadio, "radio-two-factor");
108 get(mpRowsPerSampleField, "rows-per-sample-spin");
110 mpSingleFactorRadio->SetToggleHdl( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
111 mpTwoFactorRadio->SetToggleHdl( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
113 mpSingleFactorRadio->Check(true);
114 mpTwoFactorRadio->Check(false);
116 FactorChanged(NULL);
119 ScAnalysisOfVarianceDialog::~ScAnalysisOfVarianceDialog()
122 bool ScAnalysisOfVarianceDialog::Close()
124 return DoClose( ScAnalysisOfVarianceDialogWrapper::GetChildWindowId() );
127 sal_Int16 ScAnalysisOfVarianceDialog::GetUndoNameId()
129 return STR_ANALYSIS_OF_VARIANCE_UNDO_NAME;
132 IMPL_LINK_NOARG( ScAnalysisOfVarianceDialog, FactorChanged )
134 if (mpSingleFactorRadio->IsChecked())
136 mpGroupByRowsRadio->Enable(true);
137 mpGroupByColumnsRadio->Enable(true);
138 mpRowsPerSampleField->Enable(false);
139 meFactor = SINGLE_FACTOR;
141 else if (mpTwoFactorRadio->IsChecked())
143 mpGroupByRowsRadio->Enable(false);
144 mpGroupByColumnsRadio->Enable(false);
145 mpRowsPerSampleField->Enable(false); // Rows per sample not yet implemented
146 meFactor = TWO_FACTOR;
149 return 0;
152 void ScAnalysisOfVarianceDialog::RowColumn(ScRangeList& rRangeList, AddressWalkerWriter& aOutput, FormulaTemplate& aTemplate,
153 OUString& sFormula, GroupedBy aGroupedBy, ScRange* pResultRange)
155 if (pResultRange != NULL)
156 pResultRange->aStart = aOutput.current();
157 if (!sFormula.isEmpty())
159 for (size_t i = 0; i < rRangeList.size(); i++)
161 ScRange* pRange = rRangeList[i];
162 aTemplate.setTemplate(sFormula);
163 aTemplate.applyRange(strWildcardRange, *pRange);
164 aOutput.writeFormula(aTemplate.getTemplate());
165 if (pResultRange != NULL)
166 pResultRange->aEnd = aOutput.current();
167 aOutput.nextRow();
170 else
172 sal_Int16 aLabelId = (aGroupedBy == BY_COLUMN) ? STR_COLUMN_LABEL_TEMPLATE : STR_ROW_LABEL_TEMPLATE;
173 OUString aLabelTemplate(SC_STRLOAD(RID_STATISTICS_DLGS, aLabelId));
175 for (size_t i = 0; i < rRangeList.size(); i++)
177 aTemplate.setTemplate(aLabelTemplate);
178 aTemplate.applyNumber(strWildcardNumber, i + 1);
179 aOutput.writeString(aTemplate.getTemplate());
180 if (pResultRange != NULL)
181 pResultRange->aEnd = aOutput.current();
182 aOutput.nextRow();
187 void ScAnalysisOfVarianceDialog::AnovaSingleFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
189 output.writeBoldString(SC_STRLOAD(RID_STATISTICS_DLGS, STR_ANOVA_SINGLE_FACTOR_LABEL));
190 output.newLine();
192 double aAlphaValue = mpAlphaField->GetValue() / 100.0;
193 output.writeString("Alpha");
194 output.nextColumn();
195 output.writeValue(aAlphaValue);
196 aTemplate.autoReplaceAddress("%ALPHA%", output.current());
197 output.newLine();
198 output.newLine();
200 // Write labels
201 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId != 0; i++)
203 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, lclBasicStatistics[i].aLabelId));
204 output.nextColumn();
206 output.newLine();
208 // Collect aRangeList
209 ScRangeList aRangeList;
210 lclMakeSubRangesList(aRangeList, mInputRange, mGroupedBy);
212 output.push();
214 // Write values
215 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId != 0; i++)
217 output.resetRow();
218 ScRange aResultRange;
219 OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
220 RowColumn(aRangeList, output, aTemplate, sFormula, mGroupedBy, &aResultRange);
221 output.nextColumn();
222 if (lclBasicStatistics[i].aResultRangeName != NULL)
224 OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
225 aTemplate.autoReplaceRange("%" + sResultRangeName + "%", aResultRange);
229 output.nextRow(); // Blank row
231 // Write ANOVA labels
232 output.resetColumn();
233 for(sal_Int32 i = 0; lclAnovaLabels[i] != 0; i++)
235 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, lclAnovaLabels[i]));
236 output.nextColumn();
238 output.nextRow();
240 aTemplate.autoReplaceRange("%FIRST_COLUMN%", *aRangeList[0]);
242 // Between Groups
244 // Label
245 output.resetColumn();
246 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, STR_ANOVA_LABEL_BETWEEN_GROUPS));
247 output.nextColumn();
249 // Sum of Squares
251 aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE%;%MEAN_RANGE%)-SUM(%SUM_RANGE%)^2/SUM(%COUNT_RANGE%)");
252 aTemplate.autoReplaceAddress("%BETWEEN_SS%", output.current());
253 output.writeFormula(aTemplate.getTemplate());
254 output.nextColumn();
256 // Degree of freedom
257 aTemplate.setTemplate("=COUNT(%SUM_RANGE%)-1");
258 aTemplate.autoReplaceAddress("%BETWEEN_DF%", output.current());
259 output.writeFormula(aTemplate.getTemplate());
260 output.nextColumn();
262 // MS
263 aTemplate.setTemplate("=%BETWEEN_SS% / %BETWEEN_DF%");
264 aTemplate.autoReplaceAddress("%BETWEEN_MS%", output.current());
265 output.writeFormula(aTemplate.getTemplate());
266 output.nextColumn();
268 // F
269 aTemplate.setTemplate("=%BETWEEN_MS% / %WITHIN_MS%");
270 aTemplate.applyAddress("%WITHIN_MS%", output.current(-1, 1));
271 aTemplate.autoReplaceAddress("%F_VAL%", output.current());
272 output.writeFormula(aTemplate.getTemplate());
273 output.nextColumn();
275 // P-value
276 aTemplate.setTemplate("=FDIST(%F_VAL%; %BETWEEN_DF%; %WITHIN_DF%");
277 aTemplate.applyAddress("%WITHIN_DF%", output.current(-3, 1));
278 output.writeFormula(aTemplate.getTemplate());
279 output.nextColumn();
281 // F critical
282 aTemplate.setTemplate("=FINV(%ALPHA%; %BETWEEN_DF%; %WITHIN_DF%");
283 aTemplate.applyAddress("%WITHIN_DF%", output.current(-4, 1));
284 output.writeFormula(aTemplate.getTemplate());
286 output.nextRow();
288 // Within Groups
290 // Label
291 output.resetColumn();
292 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, STR_ANOVA_LABEL_WITHIN_GROUPS));
293 output.nextColumn();
295 // Sum of Squares
296 OUString aSSPart = lclCreateMultiParameterFormula(aRangeList, OUString("DEVSQ(%RANGE%)"), strWildcardRange, mDocument, mAddressDetails);
297 aTemplate.setTemplate("=SUM(%RANGE%)");
298 aTemplate.applyString(strWildcardRange, aSSPart);
299 aTemplate.autoReplaceAddress("%WITHIN_SS%", output.current());
300 output.writeFormula(aTemplate.getTemplate());
301 output.nextColumn();
303 // Degree of freedom
304 aTemplate.setTemplate("=SUM(%COUNT_RANGE%)-COUNT(%COUNT_RANGE%)");
305 aTemplate.autoReplaceAddress("%WITHIN_DF%", output.current());
306 output.writeFormula(aTemplate.getTemplate());
307 output.nextColumn();
309 // MS
310 aTemplate.setTemplate("=%WITHIN_SS% / %WITHIN_DF%");
311 output.writeFormula(aTemplate.getTemplate());
313 output.nextRow();
315 // Total
317 // Label
318 output.resetColumn();
319 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, STR_ANOVA_LABEL_TOTAL));
320 output.nextColumn();
322 // Sum of Squares
323 aTemplate.setTemplate("=DEVSQ(%RANGE_LIST%)");
324 aTemplate.applyRangeList("%RANGE_LIST%", aRangeList);
325 output.writeFormula(aTemplate.getTemplate());
326 output.nextColumn();
328 // Degree of freedom
329 aTemplate.setTemplate("=SUM(%COUNT_RANGE%) - 1");
330 output.writeFormula(aTemplate.getTemplate());
332 output.nextRow();
335 void ScAnalysisOfVarianceDialog::AnovaTwoFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
337 output.writeBoldString(SC_STRLOAD(RID_STATISTICS_DLGS, STR_ANOVA_TWO_FACTOR_LABEL));
338 output.newLine();
340 double aAlphaValue = mpAlphaField->GetValue() / 100.0;
341 output.writeString("Alpha");
342 output.nextColumn();
343 output.writeValue(aAlphaValue);
344 aTemplate.autoReplaceAddress("%ALPHA%", output.current());
345 output.newLine();
346 output.newLine();
348 // Write labels
349 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId != 0; i++)
351 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, lclBasicStatistics[i].aLabelId));
352 output.nextColumn();
354 output.newLine();
356 ScRangeList aColumnRangeList;
357 ScRangeList aRowRangeList;
359 lclMakeSubRangesList(aColumnRangeList, mInputRange, BY_COLUMN);
360 lclMakeSubRangesList(aRowRangeList, mInputRange, BY_ROW);
362 // Write ColumnX values
363 output.push();
364 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId != 0; i++)
366 output.resetRow();
367 ScRange aResultRange;
368 OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
369 RowColumn(aColumnRangeList, output, aTemplate, sFormula, BY_COLUMN, &aResultRange);
370 if (lclBasicStatistics[i].aResultRangeName != NULL)
372 OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
373 aTemplate.autoReplaceRange("%" + sResultRangeName + "_COLUMN%", aResultRange);
375 output.nextColumn();
377 output.newLine();
379 // Write RowX values
380 output.push();
381 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId != 0; i++)
383 output.resetRow();
384 ScRange aResultRange;
385 OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
386 RowColumn(aRowRangeList, output, aTemplate, sFormula, BY_ROW, &aResultRange);
388 if (lclBasicStatistics[i].aResultRangeName != NULL)
390 OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
391 aTemplate.autoReplaceRange("%" + sResultRangeName + "_ROW%", aResultRange);
393 output.nextColumn();
395 output.newLine();
397 // Write ANOVA labels
398 for(sal_Int32 i = 0; lclAnovaLabels[i] != 0; i++)
400 output.writeString(SC_STRLOAD(RID_STATISTICS_DLGS, lclAnovaLabels[i]));
401 output.nextColumn();
403 output.nextRow();
405 // Setup auto-replace strings
406 aTemplate.autoReplaceRange(strWildcardRange, mInputRange);
407 aTemplate.autoReplaceRange("%FIRST_COLUMN%", *aColumnRangeList[0]);
408 aTemplate.autoReplaceRange("%FIRST_ROW%", *aRowRangeList[0]);
410 // Rows
412 // Label
413 output.resetColumn();
414 output.writeString("Rows");
415 output.nextColumn();
417 // Sum of Squares
418 aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
419 aTemplate.autoReplaceAddress("%ROW_SS%", output.current());
420 output.writeFormula(aTemplate.getTemplate());
421 output.nextColumn();
423 // Degree of freedom
424 aTemplate.setTemplate("=MAX(%COUNT_RANGE_COLUMN%) - 1");
425 aTemplate.autoReplaceAddress("%ROW_DF%", output.current());
426 output.writeFormula(aTemplate.getTemplate());
427 output.nextColumn();
429 // MS
430 aTemplate.setTemplate("=%ROW_SS% / %ROW_DF%");
431 aTemplate.autoReplaceAddress("%MS_ROW%", output.current());
432 output.writeFormula(aTemplate.getTemplate());
433 output.nextColumn();
435 // F
436 aTemplate.setTemplate("=%MS_ROW% / %MS_ERROR%");
437 aTemplate.applyAddress("%MS_ERROR%", output.current(-1, 2));
438 aTemplate.autoReplaceAddress("%F_ROW%", output.current());
439 output.writeFormula(aTemplate.getTemplate());
440 output.nextColumn();
442 // P-value
443 aTemplate.setTemplate("=FDIST(%F_ROW%; %ROW_DF%; %ERROR_DF%");
444 aTemplate.applyAddress("%ERROR_DF%", output.current(-3, 2));
445 output.writeFormula(aTemplate.getTemplate());
446 output.nextColumn();
448 // F critical
449 aTemplate.setTemplate("=FINV(%ALPHA%; %ROW_DF%; %ERROR_DF%");
450 aTemplate.applyAddress("%ERROR_DF%", output.current(-4, 2));
451 output.writeFormula(aTemplate.getTemplate());
452 output.nextColumn();
454 output.nextRow();
456 // Columns
458 // Label
459 output.resetColumn();
460 output.writeString("Columns");
461 output.nextColumn();
463 // Sum of Squares
464 aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
465 aTemplate.autoReplaceAddress("%COLUMN_SS%", output.current());
466 output.writeFormula(aTemplate.getTemplate());
467 output.nextColumn();
469 // Degree of freedom
470 aTemplate.setTemplate("=MAX(%COUNT_RANGE_ROW%) - 1");
471 aTemplate.autoReplaceAddress("%COLUMN_DF%", output.current());
472 output.writeFormula(aTemplate.getTemplate());
473 output.nextColumn();
475 // MS
476 aTemplate.setTemplate("=%COLUMN_SS% / %COLUMN_DF%");
477 aTemplate.autoReplaceAddress("%MS_COLUMN%", output.current());
478 output.writeFormula(aTemplate.getTemplate());
479 output.nextColumn();
481 // F
482 aTemplate.setTemplate("=%MS_COLUMN% / %MS_ERROR%");
483 aTemplate.applyAddress("%MS_ERROR%", output.current(-1, 1));
484 aTemplate.autoReplaceAddress("%F_COLUMN%", output.current());
485 output.writeFormula(aTemplate.getTemplate());
486 output.nextColumn();
488 // P-value
489 aTemplate.setTemplate("=FDIST(%F_COLUMN%; %COLUMN_DF%; %ERROR_DF%");
490 aTemplate.applyAddress("%ERROR_DF%", output.current(-3, 1));
491 output.writeFormula(aTemplate.getTemplate());
492 output.nextColumn();
494 // F critical
495 aTemplate.setTemplate("=FINV(%ALPHA%; %COLUMN_DF%; %ERROR_DF%");
496 aTemplate.applyAddress("%ERROR_DF%", output.current(-4, 1));
497 output.writeFormula(aTemplate.getTemplate());
498 output.nextColumn();
500 output.nextRow();
502 // Error
504 // Label
505 output.resetColumn();
506 output.writeString("Error");
507 output.nextColumn();
509 // Sum of Squares
510 aTemplate.setTemplate("=SUMSQ(%RANGE%)+SUM(%RANGE%)^2/COUNT(%RANGE%) - (SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) + SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%))");
511 aTemplate.autoReplaceAddress("%ERROR_SS%", output.current());
512 output.writeFormula(aTemplate.getTemplate());
513 output.nextColumn();
515 // Degree of freedom
516 aTemplate.setTemplate("=%TOTAL_DF% - %ROW_DF% - %COLUMN_DF%");
517 aTemplate.applyAddress("%TOTAL_DF%", output.current(0,1,0));
518 aTemplate.autoReplaceAddress("%ERROR_DF%", output.current());
519 output.writeFormula(aTemplate.getTemplate());
520 output.nextColumn();
522 // MS
523 aTemplate.setTemplate("=%ERROR_SS% / %ERROR_DF%");
524 output.writeFormula(aTemplate.getTemplate());
526 output.nextRow();
528 // Total
530 // Label
531 output.resetColumn();
532 output.writeString("Total");
533 output.nextColumn();
535 // Sum of Squares
536 aTemplate.setTemplate("=SUM(%ROW_SS%;%COLUMN_SS%;%ERROR_SS%)");
537 output.writeFormula(aTemplate.getTemplate());
538 output.nextColumn();
540 // Degree of freedom
541 aTemplate.setTemplate("=COUNT(%RANGE%)-1");
542 output.writeFormula(aTemplate.getTemplate());
543 output.nextColumn();
547 ScRange ScAnalysisOfVarianceDialog::ApplyOutput(ScDocShell* pDocShell)
549 AddressWalkerWriter output(mOutputAddress, pDocShell, mDocument,
550 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
551 FormulaTemplate aTemplate(mDocument);
553 if (meFactor == SINGLE_FACTOR)
555 AnovaSingleFactor(output, aTemplate);
557 else if (meFactor == TWO_FACTOR)
559 AnovaTwoFactor(output, aTemplate);
562 return ScRange(output.mMinimumAddress, output.mMaximumAddress);
565 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */