Files
lazarus-ccr/applications/lazstats/source/forms/analysis/comparisons/onecaseanovaunit.pas

2479 lines
78 KiB
ObjectPascal
Raw Normal View History

unit OneCaseANOVAUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, ExtCtrls, ComCtrls,
TASources, TACustomSeries, TAStyles,
MainUnit, Globals, DataProcs, GraphLib,
ANOVATestsUnit, BasicStatsReportAndChartFormUnit;
type
{ TOneCaseAnovaForm }
TOneCaseAnovaForm = class(TBasicStatsReportAndChartForm)
DepIn: TBitBtn;
DepOut: TBitBtn;
DepVarEdit: TEdit;
Fact1In: TBitBtn;
Fact1Out: TBitBtn;
Fact2In: TBitBtn;
Fact2Out: TBitBtn;
Fact3In: TBitBtn;
Fact3Out: TBitBtn;
Factor1Edit: TEdit;
Factor2Edit: TEdit;
Factor3Edit: TEdit;
PostHocGroup: TGroupBox;
InteractChk: TCheckBox;
Label1: TLabel;
Label3: TLabel;
Label4: TLabel;
NewmanKeulsChk: TCheckBox;
OverAllAlphaEdit: TEdit;
PostAlphaEdit: TEdit;
ScheffeChk: TCheckBox;
StaticText1: TStaticText;
StaticText2: TStaticText;
StaticText3: TStaticText;
StaticText4: TStaticText;
TukeyBChk: TCheckBox;
TukeyHSDChk: TCheckBox;
TukeyKramerChk: TCheckBox;
VarList: TListBox;
procedure DepInClick(Sender: TObject);
procedure DepOutClick(Sender: TObject);
procedure Fact1InClick(Sender: TObject);
procedure Fact1OutClick(Sender: TObject);
procedure Fact2InClick(Sender: TObject);
procedure Fact2OutClick(Sender: TObject);
procedure Fact3InClick(Sender: TObject);
procedure Fact3OutClick(Sender: TObject);
procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
private
{ private declarations }
N: integer;
ColNoSelected: IntDyneVec;
Nf1cells, Nf2cells, Nf3cells, TotalCells: integer;
minf1, maxf1, minf2, maxf2, minf3, maxf3, nofactors: integer;
NoGrpsA, NoGrpsB, NoGrpsC: integer;
SSDep, SSErr, SSF1, SSF2, SSF3, SSF1F2, SSF1F3, SSF2F3, SSF1F2F3: double;
MSDep, MSErr, MSF1, MSF2, MSF3, MSF1F2, MSF1F3, MSF2F3: double;
DFTot, DFErr, DFF1, DFF2, DFF3, DFF1F2, DFF1F3, DFF2F3: double;
Omega, OmegaF1, OmegaF2, OmegaF3, OmegaF1F2: double;
OmegaF1F3, OmegaF2F3: double;
FF1, FF2, FF1F2, ProbF1, ProbF2, ProbF3, ProbF1F2, ProbF1F3: double;
FF3, FF2F3, FF1F3, ProbF2F3: double;
MeanDep, MeanF1, MeanF2, MeanF3: double;
SSNonAdd, SSBalance,MSNonAdd, MSBalance, GrandMean, DFBalance: double;
FNonAdd, ProbNonAdd: double;
cellcnts : IntDyneVec; // array of cell counts
cellvars : DblDyneVec; // arrray of cell sums of squares then variances
cellsums : DblDyneVec; // array of cell sums then means
counts : IntDyneMat; // matrix for 2-way containing cell sizes
sums : DblDyneMat; // matrix for 2-way containing cell sums
vars : DblDyneMat; // matrix for 2-way containing sums of squares
RowSums : DblDyneVec; // 2 way row sums
ColSums : DblDyneVec; // 2 way col sums
RowCount : IntDyneVec; // 2 way row count
ColCount : IntDyneVec; // 2 way col count
SlcSums : DblDyneVec; // 3 way slice sums
SlcCount : IntDyneVec; // 3 way slice counts
OrdMeansA, OrdMeansB, OrdMeansC : DblDyneVec; // reordered means for f1, f2, f3
DepValues: DblDyneVec;
F1Values, F2Values, F3Values: DblDyneVec; // ToDo: Make them a StrDyneVec
// F1Labels, F2Labels, F3Labels: StrDyneVec;
OverAll, PostHocAlpha : double; // alphas for tests
wsum, wx2: DblDyneCube;
ncnt : IntDyneCube;
CompError : boolean;
equal_grp : boolean; // check for equal groups for post-hoc tests
comparisons : boolean;
// interacts : boolean; // true if 2 way interactions to be included in 3 way design
procedure Init;
procedure GetLevels;
function Calc2Way: Boolean;
procedure TwoWayTable(AReport: TStrings);
procedure TwoWayContrasts(AReport: TStrings);
procedure TwoWayPlot;
function Calc3Way: Boolean;
procedure ThreeWayTable(AReport: TStrings);
procedure ThreeWayContrasts(AReport: TStrings);
procedure ThreeWayPlot;
private
FSeries: TChartSeries;
FChartCombobox: TCombobox;
FStyles: TChartStyles;
procedure GetDataIndices(out ix, iy, iz: Integer);
procedure PopulateChartCombobox(ThreeWay: Boolean);
procedure SelectTwoWayPlot(Sender: TObject);
procedure SelectThreeWayPlot(Sender: TObject);
protected
procedure AdjustConstraints; override;
procedure Compute; override;
procedure UpdateBtnStates; override;
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
public
constructor Create(AOwner: TComponent); override;
procedure Reset; override;
end;
var
OneCaseAnovaForm: TOneCaseAnovaForm;
implementation
{$R *.lfm}
uses
Math,
TACustomSource, TASeries, TALegend, TAChartUtils,
Utils, MathUnit, MatrixUnit, GridProcs, ChartFrameUnit;
{ TOneCaseAnovaForm }
constructor TOneCaseAnovaForm.Create(AOwner: TComponent);
var
panel: TPanel;
lbl: TLabel;
begin
inherited;
if GraphFrm = nil then
Application.CreateForm(TGraphFrm, GraphFrm);
OverAllAlphaEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
PostAlphaEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
FStyles := TChartStyles.Create(FChartFrame);
panel := TPanel.Create(FChartFrame.ChartToolbar);
lbl := TLabel.Create(panel);
lbl.Parent := panel;
lbl.Caption := 'Plots:';
FChartCombobox := TCombobox.Create(panel);
FChartCombobox.Parent := panel;
FChartCombobox.Style := csDropdownList;
FChartCombobox.DropdownCount := 24;
FChartCombobox.Items.Clear;
FChartCombobox.Constraints.MinWidth := 300;
lbl.AnchorSideLeft.Side := asrTop;
lbl.AnchorSideLeft.Control := panel;
lbl.AnchorSideTop.Side := asrCenter;
lbl.AnchorSideTop.Control := FChartCombobox;
FChartCombobox.AnchorSideLeft.Control := lbl;
FChartCombobox.AnchorSideLeft.Side := asrBottom;
FChartCombobox.BorderSpacing.Left := 6;
FChartCombobox.BorderSpacing.Around := 2;
panel.Parent := FChartFrame.ChartToolbar;
panel.AutoSize := true;
panel.BevelInner := bvNone;
panel.BevelOuter := bvNone;
end;
procedure TOneCaseAnovaForm.AdjustConstraints;
begin
inherited;
ParamsPanel.Constraints.MinHeight := InteractChk.Top + InteractChk.Height +
PostHocGroup.BorderSpacing.Top + PostHocGroup.Height + PostHocGroup.BorderSpacing.Bottom +
PostAlphaEdit.Height + ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
ParamsPanel.Constraints.MinWidth := Max(
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
PostHocGroup.Width
);
FChartFrame.ChartToolbar.ButtonHeight := Max(
FChartFrame.ChartToolbar.ButtonHeight,
FChartCombobox.Height + 2*FChartCombobox.BorderSpacing.Around
);
end;
procedure TOneCaseAnovaForm.Reset;
var
i: integer;
begin
inherited;
VarList.Clear;
DepVarEdit.Text := '';
Factor1Edit.Text := '';
Factor2Edit.Text := '';
Factor3Edit.Text := '';
//PlotMeans.Checked := false;
ScheffeChk.Checked := false;
TukeyHSDChk.Checked := false;
TukeyBChk.Checked := false;
TukeyKramerChk.Checked := false;
NewmanKeulsChk.Checked := false;
// BonferroniChk.Checked := false;
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.DepInClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (DepVarEdit.Text = '') then
begin
DepVarEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.DepOutClick(Sender: TObject);
begin
if DepVarEdit.Text <> '' then
begin
VarList.Items.Add(DepVarEdit.Text);
DepVarEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Fact1InClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (Factor1Edit.Text = '') then
begin
Factor1Edit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Fact1OutClick(Sender: TObject);
begin
if Factor1Edit.Text <> '' then
begin
VarList.Items.Add(Factor1Edit.Text);
Factor1Edit.Text := '';
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Fact2InClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (Factor2Edit.Text = '') then
begin
Factor2Edit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Fact2OutClick(Sender: TObject);
begin
if Factor2Edit.Text <> '' then
begin
VarList.Items.Add(Factor2Edit.Text);
Factor2Edit.Text := '';
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Fact3InClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (Factor3Edit.Text = '') then
begin
Factor3Edit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Fact3OutClick(Sender: TObject);
begin
if Factor3Edit.Text <> '' then
begin
VarList.Items.Add(Factor3Edit.Text);
Factor3Edit.Text := '';
end;
UpdateBtnStates;
end;
procedure TOneCaseAnovaForm.Compute;
var
lReport: TStrings;
msg: String;
C: TWinControl;
begin
if Factor3Edit.Text = '' then
NoFactors := 2
else
NoFactors := 3;
// initialize values
Init;
// get min and max of each factor code
GetLevels;
// Analysis
case NoFactors of
2 : begin // two-way anova
SetLength(counts, Nf1cells, Nf2cells); // matrix for 2-way containing cell sizes
SetLength(sums, Nf1cells, Nf2cells); // matrix for 2-way containing cell sums
SetLength(vars, Nf1cells, Nf2cells); // matrix for 2-way containing sums of squares
SetLength(RowSums, Nf1cells); // 2 way row sums
SetLength(ColSums, Nf2cells); // 2 way col sums
SetLength(RowCount, Nf1cells); // 2 way row count
SetLength(ColCount, Nf2cells); // 2 way col count
SetLength(OrdMeansA, Nf1cells); // ordered means for factor 1
SetLength(OrdMeansB, Nf2cells); // ordered means for factor 2
if Calc2Way then
begin
lReport := TStringList.Create;
try
TwoWayTable(lReport);
TwoWayContrasts(lReport);
FReportFrame.DisplayReport(lReport);
TwoWayPlot;
finally
lReport.Free;
end;
end;
// vars := nil;
// sums := nil;
// counts := nil;
end;
3 : begin // three way anova
SetLength(RowSums, Nf1cells); // 2 way row sums
SetLength(ColSums, Nf2cells); // 2 way col sums
SetLength(RowCount, Nf1cells); // 2 way row count
SetLength(ColCount, Nf2cells); // 2 way col count
SetLength(SlcSums, Nf3cells); // 3 way slice sums
SetLength(SlcCount, Nf3cells); // 3 way slice counts
SetLength(OrdMeansA, Nf1cells); // ordered means for factor 1
SetLength(OrdMeansB, Nf2cells); // ordered means for factor 2
SetLength(OrdMeansC, Nf3cells); // ordered means for factor 3
SetLength(wsum, Nf1cells, Nf2cells, Nf3cells);
SetLength(wx2, Nf1cells, Nf2cells, Nf3cells);
SetLength(ncnt, Nf1cells, Nf2cells, Nf3cells);
if Calc3Way then
begin
lReport := TStringList.Create;
try
ThreeWayTable(lReport);
ThreeWayContrasts(lReport);
FReportFrame.DisplayReport(lReport);
ThreeWayPlot;
finally
lReport.Free;
end;
{
ncnt := nil;
wx2 := nil;
wsum := nil;
OrdMeansC := nil;
SlcCount := nil;
SlcSums := nil;
}
end;
end;
end; // end switch
end;
procedure TOneCaseAnovaForm.Init;
var
i: Integer;
cellstring: String;
begin
comparisons := ScheffeChk.Checked or TukeyHSDChk.Checked or
TukeyBChk.Checked or TukeyKramerChk.Checked or NewmanKeulsChk.Checked;
SSDep := 0.0;
SSF1 := 0.0;
SSF2 := 0.0;
SSF3 := 0.0;
SSF1F2 := 0.0;
SSF1F3 := 0.0;
SSF2F3 := 0.0;
SSF1F2F3 := 0.0;
MeanDep := 0.0;
MeanF1 := 0.0;
MeanF2 := 0.0;
MeanF3 := 0.0;
Nf1cells := 0;
Nf2cells := 0;
Nf3cells := 0;
//N := 0;
minf1 := 0;
maxf1 := 0;
minf2 := 0;
maxf2 := 0;
minf3 := 0;
maxf3 := 0;
// Get column numbers of dependent variable and factors
SetLength(ColNoSelected, NoFactors + 1); // +1 because DepVar is at Index 0
ColNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, DepVarEdit.Text);
ColNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, Factor1Edit.Text);
ColNoSelected[2] := GetVariableIndex(OS3MainFrm.DataGrid, Factor2Edit.Text);
if Factor3Edit.Text <> '' then
ColNoSelected[3] := GetVariableIndex(OS3MainFrm.DataGrid, Factor3Edit.Text);
OverAll := StrToFloat(OverAllAlphaEdit.Text);
PostHocAlpha := StrToFloat(PostAlphaEdit.Text);
end;
procedure TOneCaseAnovaForm.GetLevels;
var
i: integer;
intValue: Integer;
mn, mx: Double;
begin
// Extract dependent variable values
DepValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[0], ColNoSelected);
// Extract factor 1 values
F1Values := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[1], ColNoSelected);
VecMaxMin(F1Values, mx, mn);
MaxF1 := round(mx);
MinF1 := round(mn);
NF1Cells := MaxF1 - MinF1 + 1; // this can be wrong when codes are with gaps.
// Extract factor 2 values
F2Values := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[2], ColNoSelected);
VecMaxMin(F2Values, mx, mn);
MaxF2 := round(mx);
MinF2 := round(mn);
NF2Cells := MaxF2 - MinF2 + 1;
// Extract factor 3 values
if NoFactors >= 3 then
begin
F3Values := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[3], ColNoSelected);
VecMaxMin(F3Values, mx, mn);
MaxF3 := round(mx);
MinF3 := round(mn);
NF3Cells := MaxF3 - MinF2 + 1;
end else
NF3Cells := 0;
// !!!!!!!!!!! wp: the following is needed only in the *Contrasts methods --> Move to there !!!!!!!!!!!!!!!
TotalCells := NF1Cells + NF2Cells + NF3Cells;
// allocate space
SetLength(CellCnts, TotalCells); // array of cell counts
SetLength(CellVars, TotalCells); // arrray of cell sums of squares variances
SetLength(CellSums, TotalCells); // array of cell sums means
// initialize array values
for i := 0 to TotalCells-1 do
begin
CellSums[i] := 0.0;
CellVars[i] := 0.0;
CellCnts[i] := 0;
end;
end;
function TOneCaseAnovaForm.Calc2Way: Boolean;
var
i, j, grpA, grpB: integer;
Constant, RowsTotCnt, ColsTotCnt, SSCells: double;
X, Xsq, rowMean, colmean: Double;
begin
// initialize matrix values
NoGrpsA := MaxF1 - MinF1 + 1;
NoGrpsB := MaxF2 - MinF2 + 1;
for i := 0 to NoGrpsA-1 do
begin
RowSums[i] := 0.0;
RowCount[i] := 0;
for j := 0 to NoGrpsB-1 do
begin
counts[i, j] := 0;
sums[i, j] := 0.0;
vars[i, j] := 0.0;
end;
end;
for i := 0 to NoGrpsB-1 do
begin
ColCount[i] := 0;
ColSums[i] := 0.0;
end;
N := 0;
MeanDep := 0.0;
SSDep := 0.0;
SSCells := 0.0;
RowsTotCnt := 0.0;
ColsTotCnt := 0.0;
SSNonAdd := 0.0;
SSBalance := 0.0;
MSNonAdd := 0.0;
MSBalance := 0.0;
// Get working totals
for i := 0 to High(DepValues) do
begin
grpA := round(F1Values[i]) - MinF1;
grpB := round(F2Values[i]) - MinF2;
X := DepValues[i];
Xsq := X * X;
Counts[grpA, grpB] := counts[grpA, grpB] + 1;
sums[grpA, grpB] := sums[grpA, grpB] + X;
vars[grpA, grpB] := vars[grpA, grpB] + Xsq;
RowSums[grpA] := RowSums[grpA] + X;
ColSums[grpB] := ColSums[grpB] + X;
RowCount[grpA] := RowCount[grpA] + 1;
ColCount[grpB] := ColCount[grpB] + 1;
MeanDep := MeanDep + X;
SSDep := SSDep + Xsq;
N := N + 1;
end;
{
// get working totals
for i := 1 to NoCases do
begin
if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue;
grpA := floor(StrToFloat(OS3MainFrm.DataGrid.Cells[F1Col,i]));
grpB := floor(StrToFloat(OS3MainFrm.DataGrid.Cells[F2Col,i]));
X := StrToFloat(OS3MainFrm.DataGrid.Cells[DepVarCol,i]);
grpA := grpA - minf1 + 1;
grpB := grpB - minf2 + 1;
counts[grpA-1,grpB-1] := counts[grpA-1,grpB-1] + 1;
sums[grpA-1,grpB-1] := sums[grpA-1,grpB-1] + X;
vars[grpA-1,grpB-1] := vars[grpA-1,grpB-1] + X * X;
RowSums[grpA-1] := RowSums[grpA-1] + X;
ColSums[grpB-1] := ColSums[grpB-1] + X;
RowCount[grpA-1] := RowCount[grpA-1] + 1;
ColCount[grpB-1] := ColCount[grpB-1] + 1;
MeanDep := MeanDep + X;
SSDep := SSDep + X * X;
N := N + 1;
end;
}
// Calculate results
for i := 0 to NoGrpsA - 1 do
begin
SSF1 := SSF1 + sqr(RowSums[i]) / RowCount[i];
RowsTotCnt := RowsTotCnt + RowCount[i];
end;
for j := 0 to NoGrpsB - 1 do
begin
SSF2 := SSF2 + sqr(ColSums[j]) / ColCount[j];
ColsTotCnt := ColsTotCnt + ColCount[j];
end;
GrandMean := MeanDep / N;
for i := 0 to NoGrpsA - 1 do
begin
rowmean := RowSums[i] / RowCount[i];
for j := 0 to NoGrpsB - 1 do
begin
colmean := ColSums[j] / ColCount[j];
SSNonAdd := SSNonAdd + (colmean - GrandMean) * (rowmean - GrandMean) * sums[i,j];
end;
end;
if (N > 0) then
Constant := (MeanDep * MeanDep) / N
else
Constant := 0.0;
SSF1 := SSF1 - Constant;
SSF2 := SSF2 - Constant;
SSDep := SSDep - Constant;
SSErr := SSDep - (SSF1 + SSF2);
SSNonAdd := (SSNonAdd * SSNonAdd) / ((SSF1 * SSF2) / (NoGrpsA * NoGrpsB) );
MSNonAdd := SSNonAdd;
SSBalance := SSErr - SSNonAdd;
if ((SSF1 < 0) or (SSF2 < 0)) then
begin
ErrorMsg('A negative SS found. Unbalanced design? Ending analysis.');
Result := false;
exit;
end;
DFTot := N - 1;
DFF1 := NoGrpsA - 1;
DFF2 := NoGrpsB - 1;
DFErr := DFF1 * DFF2;
DFBalance := DFErr - 1;
MSF1 := SSF1 / DFF1;
MSF2 := SSF2 / DFF2;
MSErr := SSErr / DFErr;
MSDep := SSDep / DFTot;
MSBalance := SSBalance / DFBalance;
OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr);
OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr);
Omega := OmegaF1 + OmegaF2;
MeanDep := MeanDep / N;
// F tests for fixed effects
FF1 := abs(MSF1 / MSErr);
FF2 := abs(MSF2 / MSErr);
if (MSBalance > 0.0) then
FNonAdd := MSNonAdd / MSBalance
else
FNonAdd := 0.0;
ProbF1 := ProbF(FF1,DFF1,DFErr);
ProbF2 := ProbF(FF2,DFF2,DFErr);
ProbNonAdd := ProbF(FNonAdd,1.0,DFBalance);
if (ProbF1 > 1.0) then ProbF1 := 1.0;
if (ProbF2 > 1.0) then ProbF2 := 1.0;
// Obtain omega squared (proportion of dependent variable explained)
if (OmegaF1 < 0.0) then OmegaF1 := 0.0;
if (OmegaF2 < 0.0) then OmegaF2 := 0.0;
if (Omega < 0.0) then Omega := 0.0;
Result := True;
end;
procedure TOneCaseAnovaForm.TwoWayTable(AReport: TStrings);
var
i, j, groupsize: integer;
MinVar, MaxVar, sumvars, sumDFrecip, XBar, V, S, RowSS, ColSS: double;
sumfreqlogvar: double;
begin
if CompError then
exit;
AReport.Add('TWO-WAY ANALYSIS OF VARIANCE');
AReport.Add('');
AReport.Add('Variable analyzed: %s', [DepVarEdit.Text]);
AReport.Add('');
AReport.Add('Factor A (rows) variable: %s', [Factor1Edit.Text]);
AReport.Add('Factor B (columns) variable: %s', [Factor2Edit.Text]);
AReport.Add('');
AReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Squared');
AReport.Add('-------------- ---- ------------ ------------ ---------- -------- -------------');
AReport.Add('Among Rows %4.0f %12.3f %12.3f %10.3f %8.3f %10.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]);
AReport.Add('Among Columns %4.0f %12.3f %12.3f %10.3f %8.3f %10.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]);
AReport.Add('Residual %4.0f %12.3f %12.3f', [DFErr, SSErr, MSErr]);
AReport.Add(' NonAdditivity %4.0f %12.3f %12.3f %10.3f %8.3f', [1.0, SSNonAdd, MSNonAdd, FNonAdd, ProbNonAdd]);
AReport.Add(' Balance %4.0f %12.3f %12.3f', [DFBalance, SSBalance, MSBalance]);
AReport.Add('Total %4.0f %12.3f %12.3f', [DFTot, SSDep, MSDep]);
AReport.Add('');
AReport.Add('Omega squared for combined effects: %10.3f', [Omega]);
AReport.Add('');
AReport.Add('DESCRIPTIVE STATISTICS');
AReport.Add('');
AReport.Add('GROUP Row Col. N MEAN VARIANCE STD.DEV.');
AReport.Add('----- --- ---- ---- -------- -------- ---------');
groupsize := ceil(counts[0,0]);
equal_grp := true;
MaxVar := -1e308;
MinVar := 1e308;
sumvars := 0.0;
sumfreqlogvar := 0.0;
sumDFrecip := 0.0;
// Display cell means, variances, standard deviations
V := 0.0;
XBar := 0.0;
S := 0.0;
for i := 0 to NoGrpsA - 1 do
begin
for j := 0 to NoGrpsB - 1 do
begin
if (counts[i,j] > 1) then
begin
XBar := sums[i, j] / counts[i, j];
V := vars[i, j] - sqr(sums[i, j]) / counts[i, j];
V := V / (counts[i, j] - 1.0);
S := sqrt(V);
sumvars := sumvars + V;
if (V > MaxVar) then MaxVar := V;
if (V < MinVar) then MinVar := V;
sumDFrecip := sumDFrecip + 1.0 / (counts[i, j] - 1.0);
sumfreqlogvar := sumfreqlogvar + (counts[i,j] - 1.0) * ln(V);
if (counts[i, j] <> groupsize) then equal_grp := false;
end
else
XBar := sums[i][j];
AReport.Add('Cell %3d %3d %3d %8.3f %8.3f %8.3f', [minf1+i, minf2+j, counts[i,j], XBar, V, S]);
end;
end;
//Display Row means, variances, standard deviations
for i := 0 to NoGrpsA - 1 do
begin
XBar := RowSums[i] / RowCount[i];
OrdMeansA[i] := XBar;
RowSS := 0.0;
for j := 0 to NoGrpsB - 1 do RowSS := RowSS + vars[i,j];
V := RowSS - sqr(RowSums[i]) / RowCount[i];
V := V / (RowCount[i] - 1.0);
S := sqrt(V);
AReport.Add('Row %3d %3d %8.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]);
end;
//Display means, variances and standard deviations for columns
for j := 0 to NoGrpsB - 1 do
begin
XBar := ColSums[j] / ColCount[j];
OrdMeansB[j] := XBar;
ColSS := 0.0;
for i := 0 to NoGrpsA - 1 do ColSS := ColSS + vars[i,j];
if (ColCount[j] > 0) then V := ColSS - sqr(ColSums[j]) / ColCount[j];
if (ColCount[j] > 1) then V := V / (ColCount[j] - 1.0);
if (V > 0.0) then S := sqrt(V);
AReport.Add('Col %3d %3d %8.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]);
end;
AReport.Add('TOTAL %3d %8.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]);
AReport.Add('');
end;
procedure TOneCaseAnovaForm.PopulateChartCombobox(ThreeWay: Boolean);
var
a, b, c: String;
i, idx: Integer;
begin
a := Factor1Edit.Text;
b := Factor2Edit.Text;
c := Factor3Edit.Text;
idx := FChartCombobox.ItemIndex;
FChartCombobox.Items.Clear;
FChartCombobox.Items.Add(a);
FChartCombobox.Items.Add(b);
if ThreeWay then
begin
FChartCombobox.Items.Add(c);
for i := 0 to NF3Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, b, a, c, Round(MinF3) + i]));
for i := 0 to NF3Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, b, b, c, Round(MinF3) + i]));
for i := 0 to NF2Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, c, a, b, Round(MinF2) + i]));
for i := 0 to NF2Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, c, c, b, Round(MinF2) + i]));
for i := 0 to NF1Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [b, c, b, a, Round(MinF1) + i]));
for i := 0 to NF1Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [b, c, c, a, Round(MinF1) + i]));
end else
begin
FChartCombobox.Items.Add(Format('Interaction %s*%s vs %s', [a, b, a]));
FChartCombobox.Items.Add(Format('Interaction %s*%s vs %s', [a, b, b]));
end;
if idx = -1 then
FChartCombobox.ItemIndex := 0
else
FChartCombobox.ItemIndex := Min(idx, FChartCombobox.Items.Count-1);;
end;
procedure TOneCaseAnovaForm.SelectTwoWayPlot(Sender: TObject);
var
i, j, idx: Integer;
item: PChartDataItem;
begin
FStyles.Styles.Clear;
FSeries.Clear;
case FChartCombobox.ItemIndex of
0: begin // Plot means vs factor A
FSeries.ListSource.YCount := 1;
for i := 0 to NF1Cells-1 do
FSeries.AddXY(minF1 + i, RowSums[i] / RowCount[i], IntToStr(MinF1 + i));
FChartFrame.SetXTitle(Factor1Edit.Text);
end;
1: begin // Plot means vs factor B
FSeries.ListSource.YCount := 1;
for j := 0 to NF2Cells-1 do
FSeries.AddXY(minF2 + j, ColSums[j] / ColCount[j], IntToStr(MinF2 + j));
FChartFrame.SetXTitle(Factor2Edit.Text);
end;
2: begin // Plot interaction A*B vs A
FSeries.ListSource.YCount := NF2Cells;
for i := 0 to NF1Cells-1 do
begin
idx := FSeries.AddXY(minF1 + i, NaN, IntToStr(minF1 + i));
item := FSeries.Source.Item[idx];
for j := 0 to NF2Cells-1 do
item^.SetY(j, sums[i, j] / counts[i, j]);
end;
FChartFrame.SetXTitle(Factor1Edit.Text);
for j := 0 to NF2cells-1 do
with TChartStyle(FStyles.Styles.Add) do
begin
Brush.Color := DATA_COLORS[j mod Length(DATA_COLORS)];
UseBrush := true;
Text := Format('%s %s', [Factor2Edit.Text, IntToStr(MinF2 + j)]);
end;
end;
3: begin // Plot means vs interaction A*B vs B
FSeries.ListSource.YCount := NF1Cells;
for j := 0 to NF2Cells-1 do
begin
idx := FSeries.AddXY(minF2 + j, NaN, IntToStr(minF2 + j));
item := FSeries.Source.Item[idx];
for i := 0 to NF1Cells-1 do
item^.SetY(i, sums[i, j] / counts[i, j]);
end;
FChartFrame.SetXTitle(Factor2Edit.Text);
for i := 0 to NF1Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s %s', [Factor1Edit.Text, IntToStr(MinF1 + i)]);
end;
end;
end; // case
if (FSeries is TBarSeries) then
begin
if FStyles.Styles.Count > 0 then
begin
TBarSeries(FSeries).Styles := FStyles;
FSeries.Legend.Multiplicity := lmStyle;
end else
FSeries.Legend.Multiplicity := lmSingle;
end;
FChartFrame.Chart.BottomAxis.Marks.Source := FSeries.Source;
FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel;
FChartFrame.Chart.Legend.Visible := FSeries.Source.YCount > 1;
end;
procedure TOneCaseAnovaForm.TwoWayPlot;
begin
FChartFrame.Clear; // this destroys the series
FChartFrame.SetYTitle('Means');
FSeries := FChartFrame.PlotXY(ptBars, nil, nil, nil, nil, '', DATA_COLORS[0]);
TBarSeries(FSeries).Stacked := false;
PopulateChartCombobox(false);
FChartCombobox.OnChange := @SelectTwoWayPlot;
SelectTwoWayPlot(nil);
end;
(*
procedure TOneCaseAnovaForm.TwoWayPlot;
var
i, j: integer;
maxmean, XBar: double;
XValue: DblDyneVec = nil;
plottype: integer;
begin
if CompError then
exit;
case PlotOptionsGroup.ItemIndex of
0: exit;
1: plotType := 2; // 3D bars
2: plotType := 1; // 2D bars
3: plotType := 9; // 2D horizontal bars
else raise Exception.Create('Plot type not supported.');
end;
SetLength(XValue, Nf1cells+Nf2cells);
// Factor A first
GraphFrm.SetLabels[1] := 'FACTOR A';
maxmean := 0.0;
SetLength(GraphFrm.Xpoints, 1, Nf1cells);
SetLength(GraphFrm.Ypoints, 1, Nf1cells);
for i := 1 to Nf1cells do
begin
RowSums[i-1] := RowSums[i-1] / RowCount[i-1];
GraphFrm.Ypoints[0,i-1] := RowSums[i-1];
if (RowSums[i-1] > maxmean) then maxmean := RowSums[i-1];
XValue[i-1] := minf1 + i - 1;
GraphFrm.Xpoints[0,i-1] := XValue[i-1];
end;
GraphFrm.nosets := 1;
GraphFrm.nbars := Nf1cells;
GraphFrm.Heading := Factor1Edit.Text;
GraphFrm.XTitle := Factor1Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal();
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor B next
GraphFrm.SetLabels[1] := 'FACTOR B';
maxmean := 0.0;
SetLength(GraphFrm.Xpoints, 1, Nf2cells);
SetLength(GraphFrm.Ypoints, 1, Nf2cells);
for i := 1 to Nf2cells do
begin
ColSums[i-1] := ColSums[i-1] / ColCount[i-1];
GraphFrm.Ypoints[0,i-1] := ColSums[i-1];
if (ColSums[i-1] > maxmean) then maxmean := ColSums[i-1];
XValue[i-1] := minf1 + i - 1;
GraphFrm.Xpoints[0,i-1] := XValue[i-1];
end;
GraphFrm.nosets := 1;
GraphFrm.nbars := Nf2cells;
GraphFrm.Heading := Factor2Edit.Text;
GraphFrm.XTitle := Factor2Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal();
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor A x B Interaction next
maxmean := 0.0;
SetLength(GraphFrm.Ypoints, Nf1cells, Nf2cells);
SetLength(GraphFrm.Xpoints, 1, Nf2cells);
for i := 1 to Nf1cells do
begin
GraphFrm.SetLabels[i] := Factor1Edit.Text + ' ' + IntToStr(i);
for j := 1 to Nf2cells do
begin
XBar := sums[i-1,j-1] / counts[i-1,j-1];
if (XBar > maxmean) then maxmean := XBar;
GraphFrm.Ypoints[i-1,j-1] := XBar;
end;
end;
for j := 1 to Nf2cells do
begin
XValue[j-1] := minf2 + j - 1;
GraphFrm.Xpoints[0,j-1] := XValue[j-1];
end;
GraphFrm.nosets := Nf1cells;
GraphFrm.nbars := Nf2cells;
GraphFrm.Heading := 'Factor A x Factor B';
GraphFrm.XTitle := Factor2Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal();
XValue := nil;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
end;
*)
function TOneCaseAnovaForm.Calc3Way: Boolean;
var
i, j, k, grpA, grpB, grpC: integer;
Constant, RowsTotCnt, ColsTotCnt, SlcsTotCnt, SSCells, p, n2: double;
X, Xsq, rowMean, colMean, sliceMean: Double;
begin
// initialize matrix values
NoGrpsA := maxf1 - minf1 + 1;
NoGrpsB := maxf2 - minf2 + 1;
NoGrpsC := maxf3 - minf3 + 1;
for i := 0 to NoGrpsA - 1 do
begin
RowSums[i] := 0.0;
RowCount[i] := 0;
for j := 0 to NoGrpsB - 1 do
begin
for k := 0 to NoGrpsC - 1 do
begin
wsum[i,j,k] := 0.0;
ncnt[i,j,k] := 0;
wx2[i,j,k] := 0.0;
end;
end;
end;
for i := 0 to NoGrpsB - 1 do
begin
ColCount[i] := 0;
ColSums[i] := 0.0;
end;
for i := 0 to NoGrpsC - 1 do
begin
SlcCount[i] := 0;
SlcSums[i] := 0;
end;
N := 0;
MeanDep := 0.0;
SSDep := 0.0;
RowsTotCnt := 0.0;
ColsTotCnt := 0.0;
SlcsTotCnt := 0.0;
SSF1 := 0.0;
SSF2 := 0.0;
SSF3 := 0.0;
SSF1F2 := 0.0;
SSF1F3 := 0.0;
SSF2F3 := 0.0;
SSF1F2F3 := 0.0;
SSCells := 0.0;
SSNonAdd := 0.0;
// Get working totals
for i := 0 to High(DepValues) do
begin
grpA := round(F1Values[i]) - MinF1;
grpB := round(F2Values[i]) - MinF2;
grpC := round(F3Values[i]) - MinF3;
X := DepValues[i];
Xsq := X * X;
ncnt[grpA, grpB, grpC] := ncnt[grpA, grpB, grpC] + 1;
wsum[grpA, grpB, grpC] := wsum[grpA, grpB, grpC] + X;
wx2[grpA, grpB, grpC] := wx2[grpA, grpB, grpC] + Xsq;
RowSums[grpA] := RowSums[grpA] + X;
ColSums[grpB] := ColSums[grpB] + X;
SlcSums[grpC] := SlcSums[grpC] + X;
RowCount[grpA] := RowCount[grpA] + 1;
Colcount[grpB] := ColCount[grpB] + 1;
SlcCount[grpC] := SlcCount[grpC] + 1;
MeanDep := MeanDep + X;
SSDep := SSDep + Xsq;
N := N + 1;
end;
{
// get working totals
for i := 1 to NoCases do
begin
if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue;
grpA := floor(StrToFloat(OS3MainFrm.DataGrid.Cells[ColNoSelected[1],i]));
grpB := floor(StrToFloat(OS3MainFrm.DataGrid.Cells[ColNoSelected[2],i]));
grpC := floor(StrToFloat(OS3MainFrm.DataGrid.Cells[ColNoSelected[3],i]));
X := StrToFloat(OS3MainFrm.DataGrid.Cells[ColNoSelected[0],i]);
grpA := grpA - minf1 + 1;
grpB := grpB - minf2 + 1;
grpC := grpC - minf3 + 1;
ncnt[grpA-1,grpB-1,grpC-1] := ncnt[grpA-1,grpB-1,grpC-1] + 1;
wsum[grpA-1,grpB-1,grpC-1] := wsum[grpA-1,grpB-1,grpC-1] + X;
wx2[grpA-1,grpB-1,grpC-1] := wx2[grpA-1,grpB-1,grpC-1] + X * X;
RowSums[grpA-1] := RowSums[grpA-1] + X;
ColSums[grpB-1] := ColSums[grpB-1] + X;
SlcSums[grpC-1] := SlcSums[grpC-1] + X;
RowCount[grpA-1] := RowCount[grpA-1] + 1;
ColCount[grpB-1] := ColCount[grpB-1] + 1;
SlcCount[grpC-1] := SlcCount[grpC-1] + 1;
MeanDep := MeanDep + X;
SSDep := SSDep + X * X;
N := N + 1;
end;
}
// Calculate results
Constant := (MeanDep * MeanDep) / N;
GrandMean := MeanDep / N;
// Get ss for rows
for i := 0 to NoGrpsA - 1 do
begin
SSF1 := SSF1 + RowSums[i] * RowSums[i] / RowCount[i];
RowsTotCnt := RowsTotCnt + RowCount[i];
end;
SSF1 := SSF1 - Constant;
// Get ss for columns
for j := 0 to NoGrpsB - 1 do
begin
SSF2 := SSF2 + ColSums[j] * ColSums[j] / ColCount[j];
ColsTotCnt := ColsTotCnt + ColCount[j];
end;
SSF2 := SSF2 - Constant;
// Get ss for slices
for k := 0 to NoGrpsC - 1 do
begin
SSF3 := SSF3 + SlcSums[k] * SlcSums[k] / SlcCount[k];
SlcsTotCnt := SlcsTotCnt + SlcCount[k];
end;
SSF3 := SSF3 - Constant;
// Get ss for row x col interaction
p := 0.0;
n2 := 0.0;
for i := 0 to NoGrpsA - 1 do
begin
for j := 0 to NoGrpsB - 1 do
begin
for k := 0 to NoGrpsC - 1 do
begin
p := p + wsum[i,j,k];
n2 := n2 + ncnt[i,j,k];
end;
SSF1F2 := SSF1F2 + p * p / n2;
p := 0.0;
n2 := 0.0;
end;
end;
SSF1F2 := SSF1F2 - SSF1 - SSF2 - Constant;
// Get ss for row x slice interaction
for i := 0 to NoGrpsA - 1 do
begin
for k := 0 to NoGrpsC - 1 do
begin
for j := 0 to NoGrpsB - 1 do
begin
p := p + wsum[i,j,k];
n2 := n2 + ncnt[i,j,k];
end;
SSF1F3 := SSF1F3 + p * p / n2;
p := 0.0;
n2 := 0.0;
end;
end;
SSF1F3 := SSF1F3 - SSF1 - SSF3 - Constant;
// Get ss for columns x slices interaction
for j := 0 to NoGrpsB - 1 do
begin
for k := 0 to NoGrpsC - 1 do
begin
for i := 0 to NoGrpsA - 1 do
begin
p := p + wsum[i,j,k];
n2 := n2 + ncnt[i,j,k];
end;
SSF2F3 := SSF2F3 + p * p / n2;
p := 0.0;
n2 := 0.0;
end;
end;
SSF2F3 := SSF2F3 - SSF2 - SSF3 - Constant;
(*
// get ss for cells
for (i := 0; i < NoGrpsA; i++)
for (j := 0; j < NoGrpsB; j++)
for (k := 0; k < NoGrpsC; k++)
SSCells := SSCells + ((wsum[i][j][k] * wsum[i][j][k]) / ncnt[i][j][k]);
SSF1F2F3 := SSCells - SSF1 - SSF2 - SSF3 - SSF1F2 - SSF1F3 - SSF2F3 - Constant;
*)
for i := 0 to NoGrpsA - 1 do
begin
rowmean := RowSums[i] / RowCount[i];
for j := 0 to NoGrpsB - 1 do
begin
colmean := ColSums[j] / ColCount[j];
for k := 0 to NoGrpsC - 1 do
begin
slicemean := SlcSums[k] / SlcCount[k];
SSNonAdd := SSNonAdd + (colmean-GrandMean) * (rowmean-GrandMean) * (slicemean-GrandMean) * wsum[i,j,k];
end;
end;
end;
SSDep := SSDep - Constant;
if InteractChk.Checked then
SSErr := SSDep - (SSF1 + SSF2 + SSF3 + SSF1F2 + SSF1F3 + SSF2F3)
else
SSErr := SSDep - (SSF1 + SSF2 + SSF3);
SSNonAdd := SSNonAdd * SSNonAdd / (SSF1 * SSF2 * SSF3);
SSNonAdd := SSNonAdd * NoGrpsA * NoGrpsB * NoGrpsC * NoGrpsA * NoGrpsB * NoGrpsC;
MSNonAdd := SSNonAdd;
SSBalance := SSErr - SSNonAdd;
if ((SSF1 < 0.0) or (SSF2 < 0.0) or (SSF3 < 0.0) or (SSF1F2 < 0.0) or (SSF1F3 < 0.0) or (SSF2F3 < 0.0)) then
begin
ErrorMsg('A negative SS found. Unbalanced Design? Ending analysis.');
Result := false;
exit;
end;
DFTot := N - 1;
DFF1 := NoGrpsA - 1;
DFF2 := NoGrpsB - 1;
DFF3 := NoGrpsC - 1;
DFF1F2 := DFF1 * DFF2;
DFF1F3 := DFF1 * DFF3;
DFF2F3 := DFF2 * DFF3;
if InteractChk.Checked then
DFErr := DFTot - DFF1 - DFF2 - DFF3 - DFF1F2 - DFF1F3 - DFF2F3
else
DFErr := DFTot - DFF1 - DFF2 - DFF3;
DFBalance := DFErr - 1;
MSF1 := SSF1 / DFF1;
MSF2 := SSF2 / DFF2;
MSF3 := SSF3 / DFF3;
MSF1F2 := SSF1F2 / DFF1F2;
MSF1F3 := SSF1F3 / DFF1F3;
MSF2F3 := SSF2F3 / DFF2F3;
MSErr := SSErr / DFErr;
MSDep := SSDep / DFTot;
MSBalance := SSBalance / DFBalance;
OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr);
OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr);
OmegaF3 := (SSF3 - DFF3 * MSErr) / (SSDep + MSErr);
OmegaF1F2 := (SSF1F2 - DFF1F2 * MSErr) / (SSDep + MSErr);
OmegaF1F3 := (SSF1F3 - DFF1F3 * MSErr) / (SSDep + MSErr);
OmegaF2F3 := (SSF2F3 - DFF2F3 * MSErr) / (SSDep + MSErr);
if InteractChk.Checked then
Omega := OmegaF1 + OmegaF2 + OmegaF3 + OmegaF1F2 + OmegaF1F3 + OmegaF2F3
else
Omega := OmegaF1 + OmegaF2 + OmegaF3;
MeanDep := MeanDep / N;
FF1 := abs(MSF1 / MSErr);
FF2 := abs(MSF2 / MSErr);
FF3 := abs(MSF3 / MSErr);
FF1F2 := abs(MSF1F2 / MSErr);
FF1F3 := abs(MSF1F3 / MSErr);
FF2F3 := abs(MSF2F3 / MSErr);
if (MSBalance > 0.0) then
FNonAdd := MSNonAdd / MSBalance
else
FNonAdd := 0.0;
ProbF1 := probf(FF1,DFF1,DFErr);
ProbF2 := probf(FF2,DFF2,DFErr);
ProbF3 := probf(FF3,DFF3,DFErr);
ProbF1F2 := probf(FF1F2,DFF1F2,DFErr);
ProbF1F3 := probf(FF1F3,DFF1F3,DFErr);
ProbF2F3 := probf(FF2F3,DFF2F3,DFErr);
ProbNonAdd := probf(FNonAdd,1.0,DFBalance);
if (ProbF1 > 1.0) then ProbF1 := 1.0;
if (ProbF2 > 1.0) then ProbF2 := 1.0;
if (ProbF3 > 1.0) then ProbF3 := 1.0;
if (ProbF1F2 > 1.0) then ProbF1F2 := 1.0;
if (ProbF1F3 > 1.0) then ProbF1F3 := 1.0;
if (ProbF2F3 > 1.0) then ProbF2F3 := 1.0;
// Obtain omega squared (proportion of dependent variable explained)
if (OmegaF1 < 0.0) then OmegaF1 := 0.0;
if (OmegaF2 < 0.0) then OmegaF2 := 0.0;
if (OmegaF3 < 0.0) then OmegaF3 := 0.0;
if (OmegaF1F2 < 0.0) then OmegaF1F2 := 0.0;
if (OmegaF1F3 < 0.0) then OmegaF1F3 := 0.0;
if (OmegaF2F3 < 0.0) then OmegaF2F3 := 0.0;
if (Omega < 0.0) then Omega := 0.0;
Result := true;
end;
procedure TOneCaseAnovaForm.ThreeWayTable(AReport: TStrings);
var
i, j, k: integer;
XBar, V, S, RowSS, ColSS, SlcSS: double;
begin
if CompError then
exit;
AReport.Add('THREE-WAY ANALYSIS OF VARIANCE');
AReport.Add('');
AReport.Add('Variable analyzed: %s', [DepVarEdit.Text]);
AReport.Add('');
AReport.Add('Factor A (rows) variable: %s', [Factor1Edit.Text]);
AReport.Add('Factor B (columns) variable: %s', [Factor2Edit.Text]);
AReport.Add('Factor C (slices) variable: %s', [Factor3Edit.Text]);
AReport.Add('');
AReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Squared');
AReport.Add('');
AReport.Add('Among Rows %4.0f %12.4f %12.4f %12.4f %6.3f %6.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]);
AReport.Add('Among Columns %4.0f %12.4f %12.4f %12.4f %6.3f %6.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]);
AReport.Add('Among Slices %4.0f %12.4f %12.4f %12.4f %6.3f %6.3f', [DFF3, SSF3, MSF3, FF3, ProbF3, OmegaF3]);
if InteractChk.Checked then
begin
AReport.Add('A x B Inter. %4.0f %12.4f %12.4f %12.4f %6.3f %6.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]);
AReport.Add('A x C Inter. %4.0f %12.4f %12.4f %12.4f %6.3f %6.3f', [DFF1F3, SSF1F3, MSF1F3, FF1F3, ProbF1F3, OmegaF1F3]);
AReport.Add('B x C Inter. %4.0f %12.4f %12.4f %12.4f %6.3f %6.3f', [DFF2F3, SSF2F3, MSF2F3, FF2F3, ProbF2F3, OmegaF2F3]);
end;
AReport.Add('Residual %4.0f %12.4f %12.4f', [DFErr, SSErr, MSErr]);
AReport.Add(' NonAdditivity %4.0f %12.4f %12.4f %12.4f %6.3f', [1.0, SSNonAdd, MSNonAdd, FNonAdd, ProbNonAdd]);
AReport.Add(' Balance %4.0f %12.4f %12.4f', [DFBalance, SSBalance, MSBalance]);
AReport.Add('Total %4.0f %12.4f %12.4f', [DFTot, SSDep, MSDep]);
AReport.Add('');
AReport.Add('Omega squared for combined effects := %8.4f', [Omega]);
AReport.Add('');
AReport.Add('');
AReport.Add('Descriptive Statistics');
AReport.Add('');
AReport.Add('GROUP N MEAN VARIANCE STD.DEV.');
equal_grp := true;
// Display cell means, variances, standard deviations
for i := 0 to NoGrpsA - 1 do
begin
for j := 0 to NoGrpsB - 1 do
begin
for k := 0 to NoGrpsC - 1 do
begin
XBar := wsum[i,j,k] / ncnt[i,j,k]; // wp: why this? Result is not used and overwritten in next loop.
V := 0.0; // dto.
S := 0.0; // dto.
end;
end;
end;
//Display Row means, variances, standard deviations
for i := 0 to NoGrpsA - 1 do
begin
XBar := RowSums[i] / RowCount[i];
OrdMeansA[i] := XBar;
RowSS := 0.0;
for j := 0 to NoGrpsB - 1 do
for k := 0 to NoGrpsC - 1 do
RowSS := RowSS + wx2[i,j,k];
V := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]);
V := V / (RowCount[i] - 1.0);
S := sqrt(V);
AReport.Add('Row %3d %3d %8.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]);
end;
//Display means, variances and standard deviations for columns
for j := 0 to NoGrpsB - 1 do
begin
XBar := ColSums[j] / ColCount[j];
OrdMeansB[j] := XBar;
ColSS := 0.0;
for i := 0 to NoGrpsA - 1 do
for k := 0 to NoGrpsC - 1 do
ColSS := ColSS + wx2[i,j,k];
V := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]);
V := V / (ColCount[j] - 1.0);
S := sqrt(V);
AReport.Add('Col %3d %3d %8.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]);
end;
//Display means, variances and standard deviations for slices
for k := 0 to NoGrpsC - 1 do
begin
XBar := SlcSums[k] / SlcCount[k];
OrdMeansC[k] := XBar;
SlcSS := 0.0;
for i := 0 to NoGrpsA - 1 do
for j := 0 to NoGrpsB - 1 do
SlcSS := SlcSS + wx2[i,j,k];
V := SlcSS - (SlcSums[k] * SlcSums[k] / SlcCount[k]);
V := V / (SlcCount[k] - 1.0);
S := sqrt(V);
AReport.Add('Slice %3d %3d %8.3f %8.3f %8.3f', [minf3+k, SlcCount[k], XBar, V, S]);
end;
AReport.Add('TOTAL %3d %8.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]);
AReport.Add('');
AReport.Add('');
end;
procedure TOneCaseAnovaform.GetDataIndices(out ix, iy, iz: Integer);
var
index, i1, i2, i3: Integer;
begin
index := FChartComboBox.ItemIndex;
i1 := 3;
i2 := i1 + NF3Cells;
i3 := i2 + NF3Cells;
if (index >= i1) and (index < i3) then
begin
if index < i2 then
begin
ix := 1;
iy := 2;
iz := index - i1;
end else
begin
ix := 2;
iy := 1;
iz := index - i2;
end;
exit;
end;
i1 := i3;
i2 := i1 + NF2Cells;
i3 := i2 + NF2Cells;
if (index >= i1) and (index < i3) then
begin
if index < i2 then
begin
ix := 1;
iy := 3;
iz := index - i1;
end else
begin
ix := 3;
iy := 1;
iz := index - i2;
end;
exit;
end;
i1 := i3;
i2 := i1 + NF1Cells;
i3 := i2 + NF1Cells;
if (index >= i1) and (index < i3) then
begin
if index < i2 then
begin
ix := 2;
iy := 3;
iz := index - i1;
end else
begin
ix := 3;
iy := 2;
iz := index - i2;
end;
end;
end;
procedure TOneCaseAnovaForm.SelectThreeWayPlot(Sender: TObject);
var
i, j, k, idx, ix, iy, iz: Integer;
item: PChartDataItem;
begin
FStyles.Styles.Clear;
FSeries.Clear;
case FChartComboBox.ItemIndex of
0: begin // Plot means vs factor A
FSeries.ListSource.YCount := 1;
for i := 0 to NF1Cells-1 do
FSeries.AddXY(minF1 + i, RowSums[i] / RowCount[i], IntToStr(MinF1 + i));
FChartFrame.SetXTitle(Factor1Edit.Text);
FChartFrame.SetTitle(Factor1Edit.Text);
end;
1: begin // Plot means vs factor B
FSeries.ListSource.YCount := 1;
for j := 0 to NF2Cells-1 do
FSeries.AddXY(minF2 + j, ColSums[j] / ColCount[j], IntToStr(MinF2 + j));
FChartFrame.SetXTitle(Factor2Edit.Text);
FChartFrame.SetTitle(Factor2Edit.Text);
end;
2: begin // Plot means vs factor C
FSeries.ListSource.YCount := 1;
for i := 0 to NF3Cells-1 do
FSeries.AddXY(minF3 + i, SlcSums[i] / SlcCount[i], IntToStr(MinF3 + i));
FChartFrame.SetXTitle(Factor3Edit.Text);
FChartFrame.SetTitle(Factor3Edit.Text);
end;
else
GetDataIndices(ix, iy,iz);
if (ix = 1) and (iy = 2) then
begin
FSeries.ListSource.YCount := NF2Cells;
for i := 0 to NF1Cells-1 do
begin
idx := FSeries.AddXY(minF1 + i, NaN, IntToStr(minF1 + i));
item := FSeries.Source.Item[idx];
for j := 0 to NF2Cells-1 do
item^.SetY(j, wsum[i,j,iz] / ncnt[i,j,iz]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [
Factor1Edit.Text, Factor2Edit.Text, Factor3Edit.Text, MinF3 + iz]));
FChartFrame.SetXTitle(Factor1Edit.Text + ' codes');
for j := 0 to NF2Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[j mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s = %s', [Factor2Edit.Text, IntToStr(MinF2 + j)]);
end;
end
else
if (ix = 2) and (iy = 1) then
begin
FSeries.ListSource.YCount := NF1Cells;
for j := 0 to NF2Cells-1 do
begin
idx := FSeries.AddXY(minF2 + j, NaN, IntToStr(minF2 + j));
item := FSeries.Source.Item[idx];
for i := 0 to NF1Cells-1 do
item^.SetY(i, wsum[i, j, iz] / ncnt[i, j, iz]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [
Factor1Edit.Text, Factor2Edit.Text, Factor3Edit.Text, MinF3 + iz]));
FChartFrame.SetXTitle(Factor2Edit.Text + ' codes');
for i := 0 to NF1Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s = %s', [Factor1Edit.Text, IntToStr(MinF1 + i)]);
end;
end
else
if (ix = 1) and (iy = 3) then
begin
FSeries.ListSource.YCount := NF3Cells;
for i := 0 to NF1Cells-1 do
begin
idx := FSeries.AddXY(minF1 + i, NaN, IntToStr(minF1 + i));
item := FSeries.Source.Item[idx];
for k := 0 to NF3Cells-1 do
item^.SetY(k, wsum[i, iz, k] / ncnt[i, iz, k]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [
Factor1Edit.Text, Factor3Edit.Text, Factor2Edit.Text, MinF2 + iz]));
FChartFrame.SetXTitle(Factor1Edit.Text + ' codes');
for k := 0 to NF3Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[k mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s = %s', [Factor3Edit.Text, IntToStr(MinF3 + k)]);
end;
end
else
if (ix = 3) and (iy = 1) then
begin
FSeries.ListSource.YCount := NF1Cells;
for k := 0 to NF3Cells-1 do
begin
idx := FSeries.AddXY(minF3 + k, NaN, IntToStr(minF3 + k));
item := FSeries.Source.Item[idx];
for i := 0 to NF1Cells-1 do
item^.SetY(i, wsum[i, iz, k] / ncnt[i, iz, k]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [
Factor1Edit.Text, Factor3Edit.Text, Factor2Edit.Text, MinF2 + iz]));
FChartFrame.SetXTitle(Factor3Edit.Text + ' codes');
for i := 0 to NF1Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s = %s', [Factor1Edit.Text, IntToStr(MinF1 + i)]);
end;
end
else
if (ix = 2) and (iy = 3) then
begin
FSeries.ListSource.YCount := NF3Cells;
for j := 0 to NF2Cells-1 do
begin
idx := FSeries.AddXY(minF2 + j, NaN, IntToStr(minF2 + j));
item := FSeries.Source.Item[idx];
for k := 0 to NF3Cells-1 do
item^.SetY(k, wsum[iz, j, k] / ncnt[iz, j, k]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [
Factor2Edit.Text, Factor3Edit.Text, Factor1Edit.Text, MinF1 + iz]));
FChartFrame.SetXTitle(Factor2Edit.Text + ' codes');
for k := 0 to NF3Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[k mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s = %s', [Factor3Edit.Text, IntToStr(MinF3 + k)]);
end;
end
else
if (ix = 3) and (iy = 2) then
begin
FSeries.ListSource.YCount := NF2Cells;
for k := 0 to NF3Cells-1 do
begin
idx := FSeries.AddXY(minF3 + k, NaN, IntToStr(minF3 + k));
item := FSeries.Source.Item[idx];
for j := 0 to NF2Cells-1 do
item^.SetY(j, wsum[iz, j, k] / ncnt[iz, j, k]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [
Factor2Edit.Text, Factor3Edit.Text, Factor1Edit.Text, MinF1 + iz]));
FChartFrame.SetXTitle(Factor3Edit.Text + ' codes');
for j := 0 to NF2Cells-1 do
with TChartStyle(FStyles.Styles.Add) do
begin
Brush.Color := DATA_COLORS[j mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s = %s', [Factor2Edit.Text, IntToStr(MinF2 + j)]);
end;
end else
raise Exception.Create('Fatal error in SelectThreeWayPlot');
end;
if (FSeries is TBarSeries) then
begin
if FStyles.Styles.Count > 0 then
begin
TBarSeries(FSeries).Styles := FStyles;
FSeries.Legend.Multiplicity := lmStyle;
end else
FSeries.Legend.Multiplicity := lmSingle;
end;
FChartFrame.Chart.BottomAxis.Marks.Source := FSeries.Source;
FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel;
FChartFrame.Chart.Legend.Visible := FSeries.Source.YCount > 1;
end;
procedure TOneCaseAnovaForm.ThreeWayPlot;
var
clr: TColor;
begin
if FChartComboBox.ItemIndex = -1 then
clr := DATA_COLORS[0]
else
clr := DATA_COLORS[FChartComboBox.ItemIndex mod Length(DATA_COLORS)];
FChartFrame.Clear; // this destroys the series
FChartFrame.SetYTitle('Means');
FSeries := FChartFrame.PlotXY(ptBars, nil, nil, nil, nil, '', clr);
TBarSeries(FSeries).Stacked := false;
PopulateChartCombobox(true);
FChartCombobox.OnChange := @SelectThreeWayPlot;
SelectThreeWayPlot(nil);
end;
(*
procedure TOneCaseAnovaForm.ThreeWayPlot;
var
i, j, k: integer;
maxmean, XBar: double;
XValue: DblDyneVec = nil;
plottype: integer;
begin
if CompError then
exit;
case PlotOptionsGroup.ItemIndex of
0: exit;
1: plotType := 2; // 3D bars
2: plotType := 1; // 2D bars
3: plotType := 9; // 2D horizontal bars
else raise Exception.Create('Plot type not supported.');
end;
SetLength(XValue, TotalCells);
// Factor A first
GraphFrm.SetLabels[1] := 'FACTOR A';
maxmean := 0.0;
SetLength(GraphFrm.Xpoints, 1, Nf1cells);
SetLength(GraphFrm.Ypoints, 1, Nf1cells);
for i := 0 to Nf1cells - 1 do
begin
RowSums[i] := RowSums[i] / RowCount[i];
GraphFrm.Ypoints[0,i] := RowSums[i];
if (RowSums[i] > maxmean) then maxmean := RowSums[i];
XValue[i] := minf1 + i;
GraphFrm.Xpoints[0,i] := XValue[i];
end;
GraphFrm.nosets := 1;
GraphFrm.nbars := Nf1cells;
GraphFrm.Heading := Factor1Edit.Text;
GraphFrm.XTitle := Factor1Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor B next
GraphFrm.SetLabels[1] := 'FACTOR B';
maxmean := 0.0;
SetLength(GraphFrm.Xpoints, 1, Nf2cells);
SetLength(GraphFrm.Ypoints, 1, Nf2cells);
for i := 0 to Nf2cells - 1 do
begin
ColSums[i] := ColSums[i] / ColCount[i];
GraphFrm.Ypoints[0,i] := ColSums[i];
if (ColSums[i] > maxmean) then maxmean := ColSums[i];
XValue[i] := minf2 + i;
GraphFrm.Xpoints[0,i] := XValue[i];
end;
GraphFrm.nosets := 1;
GraphFrm.nbars := Nf2cells;
GraphFrm.Heading := Factor2Edit.Text;
GraphFrm.XTitle := Factor2Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor C next
GraphFrm.SetLabels[1] := 'FACTOR C';
maxmean := 0.0;
SetLength(GraphFrm.Xpoints, 1, Nf3cells);
SetLength(GraphFrm.Ypoints, 1, Nf3cells);
for i := 0 to Nf3cells - 1 do
begin
SlcSums[i] := SlcSums[i] / SlcCount[i];
GraphFrm.Ypoints[0,i] := SlcSums[i];
if (SlcSums[i] > maxmean) then maxmean := SlcSums[i];
XValue[i] := minf3 + i;
GraphFrm.Xpoints[0,i] := XValue[i];
end;
GraphFrm.nosets := 1;
GraphFrm.nbars := Nf3cells;
GraphFrm.Heading := Factor3Edit.Text;
GraphFrm.XTitle := Factor2Edit.Text + ' Codes'; // why not Factor3?
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor A x B Interaction within each slice next
SetLength(GraphFrm.Ypoints, Nf1cells, Nf2cells);
SetLength(GraphFrm.Xpoints, 1, Nf2cells);
for k := 0 to Nf3cells - 1 do
begin
maxmean := 0.0;
for i := 0 to Nf1cells - 1 do
begin
GraphFrm.SetLabels[i+1] := Factor1Edit.Text + ' ' + IntToStr(i+1);
for j := 0 to Nf2cells - 1 do
begin
XBar := wsum[i,j,k] / ncnt[i,j,k];
if (XBar > maxmean) then maxmean := XBar;
GraphFrm.Ypoints[i,j] := XBar;
end;
end;
for j := 0 to Nf2cells - 1 do
begin
XValue[j] := minf2 + j ;
GraphFrm.Xpoints[0,j] := XValue[j];
end;
GraphFrm.nosets := Nf1cells;
GraphFrm.nbars := Nf2cells;
GraphFrm.Heading := 'Factor A x Factor B Within C ' + IntToStr(k+1);
GraphFrm.XTitle := Factor2Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.2;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal;
end;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor A x C Interaction within each Column next
SetLength(GraphFrm.Xpoints, 1, Nf3cells);
SetLength(GraphFrm.Ypoints, Nf1cells, Nf3cells);
for j := 0 to Nf2cells - 1 do
begin
maxmean := 0.0;
for i := 0 to Nf1cells - 1 do
begin
GraphFrm.SetLabels[i+1] := Factor1Edit.Text + ' ' + IntToStr(i+1);
for k := 0 to Nf3cells - 1 do
begin
XBar := wsum[i,j,k] / ncnt[i,j,k];
if (XBar > maxmean) then maxmean := XBar;
GraphFrm.Ypoints[i,k] := XBar;
end;
end;
for k := 0 to Nf3cells - 1 do
begin
XValue[k] := minf3 + k;
GraphFrm.Xpoints[0,k] := XValue[k];
end;
GraphFrm.nosets := Nf1cells;
GraphFrm.nbars := Nf3cells;
GraphFrm.Heading := 'Factor A x Factor C Within B ' + IntToStr(j+1);
GraphFrm.XTitle := Factor3Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.2;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal;
end;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
// Factor B x C Interaction within each row next
SetLength(GraphFrm.Xpoints, 1, Nf3cells);
SetLength(GraphFrm.Ypoints, Nf2cells, Nf3cells);
for i := 0 to Nf1cells - 1 do
begin
maxmean := 0.0;
for j := 0 to Nf2cells - 1 do
begin
GraphFrm.SetLabels[j+1] := Factor2Edit.Text + ' ' + IntToStr(j+1);
for k := 0 to Nf3cells - 1 do
begin
XBar := wsum[i,j,k] / ncnt[i,j,k];
if (XBar > maxmean) then maxmean := XBar;
GraphFrm.Ypoints[j,k] := XBar;
end;
end;
for j := 0 to Nf3cells - 1 do
begin
XValue[j] := minf3 + j;
GraphFrm.Xpoints[0,j] := XValue[j];
end;
GraphFrm.nosets := Nf2cells;
GraphFrm.nbars := Nf3cells;
GraphFrm.Heading := 'Factor B x Factor C Within A ' + IntToStr(i+1);
GraphFrm.XTitle := Factor3Edit.Text + ' Codes';
GraphFrm.YTitle := 'Mean';
GraphFrm.barwideprop := 0.2;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxmean;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream;
GraphFrm.WallColor := clDkGray;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
GraphFrm.ShowModal;
end; // next row
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
XValue := nil;
end;
*)
procedure TOneCaseAnovaForm.TwoWayContrasts(AReport: TStrings);
var
i, j: integer;
value, alpha: double;
variances: DblDyneVec = nil;
RowSS, ColSS: double;
begin
if not comparisons then
exit;
if CompError then
exit;
SetLength(variances, TotalCells);
alpha := StrToFloat(PostAlphaEdit.Text);
// row comparisons
if (Nf1cells > 2) and (ProbF1 < Overall) then
begin
for i := 0 to NoGrpsA - 1 do
begin
RowSS := 0.0;
for j := 0 to NoGrpsB - 1 do RowSS := RowSS + vars[i,j];
variances[i] := RowSS - sqr(RowSums[i]) / RowCount[i];
variances[i] := variances[i] / (RowCount[i] - 1.0);
end;
AReport.Add('');
AReport.Add('COMPARISONS AMONG ROWS');
// get smallest group size
value := 1e308;
for i := 0 to Nf1cells - 1 do
if (RowCount[i] < value) then value := RowCount[i];
if ScheffeChk.Checked then
ScheffeTest(MSErr, RowSums, RowCount, minf1, maxf1, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(RowSums,RowCount,variances,minf1,maxf1, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,RowSums,RowCount,minf1,maxf1,Alpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport);
end;
// column comparisons
if (Nf2cells > 2) and (ProbF2 < Alpha) then
begin
for j := 0 to NoGrpsB - 1 do
begin
ColSS := 0.0;
for i := 0 to NoGrpsA - 1 do ColSS := ColSS + vars[i,j];
variances[j] := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]);
variances[j] := variances[j] / (ColCount[j] - 1.0);
end;
AReport.Add('');
AReport.Add('COMPARISONS AMONG COLUMNS');
value := 1e308;
for i := 0 to Nf2cells - 1 do
if (ColCount[i] < value) then value := ColCount[i];
if ScheffeChk.Checked then
ScheffeTest(MSErr, ColSums, ColCount, minf2, maxf2, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(ColSums,ColCount,variances,minf2,maxf2, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,ColSums,ColCount,minf2,maxf2,Alpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport);
end;
// simple effects for columns within each row
if (ProbF3 < Alpha) then
begin
AReport.Add('');
AReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH ROW');
for i := 0 to Nf1cells - 1 do
begin
AReport.Add('');
AReport.Add('ROW %d COMPARISONS', [i+1]);
// move cell sums and counts to cellsums and cellcnts
for j := 0 to Nf2cells - 1 do
begin
cellsums[j] := sums[i,j];
cellcnts[j] := counts[i,j];
cellvars[j] := vars[i,j];
end;
value := 1e308;
for j := 0 to Nf2cells - 1 do
if (cellcnts[j] < value) then value := cellcnts[j];
if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf2, maxf2, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(cellsums,cellcnts,cellvars,minf2,maxf2, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,cellsums,cellcnts,minf2,maxf2,0.05, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
end;
end;
// simple effects for rows within each column
if (ProbF3 < Alpha) then
begin
AReport.Add('');
AReport.Add('COMPARISONS AMONG ROWS WITHIN EACH COLUMN');
for j := 0 to Nf2cells - 1 do
begin
AReport.Add('');
AReport.Add('COLUMN %d COMPARISONS', [j+1]);
// move cell sums and counts to cellsums and cellcnts
for i := 0 to Nf1cells - 1 do
begin
cellsums[i] := sums[i,j];
cellcnts[i] := counts[i,j];
cellvars[i] := vars[i,j];
end;
value := 1e308;
for i := 0 to Nf1cells - 1 do
if (cellcnts[j] < value) then value := cellcnts[j];
if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf1, maxf1, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(cellsums,cellcnts,cellvars,minf1,maxf1, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,cellsums,cellcnts,minf1,maxf1,0.05, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
end;
end;
variances := nil;
end;
procedure TOneCaseAnovaForm.ThreeWayContrasts(AReport: TStrings);
var
i, j, k: integer;
value, alpha: double;
variances: DblDyneVec = nil;
RowSS, ColSS, SlcSS: double;
begin
if not comparisons then
exit;
if CompError then
exit;
alpha := StrToFloat(PostAlphaEdit.Text);
if not (ScheffeChk.Checked or TukeyHSDChk.Checked or TukeyBChk.Checked or
TukeyKramerChk.Checked or NewmanKeulsChk.Checked) then exit;
SetLength(variances, TotalCells);
// row comparisons
if (Nf1cells > 2) and (ProbF1 < Alpha) then
begin
for i := 0 to NoGrpsA - 1 do
begin
RowSS := 0.0;
for j := 0 to NoGrpsB - 1 do
for k := 0 to NoGrpsC - 1 do
RowSS := RowSS + wx2[i,j,k];
variances[i] := RowSS - sqr(RowSums[i]) / RowCount[i];
variances[i] := variances[i] / (RowCount[i] - 1.0);
end;
AReport.Add('');
AReport.Add('COMPARISONS AMONG ROWS');
// get smallest group size
value := 1e308;
for i := 0 to Nf1cells - 1 do
if (RowCount[i] < value) then value := RowCount[i];
if ScheffeChk.Checked then
ScheffeTest(MSErr, RowSums, RowCount, minf1, maxf1, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(RowSums,RowCount,variances,minf1,maxf1, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,RowSums,RowCount,minf1,maxf1,Alpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport);
end;
// column comparisons
if (Nf2cells > 2) and (ProbF2 < Alpha) then
begin
for j := 0 to NoGrpsB - 1 do
begin
ColSS := 0.0;
for i := 0 to NoGrpsA - 1 do
for k := 0 to NoGrpsC - 1 do
ColSS := ColSS + wx2[i,j,k];
variances[j] := ColSS - sqr(ColSums[j]) / ColCount[j];
variances[j] := variances[j] / (ColCount[j] - 1.0);
end;
AReport.Add('');
AReport.Add('COMPARISONS AMONG COLUMNS');
value := 1e308;
for i := 0 to Nf2cells - 1 do
if (ColCount[i] < value) then value := ColCount[i];
if ScheffeChk.Checked then
ScheffeTest(MSErr, ColSums, ColCount, minf2, maxf2, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(ColSums,ColCount,variances,minf2,maxf2, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,ColSums,ColCount,minf2,maxf2,Alpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport);
end;
// slice comparisons
if (Nf3cells > 2) and (ProbF3 < Alpha) then
begin
for k := 0 to NoGrpsC - 1 do
begin
SlcSS := 0.0;
for i := 0 to NoGrpsA - 1 do
for j := 0 to NoGrpsB - 1 do SlcSS := SlcSS + wx2[i,j,k];
variances[k] := SlcSS - sqr(SlcSums[k]) / SlcCount[k];
variances[k] := variances[k] / (SlcCount[k] - 1.0);
end;
AReport.Add('');
AReport.Add('COMPARISONS AMONG SLICES');
value := 1e308;
for i := 0 to Nf3cells - 1 do
if (SlcCount[i] < value) then value := SlcCount[i];
if ScheffeChk.Checked then
ScheffeTest(MSErr, SlcSums, SlcCount, minf3, maxf3, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, SlcSums, SlcCount, minf3, maxf3, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, SlcSums, SlcCount, minf3, maxf3, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, SlcSums, SlcCount, minf3, maxf3, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(SlcSums,SlcCount,variances,minf3,maxf3, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,SlcSums,SlcCount,minf3,maxf3,Alpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, SlcSums, SlcCount, minf3, maxf3, posthocAlpha, AReport);
end;
// simple effects for columns within each row
if (ProbF1F2 < Alpha) then
begin
AReport.Add('');
AReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH ROW');
for i := 0 to Nf1cells - 1 do
begin
AReport.Add('');
AReport.Add('ROW %d COMPARISONS', [i+1]);
// move cell sums && counts to cellsums && cellcnts
for j := 0 to Nf2cells - 1 do
begin
for k := 0 to Nf3cells - 1 do
begin
cellsums[j] := wsum[i,j,k];
cellcnts[j] := ncnt[i,j,k];
cellvars[j] := wx2[i,j,k];
end;
end;
value := 1e308;
for j := 0 to Nf2cells - 1 do
if (cellcnts[j] < value) then value := cellcnts[j];
if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf2, maxf2, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(cellsums,cellcnts,cellvars,minf2,maxf2, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,cellsums,cellcnts,minf2,maxf2,0.05, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
end;
end;
// simple effects for rows within each column
if (ProbF1F2 < Alpha) then
begin
AReport.Add('');
AReport.Add('COMPARISONS AMONG ROWS WITHIN EACH COLUMN');
for j := 0 to Nf2cells - 1 do
begin
AReport.Add('');
AReport.Add('COLUMN %d COMPARISONS', [j+1]);
// move cell sums && counts to cellsums && cellcnts
for i := 0 to Nf1cells - 1 do
begin
for k := 0 to Nf3cells - 1 do
begin
cellsums[i] := wsum[i,j,k];
cellcnts[i] := ncnt[i,j,k];
cellvars[i] := wx2[i,j,k];
end;
end;
value := 1e308;
for i := 0 to Nf1cells - 1 do
if (cellcnts[j] < value) then value := cellcnts[j];
if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf1, maxf1, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(cellsums,cellcnts,cellvars,minf1,maxf1, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,cellsums,cellcnts,minf1,maxf1,0.05, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
end;
end;
// simple effects for columns within each slice
if (ProbF2F3 < Alpha) then
begin
AReport.Add('');
AReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH SLICE');
for k := 0 to Nf3cells - 1 do
begin
AReport.Add('');
AReport.Add('SLICE %d COMPARISONS', [k+1]);
// move cell sums && counts to cellsums && cellcnts
for j := 0 to Nf2cells - 1 do
begin
for i := 0 to Nf1cells - 1 do
begin
cellsums[j] := wsum[i,j,k];
cellcnts[j] := ncnt[i,j,k];
cellvars[j] := wx2[i,j,k];
end;
end;
value := 1e308;
for j := 0 to Nf2cells-1 do
if (cellcnts[j] < value) then value := cellcnts[j];
if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf2, maxf2, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(cellsums, cellcnts, cellvars, minf2, maxf2, posthocAlpha, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport);
end;
end;
// simple effects for rows within each slice
if (ProbF1F3 < Alpha) then
begin
AReport.Add('');
AReport.Add('COMPARISONS AMONG ROWS WITHIN EACH SLICE');
for k := 0 to Nf3cells - 1 do
begin
AReport.Add('');
AReport.Add('SLICE %d COMPARISONS', [k+1]);
// move cell sums && counts to cellsums && cellcnts
for i := 0 to Nf1cells - 1 do
begin
for j := 0 to Nf2cells - 1 do
begin
cellsums[j] := wsum[i,j,k];
cellcnts[j] := ncnt[i,j,k];
cellvars[j] := wx2[i,j,k];
end;
end;
value := 1e308;
for i := 0 to Nf1cells - 1 do
if (cellcnts[i] < value) then value := cellcnts[i];
if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf1, maxf1, N, posthocAlpha, AReport);
if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr,DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, value, posthocAlpha, AReport);
if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
// if (BonferroniChk.Checked) then
// Bonferroni(cellsums,cellcnts,cellvars,minf1,maxf1, posthocAlpha, AReport);
// if (OrthogonalChk.Checked) then
// CONTRASTS(MSErr,DFErr,cellsums,cellcnts,minf1,maxf1,posthocAlpha, AReport);
if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport);
end;
end;
variances := nil;
end;
procedure TOneCaseAnovaForm.UpdateBtnStates;
var
i: Integer;
lSelected: Boolean;
begin
inherited;
lSelected := false;
for i:=0 to VarList.Items.Count-1 do
if VarList.Selected[i] then
begin
lSelected := true;
break;
end;
DepIn.Enabled := lSelected and (DepVarEdit.Text = '');
Fact1In.Enabled := lSelected and (Factor1Edit.Text = '');
Fact2In.Enabled := lSelected and (Factor2Edit.Text = '');
Fact3In.Enabled := lSelected and (Factor3Edit.Text = '');
DepOut.Enabled := DepVarEdit.Text <> '';
Fact1Out.Enabled := Factor1Edit.Text <> '';
Fact2Out.Enabled := Factor2Edit.Text <> '';
Fact3Out.Enabled := Factor3Edit.Text <> '';
end;
function TOneCaseAnovaForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
var
X: Double;
begin
Result := false;
if (DepVarEdit.Text = '') then
begin
AMsg := 'Dependent variable is not selected.';
AControl := VarList;
exit;
end;
if (Factor1Edit.Text = '') then
begin
AMsg := 'Factor 1 variable is not selected.';
AControl := VarList;
exit;
end;
if (Factor2Edit.Text = '') then
begin
AMsg := 'Factor 2 variable is not selected.';
AControl := VarList;
exit;
end;
// Factor 3 can be left empty to distinguish betwee two-way and three-way ANOVA.
if (OverAllAlphaEdit.Text = '') then
begin
AControl := OverAllAlphaEdit;
AMsg := 'No value specified for overall alpha.';
exit;
end;
if not TryStrToFloat(OverAllAlphaEdit.Text, X) then
begin
AControl := OverAllAlphaEdit;
AMsg := 'Overall alpha is not a valid number.';
exit;
end;
if (PostAlphaEdit.Text = '') then
begin
AControl := PostAlphaEdit;
AMsg := 'No value specified for post-hoc alpha.';
exit;
end;
if not TryStrToFloat(PostAlphaEdit.Text, x) then
begin
AControl := PostAlphaEdit;
AMsg := 'Post-hoc alpha is not a valid number.';
exit;
end;
Result := true;
end;
procedure TOneCaseAnovaForm.VarListDblClick(Sender: TObject);
var
index: Integer;
s: String;
begin
index := VarList.ItemIndex;
if index > -1 then
begin
s := VarList.Items[index];
if DepVarEdit.Text = '' then
DepVarEdit.Text := s
else
if Factor1Edit.Text = '' then
Factor1Edit.Text := s
else
if Factor2Edit.Text = '' then
Factor2Edit.Text := s
else
if Factor3Edit.Text = '' then
Factor3Edit.Text := s;
VarList.Items.Delete(index);
UpdateBtnStates;
end;
end;
procedure TOneCaseAnovaForm.VarListSelectionChange(Sender: TObject;
User: boolean);
begin
UpdateBtnStates;
end;
end.