diff --git a/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.lfm b/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.lfm index 0053d6144..7123ae824 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.lfm +++ b/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.lfm @@ -11,19 +11,22 @@ inherited AxSAnovaForm: TAxSAnovaForm inherited ParamsPanel: TPanel Height = 397 ClientHeight = 397 - TabOrder = 1 inherited CloseBtn: TButton Top = 372 + TabOrder = 11 end inherited ComputeBtn: TButton Top = 372 + TabOrder = 10 end inherited ResetBtn: TButton Top = 372 + TabOrder = 9 end inherited HelpBtn: TButton Tag = 106 Top = 372 + TabOrder = 8 end inherited ButtonBevel: TBevel Top = 356 @@ -55,7 +58,7 @@ inherited AxSAnovaForm: TAxSAnovaForm MultiSelect = True OnDblClick = VarListDblClick OnSelectionChange = VarListSelectionChange - TabOrder = 4 + TabOrder = 0 end object DepInBtn: TBitBtn[7] AnchorSideLeft.Control = ParamsPanel @@ -69,7 +72,7 @@ inherited AxSAnovaForm: TAxSAnovaForm ImageIndex = 1 OnClick = DepInBtnClick Spacing = 0 - TabOrder = 5 + TabOrder = 1 end object DepOutBtn: TBitBtn[8] AnchorSideLeft.Control = ParamsPanel @@ -85,7 +88,7 @@ inherited AxSAnovaForm: TAxSAnovaForm ImageIndex = 0 OnClick = DepOutBtnClick Spacing = 0 - TabOrder = 6 + TabOrder = 3 end object RepInBtn: TBitBtn[9] AnchorSideLeft.Control = ParamsPanel @@ -101,7 +104,7 @@ inherited AxSAnovaForm: TAxSAnovaForm ImageIndex = 1 OnClick = RepInBtnClick Spacing = 0 - TabOrder = 7 + TabOrder = 4 end object RepOutBtn: TBitBtn[10] AnchorSideLeft.Control = ParamsPanel @@ -117,7 +120,7 @@ inherited AxSAnovaForm: TAxSAnovaForm ImageIndex = 0 OnClick = RepOutBtnClick Spacing = 0 - TabOrder = 8 + TabOrder = 5 end object GroupBox1: TGroupBox[11] AnchorSideLeft.Control = ParamsPanel @@ -138,27 +141,27 @@ inherited AxSAnovaForm: TAxSAnovaForm ChildSizing.ControlsPerLine = 2 ClientHeight = 31 ClientWidth = 278 - TabOrder = 9 - object PlotChk: TCheckBox - Left = 12 - Height = 19 - Top = 6 - Width = 102 - Caption = 'Plot Cell Means' - TabOrder = 0 - end + TabOrder = 7 object PosthocChk: TCheckBox - Left = 130 + Left = 12 Height = 19 Top = 6 Width = 136 BorderSpacing.Left = 8 Caption = 'Posthoc Comparisons' + TabOrder = 0 + end + object PlotChk: TCheckBox + Left = 164 + Height = 19 + Top = 6 + Width = 102 + Caption = 'Plot Cell Means' TabOrder = 1 end end object Label2: TLabel[12] - AnchorSideLeft.Control = GrpVar + AnchorSideLeft.Control = GrpVarEdit AnchorSideTop.Control = DepInBtn Left = 164 Height = 15 @@ -177,7 +180,7 @@ inherited AxSAnovaForm: TAxSAnovaForm Caption = 'Repeated Measures' ParentColor = False end - object GrpVar: TEdit[14] + object GrpVarEdit: TEdit[14] AnchorSideLeft.Control = DepInBtn AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = Label2 @@ -190,10 +193,10 @@ inherited AxSAnovaForm: TAxSAnovaForm Width = 127 Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 6 - OnChange = GrpVarChange + OnChange = GrpVarEditChange ReadOnly = True - TabOrder = 10 - Text = 'GrpVar' + TabOrder = 2 + Text = 'GrpVarEdit' end object RepList: TListBox[15] AnchorSideLeft.Control = RepInBtn @@ -214,7 +217,7 @@ inherited AxSAnovaForm: TAxSAnovaForm MultiSelect = True OnDblClick = RepListDblClick OnSelectionChange = VarListSelectionChange - TabOrder = 11 + TabOrder = 6 end end inherited ParamsSplitter: TSplitter @@ -223,8 +226,8 @@ inherited AxSAnovaForm: TAxSAnovaForm inherited PageControl: TPageControl Height = 397 Width = 457 - ActivePage = PosthocPage - TabOrder = 0 + ActivePage = ReportPage + TabIndex = 0 inherited ReportPage: TTabSheet Caption = 'ANOVA Results' end diff --git a/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.pas b/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.pas index de7a55eb8..23b985b2b 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.pas +++ b/applications/lazstats/source/forms/analysis/comparisons/axsanovaunit.pas @@ -9,8 +9,7 @@ interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, TAStyles, - MainUnit, FunctionsLib, GraphLib, Globals, - DataProcs, ReportFrameUnit, BasicStatsReportAndChartFormUnit; + MainUnit, Globals, DataProcs, ReportFrameUnit, BasicStatsReportAndChartFormUnit; type @@ -24,7 +23,7 @@ type RepInBtn: TBitBtn; RepOutBtn: TBitBtn; PlotChk: TCheckBox; - GrpVar: TEdit; + GrpVarEdit: TEdit; GroupBox1: TGroupBox; Label1: TLabel; Label2: TLabel; @@ -34,7 +33,7 @@ type VarList: TListBox; procedure DepInBtnClick(Sender: TObject); procedure DepOutBtnClick(Sender: TObject); - procedure GrpVarChange(Sender: TObject); + procedure GrpVarEditChange(Sender: TObject); procedure RepInBtnClick(Sender: TObject); procedure RepListDblClick(Sender: TObject); procedure RepOutBtnClick(Sender: TObject); @@ -44,7 +43,7 @@ type private FPosthocReportFrame: TReportFrame; - procedure Plot(AData: DblDyneMat; ANumRows, ANumCols: Integer); + procedure Plot(AMeans: DblDyneMat; ANumRows, ANumCols: Integer); procedure PostHocTests(NoSelected: integer; MSerr: double; dferr: integer; Count: integer; ColMeans: DblDyneVec; AReport: TStrings); @@ -52,56 +51,7 @@ type procedure AdjustConstraints; override; procedure Compute; override; procedure UpdateBtnStates; override; - - // wp: replace the following methods by those in ANOVATestUnit? - procedure Tukey( - error_ms : double; { mean squared for residual } - error_df : double; { deg. freedom for residual } - value : double; { size of smallest group } - group_total : DblDyneVec; { sum of scores in a group } - group_count : DblDyneVec; { no. of cases in a group } - min_grp : integer; { minimum group code } - max_grp : integer; { maximum group code } - AReport : TStrings); - - procedure ScheffeTest( - error_ms : double; { mean squared residual } - group_total : DblDyneVec; { sum of scores in a group } - group_count : DblDyneVec; { count of cases in a group } - min_grp : integer; { code of first group } - max_grp : integer; { code of last group } - total_n : double; { total number of cases } - AReport : TStrings); - - procedure Newman_Keuls( - error_ms : double; { residual mean squared } - error_df : double; { deg. freedom for error } - value : double; { number in smallest group } - group_total : DblDyneVec; { sum of scores in a group } - group_count : DblDyneVec; { count of cases in a group } - min_grp : integer; { lowest group code } - max_grp : integer; { largest group code } - AReport : TStrings); - - procedure Tukey_Kramer( - error_ms : double; { residual mean squared } - error_df : double; { deg. freedom for error } - value : double; { number in smallest group } - group_total : DblDyneVec; { sum of scores in group } - group_count : DblDyneVec; { number of caes in group } - min_grp : integer; { code of lowest group } - max_grp : integer; { code of highst group } - AReport : TStrings); - - procedure TukeyBTest( - ErrorMS : double; { within groups error } - ErrorDF : double; { degrees of freedom within } - group_total : DblDyneVec; { vector of group sums } - group_count : DblDyneVec; { vector of group n's } - min_grp : integer; { smallest group code } - max_grp : integer; { largest group code } - groupsize : double; { size of groups (all equal) } - AReport : TStrings); + function Validate(out AMsg:String; out AControl: TWinControl): Boolean; override; public constructor Create(AOwner: TComponent); override; @@ -118,10 +68,12 @@ implementation {$R *.lfm} uses - Math, - TAChartUtils, TACustomSource, TACustomSeries, TASeries, - Utils, MathUnit, ChartFrameUnit; + Math, StrUtils, + TAChartUtils, TALegend, TACustomSource, TACustomSeries, TASeries, + ANOVATestsUnit, Utils, GridProcs, MathUnit, ChartFrameUnit; +const + COL_WIDTH = 10; { TAxSAnovaForm } @@ -135,8 +87,8 @@ begin InitToolbar(FPosthocReportFrame.ReportToolbar, tpTop); PostHocPage.PageIndex := 1; - if GraphFrm = nil then - Application.CreateForm(TGraphFrm, GraphFrm); + FChartFrame.Chart.Margins.Bottom := 0; + FChartFrame.Chart.BottomAxis.AxisPen.Visible := true; end; @@ -156,61 +108,53 @@ end; procedure TAxSAnovaForm.Compute; var - a1, a2, agrp, i, j, k, v1, totaln, NoSelected, range: integer; - group, col: integer; - p, X, f1, f2, f3, probf1, probf2, probf3, fd1, fd2, TotMean: double; - TotStdDev, den, maxmean: double; C: DblDyneMat = nil; StdDev: DblDyneMat = nil; squaredsumx: DblDyneVec = nil; sumxsquared: DblDyneVec = nil; coltot: DblDyneVec = nil; sumsum: DblDyneVec = nil; - degfree: array[1..8] of integer; ColNoSelected: IntDyneVec = nil; + N: IntDyneVec = nil; + a1, a2, agrp, i, j, k, v1, totaln, NoSelected, range: integer; + group, col: integer; + p, X, Xsq, f1, f2, f3, probf1, probf2, probf3, fd1, fd2, TotMean: double; + TotStdDev, den: double; + degfree: array[1..8] of integer; ss: array[1..8] of double; ms: array[1..8] of double; coeff: array[1..6] of double; - N: IntDyneVec; - value, outline: string; + outline, separatorLine: string; lReport: TStrings; begin - if GrpVar.Text = '' then - begin - MessageDlg('Select a variable for between-groups treatment groups', mtError, [mbOK], 0); - exit; - end; - - if RepList.Items.Count < 2 then - begin - MessageDlg('This test requires at least two variables for repeated measurements.', mtError, [mbOK], 0); - exit; - end; - SetLength(ColNoSelected, NoVariables+1); - NoSelected := 1; // Get between subjects group variable - for j := 1 to NoVariables do - if GrpVar.Text = OS3MainFrm.DataGrid.Cells[j,0] then ColNoSelected[0] := j; - v1 := ColNoSelected[0]; //A treatment (group) variable + v1 := GetVariableIndex(OS3MainFrm.DataGrid, GrpVarEdit.Text); + ColNoSelected[0] := v1; // A treatment (group) variable + + // Get items selected for repeated measures (B treatments) + for i := 0 to RepList.Items.Count - 1 do + ColNoSelected[i+1] := GetVariableIndex(OS3MainFrm.DataGrid, RepList.Items[i]); // +1 because grp var is at index 0 + + NoSelected := RepList.Items.Count + 1; + SetLength(ColNoSelected, NoSelected); // Trim array to correct size //get minimum and maximum group codes for Treatment A - a1 := 1000; //atoi(MainForm.Grid.Cells[v1][1].c_str()); - a2 := 0; //a1; + a1 := MaxInt; + a2 := -MaxInt; for i := 1 to NoCases do Begin - if not GoodRecord(i,NoSelected,ColNoSelected) then continue; - group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v1,i]))); + if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; + group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v1, i]))); if group < a1 then a1 := group; if group > a2 then a2 := group; end; range := a2 - a1 + 1; - NoSelected := RepList.Items.Count + 1; k := NoSelected - 1; //Number of B (within subject) treatment levels // allocate heap - SetLength(C, range+1, NoSelected+1); + SetLength(C, range+1, NoSelected+1); // wp: why +1? SetLength(N, range+1); SetLength(squaredsumx, range+1); SetLength(coltot, NoSelected+1); @@ -242,77 +186,64 @@ begin TotMean := 0.0; totaln := 0; - // Get items selected for repeated measures (B treatments) - for i := 0 to RepList.Items.Count - 1 do - begin - for j := 1 to NoVariables do - if RepList.Items.Strings[i] = OS3MainFrm.DataGrid.Cells[j,0] then - ColNoSelected[i+1] := j; - end; - //Read data values and get sums and sums of squared values for i := 1 to NoCases do begin - if not GoodRecord(i,NoSelected,ColNoSelected) then continue; - agrp := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v1,i]))); - agrp := agrp - a1 + 1; // offset to one + if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; + agrp := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v1, i]))); + agrp := agrp - a1; p := 0.0; //Now read the B treatment scores - for j := 1 to k do + for j := 0 to k-1 do begin - col := ColNoSelected[j]; - if not GoodRecord(i,NoSelected,ColNoSelected) then continue; - X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col,i])); - C[agrp-1,j-1] := C[agrp-1,j-1] + X; - StdDev[agrp-1,j-1] := StdDev[agrp-1,j-1] + (X * X); - coeff[1]:= coeff[1] + X; + col := ColNoSelected[j+1]; // Offset +1 because Grp var is at index 0 + if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; + X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col, i])); + Xsq := X * X; + C[agrp, j] := C[agrp, j] + X; + StdDev[agrp, j] := StdDev[agrp, j] + Xsq; + coeff[1] := coeff[1] + X; p := p + X; - sumxsquared[agrp-1] := sumxsquared[agrp-1] + (X * X); + sumxsquared[agrp] := sumxsquared[agrp] + Xsq; TotMean := TotMean + X; - TotStdDev := TotStdDev + (X * X); + TotStdDev := TotStdDev + Xsq; end; - N[agrp-1] := N[agrp-1] + 1; - squaredsumx[agrp-1] := squaredsumx[agrp-1] + (p * p); - sumsum[agrp-1] := sumsum[agrp-1] + p; + N[agrp] := N[agrp] + 1; + squaredsumx[agrp] := squaredsumx[agrp] + p * p; + sumsum[agrp] := sumsum[agrp] + p; end; // next case // Obtain sums of squares for std. dev.s of B treatments - for i := 1 to k do // column (B treatments) - for j := 1 to range do // group of A treatments - StdDev[range,i-1] := StdDev[range,i-1] + StdDev[j-1,i-1]; + for i := 0 to k-1 do // column (B treatments) + for j := 0 to range-1 do // group of A treatments + StdDev[range, i] := StdDev[range, i] + StdDev[j, i]; // Obtain sums of squares for std. dev.s of A treatments - for i := 1 to range do - for j := 1 to k do - StdDev[i-1,k] := StdDev[i-1,k] + StdDev[i-1,j-1]; + for i := 0 to range-1 do + for j := 0 to k-1 do + StdDev[i, k] := StdDev[i, k] + StdDev[i, j]; // Obtain cell standard deviations - for i := 1 to range do // rows - begin - for j := 1 to k do // columns - begin - StdDev[i-1,j-1] := StdDev[i-1,j-1] - ((C[i-1,j-1] * C[i-1,j-1]) / (N[i-1])); - StdDev[i-1,j-1] := StdDev[i-1,j-1] / (N[i-1]-1); - StdDev[i-1,j-1] := sqrt(StdDev[i-1,j-1]); - end; - end; + for i := 0 to range-1 do // rows + for j := 0 to k-1 do // columns + StdDev[i, j] := sqrt((StdDev[i, j] - sqr(C[i, j]) / N[i]) / (N[i] - 1)); // Obtain A treatment group standard deviations - for i := 1 to range do + for i := 0 to range-1 do begin - StdDev[i-1,k] := StdDev[i-1,k] - ((sumsum[i-1] * sumsum[i-1]) / (k * N[i-1])); - StdDev[i-1,k] := StdDev[i-1,k] / (k * N[i-1] - 1); - StdDev[i-1,k] := sqrt(StdDev[i-1,k]); + StdDev[i, k] := StdDev[i, k] - ((sumsum[i] * sumsum[i]) / (k * N[i])); + StdDev[i, k] := StdDev[i, k] / (k * N[i] - 1); + StdDev[i, k] := sqrt(StdDev[i, k]); end; // Obtain coefficients for the sums of squares - for i := 1 to range do + for i := 0 to range-1 do begin - coeff[2] := coeff[2] + sumxsquared[i-1]; - coeff[3] := coeff[3] + ((sumsum[i-1] * (sumsum[i-1]) / ((N[i-1] * k)))); - coeff[6] := coeff[6] + squaredsumx[i-1]; - totaln := totaln + N[i-1]; + coeff[2] := coeff[2] + sumxsquared[i]; + coeff[3] := coeff[3] + ((sumsum[i] * (sumsum[i]) / ((N[i] * k)))); + coeff[6] := coeff[6] + squaredsumx[i]; + totaln := totaln + N[i]; end; coeff[1] := (coeff[1] * coeff[1]) / (totaln * k); den := k; @@ -331,11 +262,11 @@ begin coeff[4] := coeff[4] / den; // Obtain B treatment group standard deviations - for j := 1 to k do + for j := 0 to k-1 do begin - StdDev[range,j-1] := StdDev[range,j-1] - ((coltot[j-1] * coltot[j-1]) / totaln); - StdDev[range,j-1] := StdDev[range,j-1] / (totaln-1); - StdDev[range,j-1] := sqrt(StdDev[range,j-1]); + StdDev[range, j] := StdDev[range, j] - ((coltot[j] * coltot[j]) / totalN); + StdDev[range, j] := StdDev[range, j] / (totalN-1); + StdDev[range, j] := sqrt(StdDev[range, j]); end; // Calculate degrees of freedom for the mean squares @@ -405,101 +336,98 @@ begin lReport.Add('------------------------------------------------------------------'); //Calculate and print means - lReport.Add('Means'); - outline := 'TRT. '; - for i := 1 to k do - begin - value := Format('B%3d ', [i]); - outline := outline + value; - end; - outline := outline + 'TOTAL'; - lReport.Add(outline); - lReport.Add(' A '); - for i := 1 to range do + for i := 0 to range-1 do begin for j := 1 to k do - C[i-1,j-1] := C[i-1,j-1] / N[i-1]; //mean of each B treatment within A treatment - sumsum[i-1] := sumsum[i-1] / (N[i-1] * k); //means in A treatment accross B treatments + C[i, j-1] := C[i, j-1] / N[i]; //mean of each B treatment within A treatment + sumsum[i] := sumsum[i] / (N[i] * k); //means in A treatment accross B treatments end; - for j := 1 to k do - coltot[j-1] := coltot[j-1] / totaln; - TotStdDev := TotStdDev - ((TotMean * TotMean) / (k * totaln)); - TotStdDev := TotStdDev / (k * totaln - 1); + for j := 0 to k-1 do + coltot[j] := coltot[j] / totalN; + TotStdDev := TotStdDev - ((TotMean * TotMean) / (k * totalN)); + TotStdDev := TotStdDev / (k * totalN - 1); TotStdDev := sqrt(TotStdDev); - TotMean := TotMean / (k * totaln); - for i := 1 to range do + TotMean := TotMean / (k * totalN); + + lReport.Add(''); + lReport.Add('MEANS'); + separatorLine := DupeString('-', COL_WIDTH + (k+1)*(COL_WIDTH + 2)- 2); + lReport.Add(separatorLine); + outline := Format('%*s ', [COL_WIDTH-1, 'Treatment']);; + for i := 0 to k-1 do + outline := outline + CenterString('B'+IntToStr(i+1), COL_WIDTH) + ' '; + outline := outline + CenterString('TOTAL', COL_WIDTH); + lReport.Add(outline); + outline := DupeString(' ', COL_WIDTH-1) + '+'; + for i := 0 to k-1 do + outline := outline + DupeString('-', COL_WIDTH) + ' '; + outline := outline + DupeString('-', COL_WIDTH); + lReport.Add(outline); + + for i := 0 to range-1 do begin - outline := Format('%3d ', [i+a1-1]); - for j := 1 to k do - begin - value := format('%7.3f', [C[i-1,j-1]]); - outline := outline + value; - end; - value := Format('%7.3f', [sumsum[i-1]]); - outline := outline + value; + outline := Format('%*s |', [COL_WIDTH-2, 'A' + IntToStr(i+a1)]); + for j := 0 to k-1 do + outline := outline + Format('%*.3f ', [COL_WIDTH, C[i, j]]); + outline := outline + Format('%*.3f', [COL_WIDTH, sumSum[i]]); lReport.Add(outline); end; - outline := 'TOTAL'; - for j := 1 to k do - begin - value := Format('%7.3f', [coltot[j-1]]); - outline := outline + value; - end; - value := Format('%7.3f', [TotMean]); - outline := outline + value; + outline := Format('%*s |', [COL_WIDTH-2, 'TOTAL']);; + for j := 0 to k-1 do + outline := outline + Format('%*.3f ', [COL_WIDTH, coltot[j]]); + outline := outline + Format('%*.3f', [COL_WIDTH, TotMean]); lReport.Add(outline); + lReport.Add(separatorLine); // Print standard deviations lReport.Add(''); - lReport.Add('Standard Deviations'); - outline := 'TRT. '; - for i := 1 to k do - begin - value := Format('B%3d ', [i]); - outline := outline + value; - end; - outline := outline + 'TOTAL'; + lReport.Add('STANDARD DEVIATIONS'); + + lReport.Add(separatorLine); + outline := Format('%*s ', [COL_WIDTH-1, 'Treatment']);; + for i := 0 to k-1 do + outline := outline + CenterString('B'+IntToStr(i+1), COL_WIDTH) + ' '; + outline := outline + CenterString('TOTAL', COL_WIDTH); lReport.Add(outline); - lReport.Add(' A '); - for i := 1 to range do + + outline := DupeString(' ', COL_WIDTH-1) + '+'; + for i := 0 to k-1 do + outline := outline + DupeString('-', COL_WIDTH) + ' '; + outline := outline + DupeString('-', COL_WIDTH); + lReport.Add(outline); + + for i := 0 to range-1 do begin - outline := Format('%3d ', [i+a1-1]); - for j := 1 to k do - begin - value := Format('%7.3f', [StdDev[i-1,j-1]]); - outline := outline + value; - end; - value := Format('%7.3f', [StdDev[i-1,k]]); - outline := outline + value; + outline := Format('%*s |', [COL_WIDTH-2, 'A' + IntToStr(i+a1)]); + for j := 0 to k-1 do + outline := outline + Format('%*.3f ', [COL_WIDTH, StdDev[i, j]]); + outline := outline + Format('%*.3f', [COL_WIDTH, StdDev[i, k]]); lReport.Add(outline); end; - outline := 'TOTAL'; - for j := 1 to k do - begin - value := Format('%7.3f', [StdDev[range,j-1]]); - outline := outline + value; - end; - value := Format('%7.3f', [TotStdDev]); - outline := outline + value; + outline := Format('%*s |', [COL_WIDTH-2, 'TOTAL']);; + for j := 0 to k-1 do + outline := outline + Format('%*.3f ', [COL_WIDTH, StdDev[range, j]]); + outline := outline + Format('%*.3f', [COL_WIDTH, TotStdDev]); lReport.Add(outline); + lReport.Add(separatorLine); + FReportFrame.DisplayReport(lReport); if PosthocChk.Checked then begin lReport.Clear; // Do tests for the A (between groups) - lReport.Add(''); - lReport.Add('==============================================================='); - lReport.Add(''); - lReport.Add('COMPARISONS FOR THE BETWEEN-GROUP MEANS'); + lReport.Add('********************************************'); + lReport.Add('* COMPARISONS FOR THE BETWEEN-GROUP MEANS *'); + lReport.Add('*********************************************'); PostHocTests(range, MS[1], degfree[1], range, sumsum, lReport); lReport.Add(''); // Do tests for the B (repeated measures) lReport.Add(''); - lReport.Add('==============================================================='); - lReport.Add(''); - lReport.Add('COMPARISONS FOR THE REPEATED-MEASURES MEANS'); + lReport.Add('*************************************************'); + lReport.Add('* COMPARISONS FOR THE REPEATED-MEASURES MEANS *'); + lReport.Add('*************************************************'); PostHocTests(k, ms[4], degfree[4], NoCases, coltot, lReport); FPostHocReportFrame.DisplayReport(lReport); @@ -559,7 +487,39 @@ begin end; -procedure TAxSAnovaForm.Plot(AData: DblDyneMat; ANumRows, ANumCols: Integer); +procedure TAxSAnovaForm.DepInBtnClick(Sender: TObject); +var + index: integer; +begin + index := VarList.ItemIndex; + if (index > -1) and (GrpVarEdit.Text = '') then + begin + GrpVarEdit.Text := VarList.Items[index]; + VarList.Items.Delete(index); + end; + VarList.ItemIndex := -1; + UpdateBtnStates; +end; + + +procedure TAxSAnovaForm.DepOutBtnClick(Sender: TObject); +begin + if GrpVarEdit.Text <> '' then + begin + VarList.Items.Add(GrpVarEdit.Text); + GrpVarEdit.Text := ''; + end; + UpdateBtnStates; +end; + + +procedure TAxSAnovaForm.GrpVarEditChange(Sender: TObject); +begin + UpdateBtnStates; +end; + + +procedure TAxSAnovaForm.Plot(AMeans: DblDyneMat; ANumRows, ANumCols: Integer); var ser: TChartSeries; i, j, idx: Integer; @@ -583,13 +543,14 @@ begin idx := ser.AddXY(j+1, NaN); item := ser.Source.Item[idx]; for i := 0 to ANumRows-1 do - item^.SetY(i, AData[i, j]); + item^.SetY(i, AMeans[i, j]); end; with (ser as TBarSeries) do begin Stacked := false; Styles := ChartStyles; + Legend.Multiplicity := lmStyle; end; for i := 0 to ANumRows-1 do @@ -604,431 +565,35 @@ begin FChartFrame.Chart.BottomAxis.Marks.Source := ser.Source; FChartFrame.Chart.BottomAxis.Marks.Style := smsXValue; - FChartFrame.Chart.Legend.Visible := false; + //FChartFrame.Chart.Legend.Visible := false; ChartPage.TabVisible := true; - (* - maxmean := 0.0; - SetLength(GraphFrm.Ypoints,range,k); - SetLength(GraphFrm.Xpoints,1,k); - for i := 1 to range do - begin - GraphFrm.SetLabels[i] := 'A ' + IntToStr(i); - for j := 1 to k do - begin - GraphFrm.Ypoints[i-1,j-1] := C[i-1,j-1]; - if C[i-1,j-1] > maxmean then - maxmean := C[i-1,j-1]; - end; - end; - - for j := 1 to k do - begin - coltot[j-1] := j; - GraphFrm.Xpoints[0,j-1] := j; - end; - - GraphFrm.nosets := range; - GraphFrm.nbars := k; - GraphFrm.Heading := 'TREATMENTS X SUBJECT REPLICATIONS ANOVA'; - GraphFrm.XTitle := 'WITHIN (B) TREATMENT GROUP'; - GraphFrm.YTitle := 'Mean'; - GraphFrm.barwideprop := 0.5; - GraphFrm.AutoScaled := false; - GraphFrm.GraphType := 2; // 3d Vertical Bar Chart - GraphFrm.miny := 0.0; - GraphFrm.maxy := maxmean; - GraphFrm.BackColor := clCream; - GraphFrm.WallColor := clDkGray; - GraphFrm.FloorColor := clLtGray; - GraphFrm.ShowBackWall := true; - GraphFrm.ShowModal; - *) -end; - -procedure TAxSAnovaForm.DepInBtnClick(Sender: TObject); -var - index: integer; -begin - index := VarList.ItemIndex; - if (index > -1) and (GrpVar.Text = '') then - begin - GrpVar.Text := VarList.Items[index]; - VarList.Items.Delete(index); - end; - VarList.ItemIndex := -1; - UpdateBtnStates; -end; - - -procedure TAxSAnovaForm.DepOutBtnClick(Sender: TObject); -begin - if GrpVar.Text <> '' then - begin - VarList.Items.Add(GrpVar.Text); - GrpVar.Text := ''; - end; - UpdateBtnStates; -end; - - -procedure TAxSAnovaForm.GrpVarChange(Sender: TObject); -begin - UpdateBtnStates; end; procedure TAxSAnovaForm.PostHocTests(NoSelected: Integer; MSerr: double; dferr: integer; Count: integer; ColMeans: DblDyneVec; AReport: TStrings); var - group_total: DblDyneVec = nil; - group_count: DblDyneVec = nil; + groupTotal: DblDyneVec = nil; + groupCount: IntDyneVec = nil; i, mingrp: integer; + alpha: Double; begin - SetLength(group_total,NoSelected); - SetLength(group_count,NoSelected); + SetLength(groupTotal ,NoSelected); + SetLength(groupCount, NoSelected); for i := 0 to NoSelected - 1 do begin - group_count[i] := double(Count); - group_total[i] := double(Count) * ColMeans[i]; + groupCount[i] := Count; + groupTotal[i] := ColMeans[i] * Count;; end; mingrp := 1; - Tukey(MSerr, dferr, Count, group_total, group_count, mingrp, NoSelected, AReport); - Tukey_Kramer(MSerr, dferr, Count, group_total, group_count, mingrp, NoSelected, AReport); - TukeyBTest(MSerr, dferr, group_total, group_count, mingrp,NoSelected, Count, AReport); - ScheffeTest(MSerr, group_total, group_count, mingrp, NoSelected, Count*NoSelected, AReport); - Newman_Keuls(MSerr, dferr, Count, group_total, group_count, mingrp, NoSelected, AReport); -end; - - -procedure TAxSAnovaForm.Tukey( - error_ms : double; { mean squared for residual } - error_df : double; { deg. freedom for residual } - value : double; { size of smallest group } - group_total : DblDyneVec; { sum of scores in a group } - group_count : DblDyneVec; { no. of cases in a group } - min_grp : integer; { minimum group code } - max_grp : integer; { maximum group code } - AReport : TStrings); -var - sig: boolean; - divisor: double; - df1: integer; - alpha: double; - contrast, mean1, mean2: double; - q_stat: double; - i,j: integer; - outline: string; -begin - alpha := DEFAULT_ALPHA_LEVEL; - AReport.Add('---------------------------------------------------------------'); - AReport.Add(' Tukey HSD Test for Differences Between Means'); - AReport.Add(' alpha selected = %.2f', [alpha]); - AReport.Add(''); - AReport.Add('Groups Difference Statistic Probability Significant?'); - AReport.Add('---------------------------------------------------------------'); - - divisor := sqrt(error_ms / value); - for i := min_grp to max_grp - 1 do - for j := i + 1 to max_grp do - begin - outline := Format('%2d - %2d ', [i,j]); - mean1 := group_total[i-1] / group_count[i-1]; - mean2 := group_total[j-1] / group_count[j-1]; - contrast := mean1 - mean2; - outline := outline + Format('%7.3f q = ', [contrast]); - contrast := abs(contrast / divisor) ; - outline := outline + Format('%6.3f ', [contrast]); - df1 := max_grp - min_grp + 1; - q_stat := STUDENT(contrast, error_df, df1); - outline := outline + Format(' %6.4f', [q_stat]); - if alpha >= q_stat then sig := TRUE else sig := FALSE; - if sig = TRUE then - outline := outline + ' YES ' - else - outline := outline + ' NO'; - AReport.Add(outline); - end; - - AReport.Add('---------------------------------------------------------------'); -end; - -procedure TAxSAnovaForm.ScheffeTest( - error_ms : double; { mean squared residual } - group_total : DblDyneVec; { sum of scores in a group } - group_count : DblDyneVec; { count of cases in a group } - min_grp : integer; { code of first group } - max_grp : integer; { code of last group } - total_n : double; { total number of cases } - AReport : TStrings); -var - statistic, stat_var, stat_sd: double; - mean1, mean2, alpha, difference, prob_scheffe, f_prob, df1, df2: double; - outline: string; - i, j: integer; -begin - alpha := DEFAULT_ALPHA_LEVEL; - AReport.Add(''); - AReport.Add('----------------------------------------------------------------'); - AReport.Add(' Scheffe contrasts among pairs of means.'); - AReport.Add(' alpha selected = %.2f', [alpha]); - AReport.Add(''); - AReport.Add('Group vs Group Difference Scheffe Critical Significant?'); - AReport.Add(' Statistic Value'); - AReport.Add('----------------------------------------------------------------'); - - alpha := 1.0 - alpha ; - for i:= min_grp to max_grp - 1 do - for j := i + 1 to max_grp do - begin - outline := Format('%2d %2d ', [i,j]); - mean1 := group_total[i-1] / group_count[i-1]; - mean2 := group_total[j-1] / group_count[j-1]; - difference := mean1 - mean2; - outline := outline + Format('%8.2f ', [difference]); - stat_var := error_ms * ( 1.0 / group_count[i-1] + 1.0 / group_count[j-1]); - stat_sd := sqrt(stat_var); - statistic := abs(difference / stat_sd); - outline := outline + Format('%8.2f ', [statistic]); - df1 := max_grp - min_grp; - df2 := total_n - df1 + 1; - f_prob := fpercentpoint(alpha, round(df1), round(df2) ); - prob_scheffe := sqrt(df1 * f_prob); - outline := outline + Format('%8.3f ', [prob_scheffe]); - if statistic > prob_scheffe then - outline := outline + 'YES' - else - outline := outline + 'NO'; - AReport.Add(outline); - end; - - AReport.Add('----------------------------------------------------------------'); -end; - -procedure TAxSAnovaForm.Newman_Keuls( - error_ms : double; { residual mean squared } - error_df : double; { deg. freedom for error } - value : double; { number in smallest group } - group_total : DblDyneVec; { sum of scores in a group } - group_count : DblDyneVec; { count of cases in a group } - min_grp : integer; { lowest group code } - max_grp : integer; { largest group code } - AReport : TStrings); -var - i, j: integer; - temp1, temp2: double; - groupno: IntDyneVec = nil; - alpha: double; - contrast, mean1, mean2: double; - q_stat: double; - divisor: double; - tempno: integer; - df1: integer; - sig: boolean; - outline: string; -begin - SetLength(groupno, max_grp - min_grp + 1); - - for i := min_grp to max_grp do - groupno[i-1] := i; - - for i := min_grp to max_grp - 1 do - begin - for j := i + 1 to max_grp do - begin - if group_total[i-1] / group_count[i-1] > group_total[j-1] / group_count[j-1] then - begin - temp1 := group_total[i-1]; - temp2 := group_count[i-1]; - tempno := groupno[i-1]; - group_total[i-1] := group_total[j-1]; - group_count[i-1] := group_count[j-1]; - groupno[i-1] := groupno[j-1]; - group_total[j-1] := temp1; - group_count[j-1] := temp2; - groupno[j-1] := tempno; - end; - end; - end; - - alpha := DEFAULT_ALPHA_LEVEL; - AReport.Add(''); - AReport.Add('----------------------------------------------------------------------'); - AReport.Add(' Neuman-Keuls Test for Contrasts on Ordered Means'); - AReport.Add(' alpha selected = %.2f', [alpha]); - AReport.Add(''); - AReport.Add('Group Mean'); - for i := 1 to max_grp do - AReport.Add('%3d %10.3f', [groupno[i-1], group_total[i-1] / group_count[i-1]]); - AReport.Add(''); - AReport.Add('Groups Difference Statistic d.f. Probability Significant?'); - AReport.Add('----------------------------------------------------------------------'); - - divisor := sqrt(error_ms / value); - for i := min_grp to max_grp - 1 do - begin - for j := i + 1 to max_grp do - begin - outline := Format('%2d - %2d ', [groupno[i-1], groupno[j-1]]); - mean1 := group_total[i-1] / group_count[i-1]; - mean2 := group_total[j-1] / group_count[j-1]; - contrast := mean1 - mean2; - outline := outline + Format('%7.3f q = ', [contrast]); - contrast := abs(contrast / divisor ); - df1 := j - i + 1; - outline := outline + Format('%6.3f %2d %3.0f ', [contrast, df1, error_df]); - q_stat := STUDENT(contrast, error_df, df1); - outline := outline + Format(' %6.4f', [q_stat]); - sig := alpha > q_stat; - if sig then - outline := outline + ' YES' - else - outline := outline + ' NO'; - AReport.Add(outline); - end; - end; - - AReport.Add('----------------------------------------------------------------------'); - groupno := nil; -end; - -procedure TAxSAnovaForm.Tukey_Kramer( - error_ms : double; { residual mean squared } - error_df : double; { deg. freedom for error } - value : double; { number in smallest group } - group_total : DblDyneVec; { sum of scores in group } - group_count : DblDyneVec; { number of caes in group } - min_grp : integer; { code of lowest group } - max_grp : integer; { code of highst group } - AReport : TStrings); -var - sig: boolean; - divisor: double; - df1: integer; - alpha: double; - contrast, mean1, mean2: double; - q_stat: double; - outline: string; - i, j: integer; -begin - alpha := DEFAULT_ALPHA_LEVEL; - AReport.Add(''); - AReport.Add('---------------------------------------------------------------'); - AReport.Add(' Tukey-Kramer Test for Differences Between Means'); - AReport.Add(' alpha selected = %.2f', [alpha]); - AReport.Add(''); - AReport.Add('Groups Difference Statistic Probability Significant?'); - AReport.Add('---------------------------------------------------------------'); - - for i := min_grp to max_grp - 1 do - for j := i + 1 to max_grp do - begin - outline := Format('%2d - %2d ', [i, j]); - mean1 := group_total[i-1] / group_count[i-1]; - mean2 := group_total[j-1] / group_count[j-1]; - contrast := mean1 - mean2; - outline := outline + Format('%7.3f q = ', [contrast]); - divisor := sqrt(error_ms * ((1.0/group_count[i-1] + 1.0/group_count[j-1]) / 2)); - contrast := abs(contrast / divisor) ; - outline := outline + Format('%6.3f ', [Contrast]); - df1 := max_grp - min_grp + 1; - q_stat := STUDENT(contrast, error_df, df1); - outline := outline + Format(' %6.4f', [q_stat]); - sig := alpha >= q_stat; - if sig then - outline := outline + ' YES ' - else - outline := outline + ' NO'; - AReport.Add(outline); - end; - - AReport.Add('---------------------------------------------------------------'); -end; - -procedure TAxSAnovaForm.TukeyBTest( - ErrorMS : double; // within groups error - ErrorDF : double; // degrees of freedom within - group_total : DblDyneVec; // vector of group sums - group_count : DblDyneVec; // vector of group n's - min_grp : integer; // smallest group code - max_grp : integer; // largest group code - groupsize : double; // size of groups (all equal) - AReport : TStrings); -var - alpha : double; - outline: string; - i, j: integer; - df1: double; - qstat: double; - tstat: double; - groupno: IntDyneVec = nil; - temp1, temp2: double; - tempno: integer; - NoGrps: integer; - contrast: double; - mean1, mean2: double; - sig: string[6]; - groups: double; - divisor: double; -begin - SetLength(groupno,max_grp-min_grp+1); alpha := DEFAULT_ALPHA_LEVEL; - AReport.Add(''); - AReport.Add('---------------------------------------------------------------'); - AReport.Add(' Tukey B Test for Contrasts on Ordered Means'); - AReport.Add(' alpha selected = %.2f', [alpha]); - AReport.Add('---------------------------------------------------------------'); - AReport.Add(''); - AReport.Add('Groups Difference Statistic d.f. Prob.>value Significant?'); - - divisor := sqrt(ErrorMS / groupsize); - NoGrps := max_grp - min_grp + 1; - for i := min_grp to max_grp do - groupno[i-1] := i; - for i := 1 to NoGrps - 1 do - begin - for j := i + 1 to NoGrps do - begin - if group_total[i-1] / group_count[i-1] > group_total[j-1] / group_count[j-1] then - begin - temp1 := group_total[i-1]; - temp2 := group_count[i-1]; - tempno := groupno[i-1]; - group_total[i-1] := group_total[j-1]; - group_count[i-1] := group_count[j-1]; - groupno[i-1] := groupno[j-1]; - group_total[j-1] := temp1; - group_count[j-1] := temp2; - groupno[j-1] := tempno; - end; - end; - end; - - for i := 1 to NoGrps-1 do - begin - for j := i+1 to NoGrps do - begin - mean1 := group_total[i-1] / group_count[i-1]; - mean2 := group_total[j-1] / group_count[j-1]; - contrast := abs((mean1 - mean2) / divisor); - df1 := j - i + 1.0; - qstat := STUDENT(contrast, ErrorDF, df1); - groups := NoGrps; - tstat := STUDENT(contrast, ErrorDF, groups); - qstat := (qstat + tstat) / 2.0; - if alpha >= qstat then - sig := 'YES' - else - sig := 'NO'; - outline := Format('%3d - %3d %10.3f %10.3f %4.0f,%4.0f %5.3f %s', [ - groupno[i-1], groupno[j-1], - mean1-mean2, contrast, df1, ErrorDF, qstat, sig - ]); - AReport.Add(outline); - end; - end; - groupno := nil; + Tukey(MSerr, DFerr, Count, groupTotal, groupCount, mingrp, NoSelected, alpha, AReport); + Tukey_Kramer(MSerr, dferr, Count, groupTotal, groupCount, mingrp, NoSelected, alpha, AReport); + TukeyBTest(MSerr, dferr, groupTotal, groupCount, mingrp,NoSelected, Count, alpha, AReport); + ScheffeTest(MSerr, groupTotal, groupCount, mingrp, NoSelected, Count*NoSelected, alpha, AReport); + Newman_Keuls(MSerr, dferr, Count, groupTotal, groupCount, mingrp, NoSelected, alpha, AReport); end; @@ -1086,6 +651,7 @@ begin UpdateBtnStates; end; + procedure TAxSAnovaForm.Reset; var i: integer; @@ -1099,7 +665,7 @@ begin for i := 1 to NoVariables do VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); RepList.Items.Clear; - GrpVar.Clear; + GrpVarEdit.Clear; UpdateBtnStates; end; @@ -1115,8 +681,8 @@ begin if FPosthocReportFrame <> nil then FPosthocReportFrame.UpdateBtnStates; - DepInBtn.Enabled := (VarList.ItemIndex > -1) and (GrpVar.Text = ''); - DepOutBtn.Enabled := (GrpVar.Text <> ''); + DepInBtn.Enabled := (VarList.ItemIndex > -1) and (GrpVarEdit.Text = ''); + DepOutBtn.Enabled := (GrpVarEdit.Text <> ''); lSelected := false; for i := 0 to VarList.Items.Count-1 do @@ -1138,6 +704,28 @@ begin end; +function TAxSAnovaForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean; +begin + Result := false; + + if GrpVarEdit.Text = '' then + begin + AControl := VarList; + AMsg := 'Select a variable for between-groups treatment groups'; + exit; + end; + + if RepList.Items.Count < 2 then + begin + AControl := VarList; + AMsg := 'This test requires at least two variables for repeated measurements.'; + exit; + end; + + Result := true; +end; + + procedure TAxSAnovaForm.VarListDblClick(Sender: TObject); var index: Integer; @@ -1147,8 +735,8 @@ begin if index > -1 then begin s := VarList.Items[index]; - if GrpVar.Text = '' then - GrpVar.Text := s + if GrpVarEdit.Text = '' then + GrpVarEdit.Text := s else RepList.Items.Add(s); VarList.Items.Delete(index);