From 817793a779f61c48e69da8c0ef12b76bbfc23289 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Fri, 13 Nov 2020 17:49:49 +0000 Subject: [PATCH] LazStats: Inherit BNestAUnit from BasicStatsReportAndChartForm. Refactor. Add test data file from OpenStat samples. Refine ABCNestedUnit. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7866 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- applications/lazstats/LazStats.hlp | 3 +- applications/lazstats/data/ABNested.laz | 135 +++ applications/lazstats/data/ABNested.tab | 28 + .../analysis/comparisons/abcnestedunit.lfm | 4 +- .../analysis/comparisons/abcnestedunit.pas | 131 +-- .../analysis/comparisons/blkanovaunit.pas | 24 - .../forms/analysis/comparisons/bnestaunit.lfm | 686 +++++++------ .../forms/analysis/comparisons/bnestaunit.pas | 913 +++++++++++------- 8 files changed, 1077 insertions(+), 847 deletions(-) create mode 100644 applications/lazstats/data/ABNested.laz create mode 100644 applications/lazstats/data/ABNested.tab diff --git a/applications/lazstats/LazStats.hlp b/applications/lazstats/LazStats.hlp index 0887e9c9a..4658ef4ad 100644 --- a/applications/lazstats/LazStats.hlp +++ b/applications/lazstats/LazStats.hlp @@ -71,4 +71,5 @@ correlation, means, standard deviations and confidence interval for each correla 167=Notes: This is a non-parametric analysis of ordinal data.\nIt is similar to a two-way Analysis of Variance but utilizes a chi-square statistic (H) for determining the significance of the row, column and interaction effects. The dependent value, if not initially rank data, may be obtained first by creating a new variable with the "transformation" procedure available under the "Variables" menu. The output of this procedure contains the results both of a "traditional" 2-way ANOVA as well as the SRH results.\nIt should be noted that the power of the SRH analysis is less than that of the traditional ANOVA. It is suggested that there be at least 5 or more cases in each cell and that the design is a balanced design of fixed levels.\nThe H statistic is obtained as the division of the sum of squares for an effect by the mean square of the total and the test is performed by a chi-squared probability with the degrees of freedom equal to the SS of the effect being tested. 168=This procedure lets you enter the number of observed values and the number of expected values for one or more categories.\nEnter the values as indicated and when finished, press the compute button. 169=Directions:\nFor independent groups data, first click the variable to be analyzed then click the variable containing group codes.\nFor dependent variables it is assumed the data for each pair of values are in a case.\nEnter the names of those two variables. -170=Directions:\nThis analysis assumes that levels of Factor B are Nested within levels of Factor A. It is assumed that all factors are fixed level factors.\n\nThe variables for the group coding should be defined as integers. The dependent variable should be defined as a floating point variable. The number of cases for each ABC group should be equal and the number of B treatments in in each A level should be equal. The number of C treatment levels should be the same for each AB combination.\n\nClick the variable for each factor variable and the corresponding arrow to enter it in the edit box for that variable. Select the type of plot desired for the means (if any.) Click the Compute button to continue. \ No newline at end of file +170=Directions:\nThis analysis assumes that levels of Factor B are nested within levels of Factor A. It is assumed that all factors are fixed level factors.\n\nThe variables for the group coding should be defined as integers. The dependent variable should be defined as a floating point variable. The number of cases for each ABC group should be equal and the number of B treatments in in each A level should be equal. The number of C treatment levels should be the same for each AB combination.\n\nClick the variable for each factor variable and the corresponding arrow to enter it in the edit box for that variable. Select the type of plot desired for the means (if any.) Click the Compute button to continue. +171=Directions: This analysis assumes that levels of Factor B are nested within levels of Factor A. Unless otherwise specified, it is assumed that Factors A and B are fixed level factors. If Factor B is a random variable, check the provided box to indicate this.\n\nThe number of cases for each B group should be equal and the number of B treatements in each A level should be equal. \ No newline at end of file diff --git a/applications/lazstats/data/ABNested.laz b/applications/lazstats/data/ABNested.laz new file mode 100644 index 000000000..871f9130a --- /dev/null +++ b/applications/lazstats/data/ABNested.laz @@ -0,0 +1,135 @@ +27 +3 +A +VARIABLE 1 +1 +I +0 +99999 +L +B +VARIABLE 2 +1 +I +0 +99999 +L +Dep +VARIABLE 3 +4 +F +1 +99999 +L +Case 0 +A +B +Dep +Case 1 +1 +1 +1.00 +Case 2 +1 +1 +3.00 +Case 3 +1 +1 +4.00 +Case 4 +1 +2 +2.00 +Case 5 +1 +2 +3.00 +Case 6 +1 +2 +5.00 +Case 7 +1 +3 +3.00 +Case 8 +1 +3 +3.00 +Case 9 +1 +3 +6.00 +Case 10 +2 +4 +2.00 +Case 11 +2 +4 +4.00 +Case 12 +2 +4 +5.00 +Case 13 +2 +5 +3.00 +Case 14 +2 +5 +4.00 +Case 15 +2 +5 +5.00 +Case 16 +2 +6 +4.00 +Case 17 +2 +6 +5.00 +Case 18 +2 +6 +6.00 +Case 19 +3 +7 +3.00 +Case 20 +3 +7 +3.00 +Case 21 +3 +7 +5.00 +Case 22 +3 +8 +4.00 +Case 23 +3 +8 +5.00 +Case 24 +3 +8 +6.00 +Case 25 +3 +9 +6.00 +Case 26 +3 +9 +6.00 +Case 27 +3 +9 +7.00 diff --git a/applications/lazstats/data/ABNested.tab b/applications/lazstats/data/ABNested.tab new file mode 100644 index 000000000..2e82deb9f --- /dev/null +++ b/applications/lazstats/data/ABNested.tab @@ -0,0 +1,28 @@ +A B Dep +1 1 1.00 +1 1 3.00 +1 1 4.00 +1 2 2.00 +1 2 3.00 +1 2 5.00 +1 3 3.00 +1 3 3.00 +1 3 6.00 +2 4 2.00 +2 4 4.00 +2 4 5.00 +2 5 3.00 +2 5 4.00 +2 5 5.00 +2 6 4.00 +2 6 5.00 +2 6 6.00 +3 7 3.00 +3 7 3.00 +3 7 5.00 +3 8 4.00 +3 8 5.00 +3 8 6.00 +3 9 6.00 +3 9 6.00 +3 9 7.00 diff --git a/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.lfm b/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.lfm index 2afcda621..6e813a9c1 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.lfm +++ b/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.lfm @@ -1,7 +1,7 @@ inherited ABCNestedForm: TABCNestedForm - Left = 383 + Left = 441 Height = 481 - Top = 191 + Top = 202 Width = 843 Caption = 'Three-Factor Nested ANOVA' ClientHeight = 481 diff --git a/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.pas b/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.pas index 103d1a5d0..11ba81d98 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.pas +++ b/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.pas @@ -123,8 +123,9 @@ implementation {$R *.lfm} uses + Math, TAChartUtils, TACustomSource, TALegend, TASeries, - Utils, Math, MathUnit, MatrixUnit, GridProcs, ChartFrameUnit; + Utils, MathUnit, MatrixUnit, GridProcs, ChartFrameUnit; { TABCNestedForm } @@ -140,6 +141,9 @@ begin MeansPage.PageIndex := 1; FChartFrame.Chart.Margins.Bottom := 0; + FChartFrame.Chart.BottomAxis.AxisPen.Visible := true; + FChartFrame.Chart.BottomAxis.ZPosition := 1; + FChartFrame.Chart.BottomAxis.Grid.Visible := false; AddComboboxToToolbar(FChartFrame.ChartToolbar, 'Plots:', FChartCombobox); FChartCombobox.OnSelect := @SelectPlot; @@ -391,78 +395,7 @@ begin Result := true; end; -(* - SetLength(ColNoSelected, 4); - ACol := -1; - BCol := -1; - CCol := -1; - YCol := -1; - MinA := MaxInt; - MaxA := -MaxInt; - MinB := MaxInt; - MaxB := -MaxInt; - MinC := MaxInt; - MaxC := -MaxInt; - for i := 1 to NoVariables do - begin - strvalue := Trim(OS3MainFrm.DataGrid.Cells[i,0]); - if FactorAEdit.Text = strvalue then - begin - ACol := i; - ColNoSelected[0] := i; - end; - if FactorBEdit.Text = strvalue then - begin - BCol := i; - ColNoSelected[1] := i; - end; - if FactorCEdit.Text = strvalue then - begin - CCol := i; - ColNoSelected[2] := i; - end; - if DepEdit.Text = strvalue then - begin - YCol := i; - ColNoSelected[3] := i; - end; - end; - if (ACol = -1) or (BCol = -1) or (CCol = -1) or (YCol = -1) then - begin - MessageDlg('Select a variable for each entry box.', mtError, [mbOK], 0); - exit; - end; - - // get number of levels for Factors - for i := 1 to NoCases do - begin - cellstring := Trim(OS3MainFrm.DataGrid.Cells[ACol,i]); - group := round(StrToFloat(cellstring)); - if (group > MaxA) then MaxA := group; - if (group < MinA) then MinA := group; - - cellstring := Trim(OS3MainFrm.DataGrid.Cells[BCol,i]); - group := round(StrToFLoat(cellstring)); - if (group > MaxB) then MaxB := group; - if (group < MinB) then MinB := group; - - cellstring := Trim(OS3MainFrm.DataGrid.Cells[CCol,i]); - group := round(StrToFLoat(cellstring)); - if (group > MaxC) then MaxC := group; - if (group < MinC) then MinC := group; - end; - - NoALevels := MaxA - MinA + 1; - NoBLevels := MaxB - MinB + 1; - NoCLevels := MaxC - MinC + 1; - - Result := true; -end; -*) - -{ Allocates memory for all arrays needed. Setting the dynamic arrays to nil - before allocation automatically resets the array contents. } procedure TABCNestedForm.GetMemory; begin SS := CubeCreate(NoBLevels, NoALevels, NoCLevels); @@ -503,12 +436,10 @@ VAR Aindex, Bindex, Cindex, i, j, k: integer; YValue, YValueSqr: double; begin - // clear memory + // Accumulate sums and sums of squared values SSTot := 0.0; SumSqrTot := 0.0; TotN := 0; - - // Accumulate sums and sums of squared values for i := 0 to High(DepValues) do begin AIndex := round(AValues[i]) - MinA; @@ -637,51 +568,69 @@ begin lReport.Add(''); lReport.Add('CELL MEANS'); - lReport.Add('A LEVEL BLEVEL CLEVEL MEAN STD.DEV.'); + lReport.Add('-----------------------------------------------------'); + lReport.Add('A LEVEL B LEVEL C LEVEL MEAN STD.DEV. '); + lReport.Add('------- ------- ------- ---------- ----------'); for i := 0 to NoALevels-1 do for j := 0 to NoBLevels-1 do for k := 0 to NoCLevels-1 do if CellCount[j,i,k] > 0 then - lReport.Add('%5d %5d %5d %10.4f %10.4f', [i+MinA, j+MinB, k+MinC, CellMeans[j,i,k], CellSDs[j,i,k]]); + lReport.Add('%5d %5d %5d %10.3f %10.3f', [i+MinA, j+MinB, k+MinC, CellMeans[j,i,k], CellSDs[j,i,k]]); + lReport.Add('-----------------------------------------------------'); lReport.Add(''); lReport.Add('A MARGIN MEANS'); - lReport.Add('A LEVEL MEAN STD.DEV.'); + lReport.Add('---------------------------------'); + lReport.Add('A LEVEL MEAN STD.DEV. '); + lReport.Add('------- ---------- ----------'); for i := 0 to NoALevels-1 do - lReport.Add('%5d %10.3f %10.3f', [i+MinA, AMeans[i], ASDs[i]]); + lReport.Add('%5d %10.3f %10.3f', [i+MinA, AMeans[i], ASDs[i]]); + lReport.Add('---------------------------------'); lReport.Add(''); lReport.Add('B MARGIN MEANS'); - lReport.Add('B LEVEL MEAN STD.DEV.'); + lReport.Add('---------------------------------'); + lReport.Add('B LEVEL MEAN STD.DEV. '); + lReport.Add('------- ---------- ----------'); for i := 0 to NoBLevels-1 do if BCount[i] > 0 then - lReport.Add('%5d %10.3f %10.3f', [i+MinB, BMeans[i], BSDs[i]]); + lReport.Add('%5d %10.3f %10.3f', [i+MinB, BMeans[i], BSDs[i]]); + lReport.Add('---------------------------------'); lReport.Add(''); lReport.Add('C MARGIN MEANS'); - lReport.Add('C LEVEL MEAN STD.DEV.'); + lReport.Add('---------------------------------'); + lReport.Add('C LEVEL MEAN STD.DEV. '); + lReport.Add('------- ---------- ----------'); for i := 0 to NoCLevels-1 do if CCount[i] > 0 then - lReport.Add('%5d %10.3f %10.3f', [i+MinC, CMeans[i], CSDs[i]]); - + lReport.Add('%5d %10.3f %10.3f', [i+MinC, CMeans[i], CSDs[i]]); + lReport.Add('---------------------------------'); lReport.Add(''); + lReport.Add('AB MARGIN MEANS'); - lReport.Add('A LEVEL B LEVEL MEAN STD.DEV.'); + lReport.Add('-------------------------------------------'); + lReport.Add('A LEVEL B LEVEL MEAN STD.DEV. '); + lReport.Add('------- ------- ---------- ----------'); for i := 0 to NoALevels-1 do for j := 0 to NoBLevels-1 do if ABCount[i,j] > 0 then - lReport.Add('%5d %5D %10.3f %10.3f', [i+MinA, j+MinB, ABMeans[i,j], ABSDs[i,j]]); + lReport.Add('%5d %5d %10.3f %10.3f', [i+MinA, j+MinB, ABMeans[i,j], ABSDs[i,j]]); + lReport.Add('-------------------------------------------'); lReport.Add(''); lReport.Add('AC MARGIN MEANS'); - lReport.Add('A LEVEL C LEVEL MEAN STD.DEV.'); + lReport.Add('-------------------------------------------'); + lReport.Add('A LEVEL C LEVEL MEAN STD.DEV. '); + lReport.Add('------- ------- ---------- ----------'); for i := 0 to NoALevels-1 do for j := 0 to NoCLevels-1 do if ACCount[i,j] > 0 then - lReport.Add('%5d %5D %10.3f %10.3f',[i+MinA, j+MinC, ACMeans[i,j], ACSDs[i,j]]); + lReport.Add('%5d %5d %10.3f %10.3f',[i+MinA, j+MinC, ACMeans[i,j], ACSDs[i,j]]); + lReport.Add('-------------------------------------------'); lReport.Add(''); - lReport.Add('GRAND MEAN = %10.3f', [TotMean]); + lReport.Add('GRAND MEAN: %10.3f', [TotMean]); lReport.Add(''); FMeansReportFrame.DisplayReport(lReport); @@ -805,7 +754,7 @@ begin lReport.Add('Factor C: %s', [FactorCEdit.Text]); lReport.Add(''); lReport.Add('ANOVA TABLE'); - lReport.Add('------------------------------------------------------------'); + lReport.Add('-------------------------------------------------------------'); lReport.Add('SOURCE D.F. SS MS F PROB. '); lReport.Add('--------- ---- ---------- ---------- --------- ---------'); @@ -831,7 +780,7 @@ begin lReport.Add('w.cells %4d %10.3f %10.3f', [dfwcell, SSW, MSW]); lReport.Add('Total %4d %10.3f', [dftotal, SSTot]); - lReport.Add('------------------------------------------------------------'); + lReport.Add('-------------------------------------------------------------'); FReportFrame.DisplayReport(lReport); diff --git a/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas b/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas index 9343c74cb..420a033f7 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas +++ b/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas @@ -196,30 +196,6 @@ begin FStyles := TChartStyles.Create(FChartFrame); AddComboboxToToolbar(FChartFrame.ChartToolbar, 'Plots:', FChartCombobox); - { - 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; - } FChartFrame.Chart.Margins.Bottom := 0; PageControl.ActivePageIndex := 0; diff --git a/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.lfm b/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.lfm index 2b7854ed3..eda48e643 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.lfm +++ b/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.lfm @@ -1,370 +1,330 @@ -object BNestedAForm: TBNestedAForm +inherited BNestedAForm: TBNestedAForm Left = 768 - Height = 498 + Height = 432 Top = 238 - Width = 488 - AutoSize = True + Width = 544 Caption = 'Factor B Nested in Factor A Analysis of Variance' - ClientHeight = 498 - ClientWidth = 488 - OnActivate = FormActivate - OnCreate = FormCreate - OnShow = ResetBtnClick - Position = poMainFormCenter - LCLVersion = '2.0.10.0' - object Label1: TLabel - AnchorSideLeft.Control = Owner - AnchorSideTop.Control = Memo1 - AnchorSideTop.Side = asrBottom - Left = 8 - Height = 15 - Top = 114 - Width = 100 - BorderSpacing.Left = 8 - BorderSpacing.Top = 16 - Caption = 'Available Variables:' - ParentColor = False + ClientHeight = 432 + ClientWidth = 544 + inherited ParamsPanel: TPanel + Height = 416 + Width = 315 + ClientHeight = 416 + ClientWidth = 315 + inherited CloseBtn: TButton + Left = 260 + Top = 391 + TabOrder = 15 + end + inherited ComputeBtn: TButton + Left = 176 + Top = 391 + TabOrder = 14 + end + inherited ResetBtn: TButton + Left = 114 + Top = 391 + TabOrder = 13 + end + inherited HelpBtn: TButton + Tag = 171 + Left = 55 + Top = 391 + TabOrder = 12 + end + inherited ButtonBevel: TBevel + Top = 375 + Width = 315 + end + object AInBtn: TBitBtn[5] + AnchorSideLeft.Control = ParamsPanel + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = DepOutBtn + AnchorSideTop.Side = asrBottom + Left = 144 + Height = 26 + Top = 96 + Width = 26 + BorderSpacing.Top = 24 + Images = MainDataModule.ImageList + ImageIndex = 1 + OnClick = AInBtnClick + Spacing = 0 + TabOrder = 4 + end + object AOutBtn: TBitBtn[6] + AnchorSideLeft.Control = ParamsPanel + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = AInBtn + AnchorSideTop.Side = asrBottom + Left = 144 + Height = 26 + Top = 126 + Width = 26 + BorderSpacing.Top = 4 + Images = MainDataModule.ImageList + ImageIndex = 0 + OnClick = AOutBtnClick + Spacing = 0 + TabOrder = 5 + end + object BInBtn: TBitBtn[7] + AnchorSideLeft.Control = ParamsPanel + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = AOutBtn + AnchorSideTop.Side = asrBottom + Left = 144 + Height = 26 + Top = 176 + Width = 26 + BorderSpacing.Top = 24 + Images = MainDataModule.ImageList + ImageIndex = 1 + OnClick = BInBtnClick + Spacing = 0 + TabOrder = 7 + end + object BOutBtn: TBitBtn[8] + AnchorSideLeft.Control = ParamsPanel + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = BInBtn + AnchorSideTop.Side = asrBottom + Left = 144 + Height = 26 + Top = 206 + Width = 26 + BorderSpacing.Top = 4 + Images = MainDataModule.ImageList + ImageIndex = 0 + OnClick = BOutBtnClick + Spacing = 0 + TabOrder = 8 + end + object DepInBtn: TBitBtn[9] + AnchorSideLeft.Control = ParamsPanel + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = VarList + Left = 144 + Height = 26 + Top = 16 + Width = 26 + Images = MainDataModule.ImageList + ImageIndex = 1 + OnClick = DepInBtnClick + Spacing = 0 + TabOrder = 1 + end + object DepOutBtn: TBitBtn[10] + AnchorSideLeft.Control = ParamsPanel + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = DepInBtn + AnchorSideTop.Side = asrBottom + Left = 144 + Height = 26 + Top = 46 + Width = 26 + BorderSpacing.Top = 4 + Images = MainDataModule.ImageList + ImageIndex = 0 + OnClick = DepOutBtnClick + Spacing = 0 + TabOrder = 2 + end + object Label1: TLabel[11] + AnchorSideLeft.Control = ParamsPanel + AnchorSideTop.Control = ParamsPanel + Left = 0 + Height = 15 + Top = 0 + Width = 100 + Caption = 'Available Variables:' + ParentColor = False + end + object VarList: TListBox[12] + AnchorSideLeft.Control = ParamsPanel + AnchorSideTop.Control = Label1 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = AInBtn + AnchorSideBottom.Control = PlotOptionsGroup + Left = 0 + Height = 279 + Top = 16 + Width = 138 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Top = 1 + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 8 + ItemHeight = 0 + MultiSelect = True + OnDblClick = VarListDblClick + OnSelectionChange = VarListSelectionChange + TabOrder = 0 + end + object Label2: TLabel[13] + AnchorSideLeft.Control = AInBtn + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = ACodesEdit + Left = 170 + Height = 15 + Top = 100 + Width = 88 + Anchors = [akLeft, akBottom] + BorderSpacing.Bottom = 2 + Caption = 'Factor A Variable' + ParentColor = False + end + object Label3: TLabel[14] + AnchorSideLeft.Control = BCodesEdit + AnchorSideBottom.Control = BCodesEdit + Left = 176 + Height = 15 + Top = 180 + Width = 115 + Anchors = [akLeft, akBottom] + BorderSpacing.Bottom = 2 + Caption = 'Factor B (Nested in A)' + ParentColor = False + end + object Label4: TLabel[15] + AnchorSideLeft.Control = DepEdit + AnchorSideBottom.Control = DepEdit + Left = 176 + Height = 15 + Top = 20 + Width = 102 + Anchors = [akLeft, akBottom] + BorderSpacing.Bottom = 2 + Caption = 'Dependent Variable' + ParentColor = False + end + object ACodesEdit: TEdit[16] + AnchorSideLeft.Control = AInBtn + AnchorSideLeft.Side = asrBottom + AnchorSideRight.Control = ParamsPanel + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = AOutBtn + AnchorSideBottom.Side = asrBottom + Left = 176 + Height = 23 + Top = 117 + Width = 139 + Anchors = [akLeft, akRight, akBottom] + BorderSpacing.Left = 6 + BorderSpacing.Bottom = 12 + ReadOnly = True + TabOrder = 6 + Text = 'ACodesEdit' + end + object BCodesEdit: TEdit[17] + AnchorSideLeft.Control = BInBtn + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = ParamsPanel + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = BOutBtn + AnchorSideBottom.Side = asrBottom + Left = 176 + Height = 23 + Top = 197 + Width = 139 + Anchors = [akLeft, akRight, akBottom] + BorderSpacing.Left = 6 + BorderSpacing.Bottom = 12 + ReadOnly = True + TabOrder = 9 + Text = 'BCodesEdit' + end + object DepEdit: TEdit[18] + AnchorSideLeft.Control = DepInBtn + AnchorSideLeft.Side = asrBottom + AnchorSideRight.Control = ParamsPanel + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = DepOutBtn + AnchorSideBottom.Side = asrBottom + Left = 176 + Height = 23 + Top = 37 + Width = 139 + Anchors = [akLeft, akRight, akBottom] + BorderSpacing.Left = 6 + BorderSpacing.Bottom = 12 + ReadOnly = True + TabOrder = 3 + Text = 'DepEdit' + end + object RandomBChk: TCheckBox[19] + AnchorSideLeft.Control = BCodesEdit + AnchorSideTop.Control = BCodesEdit + AnchorSideTop.Side = asrBottom + Left = 176 + Height = 19 + Top = 232 + Width = 136 + Caption = 'B is random, not fixed' + TabOrder = 10 + end + object PlotOptionsGroup: TGroupBox[20] + AnchorSideLeft.Control = ParamsPanel + AnchorSideBottom.Control = ButtonBevel + Left = 0 + Height = 72 + Top = 303 + Width = 106 + Anchors = [akLeft, akBottom] + AutoSize = True + Caption = 'Plot options' + ClientHeight = 52 + ClientWidth = 102 + TabOrder = 11 + object ShowPlotsChk: TCheckBox + AnchorSideLeft.Control = PlotOptionsGroup + AnchorSideTop.Control = PlotOptionsGroup + Left = 12 + Height = 19 + Top = 6 + Width = 78 + BorderSpacing.Left = 12 + BorderSpacing.Top = 6 + BorderSpacing.Right = 12 + Caption = 'Show plots' + Checked = True + OnChange = ShowPlotsChkChange + State = cbChecked + TabOrder = 0 + end + object Plot3DChk: TCheckBox + AnchorSideLeft.Control = ShowPlotsChk + AnchorSideTop.Control = ShowPlotsChk + AnchorSideTop.Side = asrBottom + Left = 32 + Height = 19 + Top = 25 + Width = 34 + BorderSpacing.Left = 20 + BorderSpacing.Bottom = 8 + Caption = '3D' + OnChange = Plot3DChkChange + TabOrder = 1 + end + end end - object Label2: TLabel - AnchorSideLeft.Control = AInBtn - AnchorSideLeft.Side = asrBottom - AnchorSideBottom.Control = ACodes - Left = 266 - Height = 15 - Top = 138 - Width = 88 - Anchors = [akLeft, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Bottom = 2 - Caption = 'Factor A Variable' - ParentColor = False + inherited ParamsSplitter: TSplitter + Left = 327 + Height = 432 end - object Label3: TLabel - AnchorSideLeft.Control = BInBtn - AnchorSideLeft.Side = asrBottom - AnchorSideBottom.Control = BCodes - Left = 266 - Height = 15 - Top = 222 - Width = 115 - Anchors = [akLeft, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Bottom = 2 - Caption = 'Factor B (Nested in A)' - ParentColor = False - end - object Label4: TLabel - AnchorSideLeft.Control = DepInBtn - AnchorSideLeft.Side = asrBottom - AnchorSideBottom.Control = DepEdit - Left = 266 - Height = 15 - Top = 317 - Width = 102 - Anchors = [akLeft, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Bottom = 2 - Caption = 'Dependent Variable' - ParentColor = False - end - object VarList: TListBox - AnchorSideLeft.Control = Owner - AnchorSideTop.Control = Label1 - AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = AInBtn - AnchorSideBottom.Control = OptionsBox - Left = 9 - Height = 239 - Top = 130 - Width = 213 - Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Left = 9 - BorderSpacing.Top = 1 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 - ItemHeight = 0 - MultiSelect = True - OnSelectionChange = VarListSelectionChange - TabOrder = 0 - end - object AInBtn: TBitBtn - AnchorSideLeft.Control = Owner - AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = VarList - Left = 230 - Height = 28 - Top = 130 - Width = 28 - Images = MainDataModule.ImageList - ImageIndex = 1 - OnClick = AInBtnClick - Spacing = 0 - TabOrder = 1 - end - object AOutBtn: TBitBtn - AnchorSideLeft.Control = Owner - AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = AInBtn - AnchorSideTop.Side = asrBottom - Left = 230 - Height = 28 - Top = 162 - Width = 28 - BorderSpacing.Top = 4 - Images = MainDataModule.ImageList - ImageIndex = 0 - OnClick = AOutBtnClick - Spacing = 0 - TabOrder = 2 - end - object BInBtn: TBitBtn - AnchorSideLeft.Control = Owner - AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = AOutBtn - AnchorSideTop.Side = asrBottom - Left = 230 - Height = 28 - Top = 214 - Width = 28 - BorderSpacing.Top = 24 - Images = MainDataModule.ImageList - ImageIndex = 1 - OnClick = BInBtnClick - Spacing = 0 - TabOrder = 4 - end - object BOutBtn: TBitBtn - AnchorSideLeft.Control = Owner - AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = BInBtn - AnchorSideTop.Side = asrBottom - Left = 230 - Height = 28 - Top = 246 - Width = 28 - BorderSpacing.Top = 4 - Images = MainDataModule.ImageList - ImageIndex = 0 - OnClick = BOutBtnClick - Spacing = 0 - TabOrder = 5 - end - object DepInBtn: TBitBtn - AnchorSideLeft.Control = Owner - AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = RandomBChk - AnchorSideTop.Side = asrBottom - Left = 230 - Height = 28 - Top = 309 - Width = 28 - BorderSpacing.Top = 8 - Images = MainDataModule.ImageList - ImageIndex = 1 - OnClick = DepInBtnClick - Spacing = 0 - TabOrder = 8 - end - object DepOutBtn: TBitBtn - AnchorSideLeft.Control = Owner - AnchorSideLeft.Side = asrCenter - AnchorSideTop.Control = DepInBtn - AnchorSideTop.Side = asrBottom - Left = 230 - Height = 28 - Top = 341 - Width = 28 - BorderSpacing.Top = 4 - Images = MainDataModule.ImageList - ImageIndex = 0 - OnClick = DepOutBtnClick - Spacing = 0 - TabOrder = 9 - end - object ACodes: TEdit - AnchorSideLeft.Control = AInBtn - AnchorSideLeft.Side = asrBottom - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = AOutBtn - AnchorSideBottom.Side = asrBottom - Left = 266 - Height = 23 - Top = 155 - Width = 214 - Anchors = [akLeft, akRight, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 12 - ReadOnly = True - TabOrder = 3 - Text = 'ACodes' - end - object BCodes: TEdit - AnchorSideLeft.Control = BInBtn - AnchorSideLeft.Side = asrBottom - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = BOutBtn - AnchorSideBottom.Side = asrBottom - Left = 266 - Height = 23 - Top = 239 - Width = 214 - Anchors = [akLeft, akRight, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 12 - ReadOnly = True - TabOrder = 6 - Text = 'BCodes' - end - object ResetBtn: TButton - AnchorSideRight.Control = ComputeBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 275 - Height = 25 - Top = 465 - Width = 54 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 12 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 - Caption = 'Reset' - OnClick = ResetBtnClick - TabOrder = 12 - end - object ComputeBtn: TButton - AnchorSideRight.Control = CloseBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 337 - Height = 25 - Top = 465 - Width = 76 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 8 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 - Caption = 'Compute' - OnClick = ComputeBtnClick - TabOrder = 13 - end - object CloseBtn: TButton - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 421 - Height = 25 - Top = 465 - Width = 55 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 8 - BorderSpacing.Top = 8 - BorderSpacing.Right = 12 - BorderSpacing.Bottom = 8 - Caption = 'Close' - ModalResult = 11 - TabOrder = 14 - end - object DepEdit: TEdit - AnchorSideLeft.Control = DepInBtn - AnchorSideLeft.Side = asrBottom - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = DepOutBtn - AnchorSideBottom.Side = asrBottom - Left = 266 - Height = 23 - Top = 334 - Width = 214 - Anchors = [akLeft, akRight, akBottom] - BorderSpacing.Left = 8 - BorderSpacing.Right = 8 - BorderSpacing.Bottom = 12 - ReadOnly = True - TabOrder = 10 - Text = 'DepEdit' - end - object OptionsBox: TRadioGroup - AnchorSideLeft.Control = Owner - AnchorSideBottom.Control = ButtonBevel - Left = 8 - Height = 72 - Top = 377 - Width = 466 - Anchors = [akLeft, akBottom] - AutoFill = True - AutoSize = True - BorderSpacing.Left = 8 - Caption = 'OptionsBox' - ChildSizing.LeftRightSpacing = 12 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 16 - ChildSizing.VerticalSpacing = 2 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.EnlargeVertical = crsHomogenousChildResize - ChildSizing.ShrinkHorizontal = crsScaleChilds - ChildSizing.ShrinkVertical = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 2 - ClientHeight = 52 - ClientWidth = 462 - Columns = 2 - Items.Strings = ( - 'Plot means using 2D Horizontal Bars' - 'Plot means using 3D Horizontal Bars' - 'Plot means using 2D Vertical Bars' - 'Plot means using 3D Vertical Bars' - ) - TabOrder = 11 - end - object RandomBChk: TCheckBox - AnchorSideLeft.Control = BCodes - AnchorSideTop.Control = BOutBtn - AnchorSideTop.Side = asrBottom - Left = 266 - Height = 19 - Top = 282 - Width = 136 - BorderSpacing.Top = 8 - Caption = 'B is random, not fixed' - TabOrder = 7 - end - object Memo1: TLabel - AnchorSideLeft.Control = Owner - AnchorSideTop.Control = Owner - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - Left = 8 - Height = 90 - Top = 8 - Width = 472 - Anchors = [akTop, akLeft, akRight] - BorderSpacing.Left = 8 - BorderSpacing.Top = 8 - BorderSpacing.Right = 8 - Caption = 'Directions: This analysis assumes that levels of Factor B are Nested within levels of Factor A. Unless otherwise specified, it is assumed that Factors A and B are fixed level factors. If Factor B is a random variable, check the provided box to indicate this.'#13#10#13#10'The number of cases for each B group should be equal and the number of B treatements in each A level should be equal.' - ParentColor = False - WordWrap = True - end - object ButtonBevel: TBevel - AnchorSideLeft.Control = Owner - AnchorSideRight.Control = Owner - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = CloseBtn - Left = 0 - Height = 8 - Top = 449 - Width = 488 - Anchors = [akLeft, akRight, akBottom] - Shape = bsBottomLine + inherited PageControl: TPageControl + Left = 336 + Height = 416 + Width = 200 + TabIndex = 2 + inherited ReportPage: TTabSheet + Caption = 'ANOVA Results' + end + object MeansPage: TTabSheet[1] + Caption = 'Means' + end + inherited ChartPage: TTabSheet[2] + Caption = 'Plots' + end end end diff --git a/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.pas b/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.pas index b7f212ac3..15b7f13fb 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.pas +++ b/applications/lazstats/source/forms/analysis/comparisons/bnestaunit.pas @@ -1,75 +1,90 @@ +{ Test file: ABNested.laz (imported from OpenStat sample data zip file) + Dependent: Dep + Factor A : A + Factor B : B +} + unit BNestAUnit; -{$mode objfpc}{$H+} +{$MODE objfpc}{$H+} interface uses - Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, - StdCtrls, Buttons, ExtCtrls, - MainUnit, OutputUnit, GraphLib, Globals; + Classes, SysUtils, Forms, Controls, Graphics, LCLVersion, + StdCtrls, Buttons, ExtCtrls, ComCtrls, + TACustomSeries, + MainUnit, Globals, ReportFrameUnit, BasicStatsReportAndChartFormUnit; type { TBNestedAForm } - TBNestedAForm = class(TForm) - ACodes: TEdit; + TBNestedAForm = class(TBasicStatsReportAndChartForm) + ACodesEdit: TEdit; AInBtn: TBitBtn; AOutBtn: TBitBtn; - BCodes: TEdit; - ButtonBevel: TBevel; + BCodesEdit: TEdit; BInBtn: TBitBtn; BOutBtn: TBitBtn; - Memo1: TLabel; + Plot3DChk: TCheckBox; + PlotOptionsGroup: TGroupBox; RandomBChk: TCheckBox; DepInBtn: TBitBtn; - ComputeBtn: TButton; DepOutBtn: TBitBtn; DepEdit: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; - OptionsBox: TRadioGroup; - ResetBtn: TButton; - CloseBtn: TButton; + MeansPage: TTabSheet; + ShowPlotsChk: TCheckBox; VarList: TListBox; procedure AInBtnClick(Sender: TObject); procedure AOutBtnClick(Sender: TObject); procedure BInBtnClick(Sender: TObject); procedure BOutBtnClick(Sender: TObject); - procedure ComputeBtnClick(Sender: TObject); procedure DepInBtnClick(Sender: TObject); procedure DepOutBtnClick(Sender: TObject); - procedure FormActivate(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure ResetBtnClick(Sender: TObject); + procedure Plot3DChkChange(Sender: TObject); + procedure ShowPlotsChkChange(Sender: TObject); + procedure VarListDblClick(Sender: TObject); procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean); + private - { private declarations } - FAutoSized: Boolean; SS, SumSqr, CellMeans, CellSDs : DblDyneMat; CellCount : IntDyneMat; ASS, BSS, ASumSqr, BSumSqr, AMeans, BMeans, ASDs : DblDyneVec; ACount, BCount : IntDyneVec; - MinA, MinB, MaxA, MaxB, NoALevels, NoBLevels, ACol, BCol, YCol : integer; - DepVar, FactorA, FactorB : string; + MinA, MinB, MaxA, MaxB, NoALevels, NoBLevels: integer; SSTot, SumSqrTot, TotMean, MSTot, SSA, MSA, SSB, MSB, SSW, MSW : double; TotN, dfA, dfBwA, dfwcell, dftotal : integer; - function GetVars: Boolean; + function GetVariables(out AValues, BValues, DepValues: DblDyneVec): Boolean; procedure GetMemory; - procedure GetSums; - procedure ShowMeans(AReport: TStrings); + procedure GetSums(const AValues, BValues, DepValues: DblDyneVec); + procedure ShowMeans; procedure GetResults; - procedure ShowResults(AReport: TStrings); + procedure ShowResults; procedure ReleaseMemory; procedure TwoWayPlot; - procedure UpdateBtnStates; + private + FMeansReportFrame: TReportFrame; + FChartCombobox: TCombobox; + FSeries: TChartSeries; + procedure PopulateChartCombobox; + procedure SelectPlot(Sender: TObject); + + protected + procedure AdjustConstraints; override; + procedure Compute; override; + procedure UpdateBtnStates; override; + function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override; + public - { public declarations } + constructor Create(AOwner: TComponent); override; + procedure Reset; override; end; var @@ -77,92 +92,119 @@ var implementation +{$R *.lfm} + uses Math, - Utils, MathUnit; + TAChartUtils, TACustomSource, TALegend, TASeries, + Utils, MathUnit, MatrixUnit, GridProcs, ChartFrameUnit; { TBNestedAForm } -procedure TBNestedAForm.ResetBtnClick(Sender: TObject); -var - i: integer; +constructor TBNestedAForm.Create(AOwner: TComponent); begin - VarList.Items.Clear; - ACodes.Text := ''; - BCodes.Text := ''; - DepEdit.Text := ''; - for i := 1 to NoVariables do - VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); + inherited; + + FMeansReportFrame := TReportFrame.Create(MeansPage); + FMeansReportFrame.Parent := MeansPage; + FMeansReportFrame.Align := alClient; + InitToolbar(FMeansReportFrame.ReportToolbar, tpTop); + MeansPage.PageIndex := 1; + + FChartFrame.Chart.Margins.Bottom := 0; + FChartFrame.Chart.BottomAxis.AxisPen.Visible := true; + FChartFrame.Chart.BottomAxis.ZPosition := 1; + FChartFrame.Chart.BottomAxis.Grid.Visible := false; + AddComboboxToToolbar(FChartFrame.ChartToolbar, 'Plots:', FChartCombobox); + FChartCombobox.OnSelect := @SelectPlot; + + PageControl.ActivePageIndex := 0; end; + +procedure TBNestedAForm.AdjustConstraints; +begin + inherited; + + ParamsPanel.Constraints.MinWidth := Max( + 4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left, + Max(Label3.Width, RandomBChk.Width) * 2 + AInBtn.Width + 2*VarList.BorderSpacing.Right + ); + ParamsPanel.Constraints.MinHeight := RandomBChk.Top + RandomBChk.Height + + VarList.BorderSpacing.Bottom + PlotOptionsGroup.Height + + ButtonBevel.Height + CloseBtn.Height + CloseBtn.BorderSpacing.Top; +end; + + procedure TBNestedAForm.AInBtnClick(Sender: TObject); var index: integer; begin index := VarList.ItemIndex; - if (index > -1) and (ACodes.Text = '') then + if (index > -1) and (ACodesEdit.Text = '') then begin - ACodes.Text := VarList.Items[index]; + ACodesEdit.Text := VarList.Items[index]; VarList.Items.Delete(index); end; UpdateBtnStates; end; + procedure TBNestedAForm.AOutBtnClick(Sender: TObject); begin - if ACodes.Text <> '' then + if ACodesEdit.Text <> '' then begin - VarList.Items.Add(ACodes.Text); - ACodes.Text := ''; + VarList.Items.Add(ACodesEdit.Text); + ACodesEdit.Text := ''; end; UpdateBtnStates; end; + procedure TBNestedAForm.BInBtnClick(Sender: TObject); var index: integer; begin index := VarList.ItemIndex; - if (index > -1) and (BCodes.Text = '') then + if (index > -1) and (BCodesEdit.Text = '') then begin - BCodes.Text := VarList.Items[index]; + BCodesEdit.Text := VarList.Items[index]; VarList.Items.Delete(index); end; UpdateBtnStates; end; + procedure TBNestedAForm.BOutBtnClick(Sender: TObject); begin - if BCodes.Text <> '' then + if BCodesEdit.Text <> '' then begin - VarList.Items.Add(BCodes.Text); - BCodes.Text := ''; + VarList.Items.Add(BCodesEdit.Text); + BCodesEdit.Text := ''; end; UpdateBtnStates; end; -procedure TBNestedAForm.ComputeBtnClick(Sender: TObject); + +procedure TBNestedAForm.Compute; var - lReport: TStrings; + dataA: DblDyneVec = nil; + dataB: DblDyneVec = nil; + dataDep: DblDyneVec = nil; begin - lReport := TStringList.Create; - try - if GetVars then - begin - GetMemory; - GetSums; - ShowMeans(lReport); - GetResults; - ShowResults(lReport); - DisplayReport(lReport); - TwoWayPlot; - ReleaseMemory; - end; - finally - lReport.Free; + if GetVariables(dataA, dataB, dataDep) then + begin + GetMemory; + GetSums(dataA, dataB, dataDep); + ShowMeans; + GetResults; + ShowResults; + TwoWayPlot; + ReleaseMemory; end; end; + procedure TBNestedAForm.DepInBtnClick(Sender: TObject); var index: integer; @@ -176,6 +218,7 @@ begin UpdateBtnStates; end; + procedure TBNestedAForm.DepOutBtnClick(Sender: TObject); begin if DepEdit.Text <> '' then @@ -186,41 +229,230 @@ begin UpdateBtnStates; end; -procedure TBNestedAForm.FormActivate(Sender: TObject); + +procedure TBNestedAForm.Plot3DChkChange(Sender: TObject); +begin + if FSeries is TBarSeries then + begin + if Plot3dChk.Checked then + TBarSeries(FSeries).Depth := 20 + else + TBarSeries(FSeries).Depth := 0; + end; +end; + + +procedure TBNestedAForm.ShowPlotsChkChange(Sender: TObject); +begin + ChartPage.TabVisible := ShowPlotsChk.Checked; + Plot3DChk.Enabled := ShowPlotsChk.Checked; +end; + + +procedure TBNestedAForm.GetMemory; +begin + SS := MatCreate(NoBLevels,NoALevels); + SumSqr := MatCreate(NoBLevels,NoALevels); + CellCount := IntMatCreate(NoBLevels,NoALevels); + CellMeans := MatCreate(NoBLevels,NoALevels); + CellSDs := MatCreate(NoBLevels,NoALevels); + + ASS := VecCreate(NoALevels); + BSS := VecCreate(NoBLevels); + ASumSqr := VecCreate(NoALevels); + BSumSqr := VecCreate(NoBLevels); + AMeans := VecCreate(NoALevels); + BMeans := VecCreate(NoBLevels); + ACount := IntVecCreate(NoALevels); + BCount := IntVecCreate(NoBLevels); + ASDs := VecCreate(NoALevels); +end; + + +procedure TBNestedAForm.GetResults; +VAR + temp, constant : double; + NoBLevelsInA, BLevCount, i, j, celln : integer; +begin + celln := 0; + for i := 0 to NoALevels-1 do + for j := 0 to NoBLevels-1 do + if CellCount[j,i] > celln then celln := CellCount[j,i]; + + // Assume all cells have same n size + // Get number of levels in A + BLevCount := 0; + for i := 0 to NoALevels-1 do + begin + NoBLevelsInA := 0; + for j := 0 to NoBLevels-1 do + if CellCount[j,i] > 0 then NoBLevelsInA := NoBLevelsInA + 1; + if NoBLevelsInA > BLevCount then BLevCount := NoBLevelsInA; + end; + + dfA := NoALevels - 1; + dfBwA := NoALevels * (BLevCount - 1); + dfwcell := NoALevels * BLevCount * (celln - 1); + dftotal := TotN - 1; + + constant := SumSqrTot / TotN; + SSTot := SSTot - constant; + MSTot := SSTot / dftotal; + + SSA := 0.0; + for i := 0 to NoALevels-1 do SSA := SSA + (ASumSqr[i] / ACount[i]); + temp := SSA; + SSA := SSA - constant; + MSA := SSA / dfA; + + SSB := 0.0; + for i := 0 to NoALevels - 1 do + for j := 0 to NoBLevels-1 do + if CellCount[j,i] > 0 then SSB := SSB + (SumSqr[j,i] / CellCount[j,i]); + SSB := SSB - temp; + + MSB := SSB / dfBwA; + SSW := SSTot - SSA - SSB; + MSW := SSW / dfwcell; +end; + + +procedure TBNestedAForm.GetSums(const AValues, BValues, DepValues: DblDyneVec); var - w: Integer; + AIndex, BIndex, i, j: integer; + YValue, YValueSqr: double; begin - if FAutoSized then + // Accumulate sums and sums of squared values + SSTot := 0; + SumSqrTot := 0; + TotN := 0; + for i := 0 to High(DepValues) do + begin + AIndex := round(AValues[i]) - MinA; + BIndex := round(BValues[i]) - MinB; + YValue := DepValues[i]; + YValueSqr := YValue * YValue; +{ + strvalue := Trim(OS3MainFrm.DataGrid.Cells[ACol,i]); + Aindex := round(StrToFloat(strvalue)); + strvalue := Trim(OS3MainFrm.DataGrid.Cells[BCol,i]); + Bindex := round(StrToFloat(strvalue)); + strvalue := Trim(OS3MainFrm.DataGrid.Cells[YCol,i]); + YValue := StrToFloat(strvalue); + Aindex := Aindex - MinA; + Bindex := Bindex - MinB; +} + SS[BIndex, AIndex] := SS[BIndex, AIndex] + YValueSqr; + SumSqr[BIndex, AIndex] := SumSqr[BIndex, AIndex] + YValue; + CellCount[BIndex, AIndex] := CellCount[BIndex, AIndex] + 1; + ACount[AIndex] := ACount[AIndex] + 1; + BCount[BIndex] := BCount[BIndex] + 1; + ASS[AIndex] := ASS[AIndex] + YValueSqr; + BSS[BIndex] := BSS[BIndex] + YValueSqr; + ASumSqr[AIndex] := ASumSqr[AIndex] + YValue; + BSumSqr[BIndex] := BSumSqr[BIndex] + YValue; + SSTot := SSTot + YValueSqr; + SumSqrTot := SumSqrTot + YValue; + TotN := TotN + 1; + end; + + // Get cell means and marginal means, SDs plus square of sums + for i := 0 to NoBlevels-1 do + begin + for j := 0 to NoALevels-1 do + begin + if CellCount[i,j] > 0 then + begin + CellMeans[i,j] := SumSqr[i,j] / CellCount[i,j]; + SumSqr[i,j] := SumSqr[i,j] * SumSqr[i,j]; + CellSDs[i,j] := SS[i,j] - (SumSqr[i,j] / CellCount[i,j]); + CellSDs[i,j] := CellSDs[i,j] / (CellCount[i,j] - 1); + CellSDs[i,j] := Sqrt(CellSDs[i,j]); + end; + end; + end; + + for i := 0 to NoBLevels-1 do + begin + BMeans[i] := BSumSqr[i] / BCount[i]; + BSumSqr[i] := BSumSqr[i] * BSumSqr[i]; + end; + + for i := 0 to NoALevels-1 do + begin + AMeans[i] := ASumSqr[i] / ACount[i]; + ASumSqr[i] := ASumSqr[i] * ASumSqr[i]; + ASDs[i] := ASS[i] - (ASumSqr[i] / ACount[i]); + ASDs[i] := ASDs[i] / (ACount[i] - 1); + ASDs[i] := Sqrt(ASDs[i]); + end; + + TotMean := SumSqrTot / TotN; + SumSqrTot := SumSqrTot * SumSqrTot; +end; + + +function TBNestedAForm.GetVariables( + out AValues, BValues, DepValues: DblDyneVec): Boolean; +var + ColNoSelected: IntDyneVec = nil; + mn, mx: Double; + msg: String; +begin + Result := false; + + SetLength(ColNoSelected, 3); + ColNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, ACodesEdit.Text); // A + ColNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, BCodesEdit.Text); // B + ColNoSelected[2] := GetVariableindex(OS3MainFrm.DataGrid, DepEdit.Text); // Dependent + + AValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[0], ColNoSelected); + if not CheckFactorCodes(ACodesEdit.Text, AValues, msg) then + begin + ErrorMsg(msg); exit; + end; - w := {%H-}MaxValue([ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]); - ResetBtn.Constraints.MinWidth := w; - ComputeBtn.Constraints.MinWidth := w; - CloseBtn.Constraints.MinWidth := w; + BValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[1], ColNoSelected); + if not CheckFactorCodes(BCodesEdit.Text, BValues, msg) then + begin + ErrorMsg(msg); + exit; + end; - VarList.Constraints.MinHeight := DepOutBtn.Top + DepOutBtn.Height - VarList.Top; - Constraints.MinHeight := Height; - Constraints.MinWidth := Width; + DepValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[2], ColNoSelected); - FAutoSized := true; + if (Length(DepValues) <> Length(AValues)) or + (Length(DepValues) <> Length(BValues)) then + begin + ErrorMsg('All variables must contain equal amounts of cases.'); + exit; + end; + + VecMaxMin(AValues, mx, mn); + MaxA := round(mx); + MinA := round(mn); + + VecMaxMin(BValues, mx, mn); + MaxB := round(mx); + MinB := round(mn); + + NoALevels := MaxA - MinA + 1; + NoBLevels := MaxB - MinB + 1; + + Result := true; end; -procedure TBNestedAForm.FormCreate(Sender: TObject); -begin - Assert(OS3MainFrm <> nil); - if GraphFrm = nil then - Application.CreateForm(TGraphFrm, GraphFrm); -end; -function TBNestedAForm.GetVars: Boolean; + (* var i, group : integer; strvalue, cellstring : string; begin Result := false; DepVar := DepEdit.Text; - FactorA := ACodes.Text; - FactorB := BCodes.Text; + FactorA := ACodesEdit.Text; + FactorB := BCodesEdit.Text; ACol := 0; BCol := 0; YCol := 0; @@ -237,10 +469,11 @@ begin end; if (ACol = 0) or (BCol = 0) or (YCol = 0) then begin - MessageDlg('Select a variable for each entry box.', mtError, [mbOK], 0); + ErrorMsg('Select a variable for each entry box.'); exit; end; - // get number of levels for Factors + + // Get number of levels for Factors for i := 1 to NoCases do begin cellstring := Trim(OS3MainFrm.DataGrid.Cells[ACol,i]); @@ -257,229 +490,116 @@ begin Result := true; end; +*) -procedure TBNestedAForm.GetMemory; -begin - SetLength(SS,NoBLevels,NoALevels); - SetLength(SumSqr,NoBLevels,NoALevels); - SetLength(CellCount,NoBLevels,NoALevels); - SetLength(CellMeans,NoBLevels,NoALevels); - SetLength(CellSDs,NoBLevels,NoALevels); - SetLength(ASS,NoALevels); - SetLength(BSS,NoBLevels); - SetLength(ASumSqr,NoALevels); - SetLength(BSumSqr,NoBLevels); - SetLength(AMeans,NoALevels); - SetLength(BMeans,NoBLevels); - SetLength(ACount,NoALevels); - SetLength(BCount,NoBLevels); - SetLength(ASDs,NoALevels); -end; -procedure TBNestedAForm.GetSums; -VAR - Aindex, Bindex, i, j : integer; - YValue : double; - strvalue : string; -begin - // initialize memory - for i := 0 to NoBLevels-1 do - begin - for j := 0 to NoALevels-1 do - begin - SS[i,j] := 0.0; - SumSqr[i,j] := 0.0; - CellCount[i,j] := 0; - end; - end; - for i := 0 to NoALevels-1 do - begin - ACount[i] := 0; - AMeans[i] := 0.0; - ASS[i] := 0.0; - ASumSqr[i] := 0.0; - end; - for j := 0 to NoBLevels-1 do - begin - BCount[i] := 0; - BMeans[i] := 0.0; - BSS[i] := 0.0; - BSumSqr[i] := 0.0; - end; - // Accumulate sums and sums of squared values - for i := 1 to NoCases do - begin - strvalue := Trim(OS3MainFrm.DataGrid.Cells[ACol,i]); - Aindex := round(StrToFloat(strvalue)); - strvalue := Trim(OS3MainFrm.DataGrid.Cells[BCol,i]); - Bindex := round(StrToFloat(strvalue)); - strvalue := Trim(OS3MainFrm.DataGrid.Cells[YCol,i]); - YValue := StrToFloat(strvalue); - Aindex := Aindex - MinA; - Bindex := Bindex - MinB; - SS[Bindex,Aindex] := SS[Bindex,Aindex] + YValue * YValue; - SumSqr[Bindex,Aindex] := SumSqr[Bindex,Aindex] + YValue; - CellCount[Bindex,Aindex] := CellCount[Bindex,Aindex] + 1; - ACount[Aindex] := ACount[Aindex] + 1; - BCount[Bindex] := BCount[Bindex] + 1; - ASS[Aindex] := ASS[Aindex] + YValue * YValue; - BSS[Bindex] := BSS[Bindex] + YValue * YValue; - ASumSqr[Aindex] := ASumSqr[Aindex] + YValue; - BSumSqr[Bindex] := BSumSqr[Bindex] + YValue; - SSTot := SSTot + YValue * YValue; - SumSqrTot := SumSqrTot + YValue; - TotN := TotN + 1; - end; - //get cell means and marginal means, SDs plus square of sums - for i := 0 to NoBlevels-1 do - begin - for j := 0 to NoALevels-1 do - begin - if CellCount[i,j] > 0 then - begin - CellMeans[i,j] := SumSqr[i,j] / CellCount[i,j]; - SumSqr[i,j] := SumSqr[i,j] * SumSqr[i,j]; - CellSDs[i,j] := SS[i,j] - (SumSqr[i,j] / CellCount[i,j]); - CellSDs[i,j] := CellSDs[i,j] / (CellCount[i,j] - 1); - CellSDs[i,j] := Sqrt(CellSDs[i,j]); - end; - end; - end; - for i := 0 to NoBLevels-1 do - begin - BMeans[i] := BSumSqr[i] / BCount[i]; - BSumSqr[i] := BSumSqr[i] * BSumSqr[i]; - end; - for i := 0 to NoALevels-1 do - begin - AMeans[i] := ASumSqr[i] / ACount[i]; - ASumSqr[i] := ASumSqr[i] * ASumSqr[i]; - ASDs[i] := ASS[i] - (ASumSqr[i] / ACount[i]); - ASDs[i] := ASDs[i] / (ACount[i] - 1); - ASDs[i] := Sqrt(ASDs[i]); - end; - TotMean := SumSqrTot / TotN; - SumSqrTot := SumSqrTot * SumSqrTot; -end; - -procedure TBNestedAForm.ShowMeans(AReport: TStrings); +procedure TBNestedAForm.ShowMeans; var + lReport: TStrings; i, j: integer; begin - AReport.Add('NESTED ANOVA by Bill Miller'); - AReport.Add(''); - AReport.Add('File Analyzed: %s', [OS3MainFrm.FileNameEdit.Text]); - AReport.Add(''); - AReport.Add('CELL MEANS'); - AReport.Add('A LEVEL BLEVEL MEAN STD.DEV.'); - for i := 0 to NoALevels-1 do - for j := 0 to NoBLevels-1 do - if CellCount[j,i] > 0 then - AReport.Add('%5d %5d %10.3f %10.3f', [i+MinA, j+MinB, CellMeans[j,i], CellSDs[j,i]]); - AReport.Add(''); - AReport.Add('A MARGIN MEANS'); - AReport.Add('A LEVEL MEAN STD.DEV.'); - for i := 0 to NoALevels-1 do - AReport.Add('%5d %10.3f %10.3f', [i+MinA, AMeans[i], ASDs[i]]); - AReport.Add(''); - AReport.Add('GRAND MEAN: %0.3f', [TotMean]); - AReport.Add(''); - AReport.Add(''); + lReport := TStringList.Create; + try + lReport.Add('NESTED ANOVA by Bill Miller'); + lReport.Add(''); + lReport.Add('File analyzed: %s', [OS3MainFrm.FileNameEdit.Text]); + lReport.Add('Factor A: %s', [ACodesEdit.Text]); + lReport.Add('Factor B: %s', [BCodesEdit.Text]); + lReport.Add(''); + lReport.Add('CELL MEANS'); + lReport.Add('-------------------------------------------'); + lReport.Add('A LEVEL B LEVEL MEAN STD.DEV. '); + lReport.Add('------- ------- ---------- ----------'); + for i := 0 to NoALevels-1 do + for j := 0 to NoBLevels-1 do + if CellCount[j,i] > 0 then + lReport.Add('%5d %5d %10.3f %10.3f', [i+MinA, j+MinB, CellMeans[j,i], CellSDs[j,i]]); + lReport.Add('-------------------------------------------'); + lReport.Add(''); + lReport.Add('A MARGIN MEANS'); + lReport.Add('---------------------------------'); + lReport.Add('A LEVEL MEAN STD.DEV. '); + lReport.Add('------- ---------- ----------'); + for i := 0 to NoALevels-1 do + lReport.Add('%5d %10.3f %10.3f', [i+MinA, AMeans[i], ASDs[i]]); + lReport.Add('---------------------------------'); + lReport.Add(''); + lReport.Add('GRAND MEAN: %0.3f', [TotMean]); + lReport.Add(''); + lReport.Add(''); + + FMeansReportFrame.DisplayReport(lReport); + finally + lReport.Free; + end; end; -procedure TBNestedAForm.GetResults; -VAR - temp, constant : double; - NoBLevelsInA, BLevCount, i, j, celln : integer; -begin - celln := 0; - for i := 0 to NoALevels-1 do - begin - for j := 0 to NoBLevels-1 do - begin - if CellCount[j,i] > celln then celln := CellCount[j,i]; - end; - end; - // assume all cells have same n size - // get no. of levels in A - BLevCount := 0; - for i := 0 to NoALevels-1 do - begin - NoBLevelsInA := 0; - for j := 0 to NoBLevels-1 do - begin - if CellCount[j,i] > 0 then NoBLevelsInA := NoBLevelsInA + 1; - end; - if NoBLevelsInA > BLevCount then BLevCount := NoBLevelsInA; - end; - dfA := NoALevels - 1; - dfBwA := NoALevels * (BLevCount - 1); - dfwcell := NoALevels * BLevCount * (celln - 1); - dftotal := TotN - 1; - constant := SumSqrTot / TotN; - SSTot := SSTot - constant; - MSTot := SSTot / dftotal; - SSA := 0.0; - for i := 0 to NoALevels-1 do SSA := SSA + (ASumSqr[i] / ACount[i]); - temp := SSA; - SSA := SSA - constant; - MSA := SSA / dfA; - SSB := 0.0; - for i := 0 to NoALevels - 1 do - begin - for j := 0 to NoBLevels-1 do - begin - if CellCount[j,i] > 0 then SSB := SSB + (SumSqr[j,i] / CellCount[j,i]); - end; - end; - SSB := SSB - temp; - MSB := SSB / dfBwA; - SSW := SSTot - SSA - SSB; - MSW := SSW / dfwcell; - (* - OutputFrm.RichEdit.Clear; - strvalue := format('SSA = %10.3f MSA = %10.3f SSB = %10.3f MSB = %10.3f', - [SSA,MSA,SSB,MSB]); - OutputFrm.RichEdit.Lines.Add(strvalue); - strvalue := format('SSW = %10.3f MSW = %10.3f',[SSW,MSW]); - OutputFrm.RichEdit.Lines.Add(strvalue); - OutputFrm.ShowModal; -*) -end; -procedure TBNestedAForm.ShowResults(AReport: TStrings); +procedure TBNestedAForm.ShowResults; var F, PF: double; + lReport: TStrings; begin - AReport.Add('ANOVA TABLE'); - AReport.Add('SOURCE D.F. SS MS F PROB.'); + lReport := TStringList.Create; + try + lReport.Add('NESTED ANOVA by Bill Miller'); + lReport.Add(''); + lReport.Add('File analyzed: %s', [OS3MainFrm.FileNameEdit.Text]); + lReport.Add('Factor A: %s', [ACodesEdit.Text]); + lReport.Add('Factor B: %s', [BCodesEdit.Text]); + lReport.Add(''); + lReport.Add('ANOVA TABLE'); + lReport.Add('-------------------------------------------------------------'); + lReport.Add('SOURCE D.F. SS MS F PROB. '); + lReport.Add('--------- ---- ---------- ---------- --------- ---------'); - if RandomBChk.Checked then - begin - F := MSA / MSB; - PF := ProbF(F, dfA, dfBwA); - end else - begin - F := MSA / MSW; - PF := ProbF(F, dfA, dfwcell); + if RandomBChk.Checked then + begin + F := MSA / MSB; + PF := ProbF(F, dfA, dfBwA); + end else + begin + F := MSA / MSW; + PF := ProbF(F, dfA, dfwcell); + end; + lReport.Add('A %4d %10.3f %10.3f %9.3f %9.3f', [dfA, SSA, MSA, F, PF]); + + F := MSB / MSW; + PF := ProbF(F,dfBwA,dfwcell); + lReport.Add('B(W) %4d %10.3f %10.3f %9.3f %9.3f', [dfBwA, SSB, MSB, F, PF]); + + lReport.Add('w.cells %4d %10.3f %10.3f', [dfwcell, SSW, MSW]); + lReport.Add('Total %4d %10.3f', [dftotal, SSTot]); + lReport.Add('-------------------------------------------------------------'); + + FReportFrame.DisplayReport(lReport); + finally + lReport.Free; end; - AReport.Add('A %4d %10.3f%10.3f%10.3f%10.3f', [dfA, SSA, MSA, F, PF]); - - F := MSB / MSW; - PF := ProbF(F,dfBwA,dfwcell); - AReport.Add('B(W) %4d %10.3f%10.3f%10.3f%10.3f', [dfBwA, SSB, MSB, F, PF]); - - AReport.Add('w.cells %4d %10.3f%10.3f', [dfwcell, SSW, MSW]); - AReport.Add('Total %4d %10.3f', [dftotal, SSTot]); end; + +procedure TBNestedAForm.PopulateChartCombobox; +var + idx: Integer; +begin + idx := FChartCombobox.ItemIndex; + + FChartCombobox.Items.Clear; + FChartCombobox.Items.Add(ACodesEdit.Text); + FChartCombobox.Items.Add(BCodesEdit.Text); + + FChartCombobox.ItemIndex := EnsureRange(idx, 0, FChartCombobox.Items.Count-1); +end; + + procedure TBNestedAForm.ReleaseMemory; begin ASDs := nil; BCount := nil; ACount := nil; - BMeans := nil; - AMeans := nil; +// BMeans := nil; // needed for plotting +// AMeans := nil; BSumSqr := nil; ASumSqr := nil; BSS := nil; @@ -491,103 +611,164 @@ begin SS := nil; end; -procedure TBNestedAForm.TwoWayPlot; -VAR - plottype, i: integer; - maxmean: double; - XValue : DblDyneVec = nil; + +procedure TBNestedAForm.Reset; +var + i: integer; begin - case OptionsBox.ItemIndex of - 0: plotType := 9; - 1: plotType := 10; - 2: plotType := 1; - 3: plotType := 2; - else raise Exception.Create('Plot type not supported.'); + inherited; + + if FMeansReportFrame <> nil then + FMeansReportFrame.Clear; + if FChartCombobox <> nil then + FChartCombobox.Items.Clear; + + ACodesEdit.Clear; + BCodesEdit.Clear; + DepEdit.Clear; + + VarList.Items.Clear; + for i := 1 to NoVariables do + VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); +end; + + +procedure TBNestedAForm.SelectPlot(Sender: TObject); +var + i: Integer; +begin + FSeries.Clear; + + case FChartComboBox.ItemIndex of + 0: begin // Plot means vs factor A + for i := 0 to NoALevels-1 do + FSeries.AddXY(MinA + i, AMeans[i], IntToStr(MinA + i)); + FChartFrame.SetXTitle(ACodesEdit.Text + ' codes'); + FChartFrame.SetTitle('Factor ' + ACodesEdit.Text); + end; + 1: begin // Plot means vs factor B + for i := 0 to NoBLevels-1 do + FSeries.AddXY(MinB + i, BMeans[i], IntToStr(MinB + i)); + FChartFrame.SetXTitle(BCodesEdit.Text + ' codes'); + FChartFrame.SetTitle('Factor ' + BCodesEdit.Text); + end; end; - GraphFrm.SetLabels[1] := 'FACTOR A'; + FChartFrame.Chart.BottomAxis.Marks.Source := FSeries.Source; + FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel; + FChartFrame.Chart.Legend.Visible := FSeries.Source.YCount > 1; - maxmean := -1000.0; - SetLength(XValue,NoALevels+NoBLevels); - SetLength(GraphFrm.Xpoints,1,NoALevels); - SetLength(GraphFrm.Ypoints,1,NoALevels); - for i := 1 to NoALevels do - begin - GraphFrm.Ypoints[0,i-1] := AMeans[i-1]; - if AMeans[i-1] > maxmean then maxmean := AMeans[i-1]; - XValue[i-1] := MinA + i -1; - GraphFrm.Xpoints[0,i-1] := XValue[i-1]; - end; - GraphFrm.nosets := 1; - GraphFrm.nbars := NoALevels; - GraphFrm.Heading := FactorA; - GraphFrm.XTitle := FactorA + ' Group 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; + FChartFrame.UpdateBtnStates; - // Factor B next - maxmean := 0.0; - GraphFrm.SetLabels[1] := 'FACTOR B'; - SetLength(GraphFrm.Xpoints,1,NoBLevels); - SetLength(GraphFrm.Ypoints,1,NoBLevels); - for i := 1 to NoBLevels do - begin - GraphFrm.Ypoints[0,i-1] := BMeans[i-1]; - if BMeans[i-1] > maxmean then maxmean := BMeans[i-1]; - XValue[i-1] := MinB + i - 1; - GraphFrm.Xpoints[0,i-1] := XValue[i-1]; - end; - GraphFrm.nosets := 1; - GraphFrm.nbars := NoBLevels; - GraphFrm.Heading := 'FACTOR B'; - GraphFrm.XTitle := FactorB + ' Group 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; - XValue := nil; end; + +procedure TBNestedAForm.TwoWayPlot; +begin + if not ShowPlotsChk.Checked then + begin + ChartPage.TabVisible := false; + exit; + end; + + FChartFrame.Clear; // this destroys the series + FChartFrame.SetYTitle('Mean'); + + FSeries := FChartFrame.PlotXY(ptBars, nil, nil, nil, nil, '', DATA_Colors[0]); + with TBarSeries(FSeries) do + begin + Stacked := false; + {$IF LCL_FullVersion >= 2010000} + DepthBrightnessDelta := -30; + {$IFEND} + end; + + if Plot3DChk.Checked then + FSeries.Depth := 20; + + FChartCombobox.Parent.Left := 0; + PopulateChartCombobox; + SelectPlot(nil); + + ChartPage.TabVisible := true; +end; + + +function TBNestedAForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean; +begin + Result := false; + + if DepEdit.Text = '' then + begin + AMsg := 'Dependent variable not specified.'; + AControl := VarList; + exit; + end; + + if ACodesEdit.Text = '' then + begin + AMsg := 'Factor A variable not specified.'; + AControl := VarList; + exit; + end; + + if BCodesEdit.Text = '' then + begin + AMsg := 'Factor B variable not specified.'; + AControl := VarList; + exit; + end; + + Result := true; +end; + + +procedure TBNestedAForm.VarListDblClick(Sender: TObject); +var + index: Integer; + s: String; +begin + index := VarList.ItemIndex; + if index > -1 then + begin + s := VarList.Items[index]; + if DepEdit.Text = '' then + DepEdit.Text := s + else + if ACodesEdit.Text = '' then + ACodesEdit.Text := s + else + if BCodesEdit.Text = '' then + BCodesEdit.Text := s; + VarList.Items.Delete(index); + UpdateBtnStates; + end; +end; + + procedure TBNestedAForm.VarListSelectionChange(Sender: TObject; User: boolean); begin UpdateBtnStates; end; + procedure TBNestedAForm.UpdateBtnStates; var lSelected: Boolean; begin + inherited; + + if FMeansReportFrame <> nil then + FMeansReportFrame.UpdateBtnStates; + lSelected := AnySelected(VarList); - AInBtn.Enabled := lSelected and (ACodes.Text = ''); - BInBtn.Enabled := lSelected and (BCodes.Text = ''); + AInBtn.Enabled := lSelected and (ACodesEdit.Text = ''); + BInBtn.Enabled := lSelected and (BCodesEdit.Text = ''); DepInBtn.Enabled := lSelected and (DepEdit.Text = ''); - AOutBtn.Enabled := (ACodes.Text <> ''); - BOutBtn.Enabled := (BCodes.Text <> ''); + AOutBtn.Enabled := (ACodesEdit.Text <> ''); + BOutBtn.Enabled := (BCodesEdit.Text <> ''); DepOutBtn.Enabled := (DepEdit.Text <> ''); end; -initialization - {$I bnestaunit.lrs} - end.