diff --git a/applications/lazstats/docs/HelpNDoc/LazStats.hnd b/applications/lazstats/docs/HelpNDoc/LazStats.hnd index cfc751d17..ed02e360f 100644 Binary files a/applications/lazstats/docs/HelpNDoc/LazStats.hnd and b/applications/lazstats/docs/HelpNDoc/LazStats.hnd differ diff --git a/applications/lazstats/docs/chm/LazStats.chm b/applications/lazstats/docs/chm/LazStats.chm index 3d4662839..3d24064da 100644 Binary files a/applications/lazstats/docs/chm/LazStats.chm and b/applications/lazstats/docs/chm/LazStats.chm differ diff --git a/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.lfm b/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.lfm index 83a56a64a..75800a077 100644 --- a/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.lfm +++ b/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.lfm @@ -1,106 +1,86 @@ object PolyDIFFrm: TPolyDIFFrm - Left = 548 + Left = 984 Height = 413 - Top = 305 - Width = 631 + Top = 356 + Width = 657 AutoSize = True Caption = 'Polytomous Item DIF' ClientHeight = 413 - ClientWidth = 631 + ClientWidth = 657 OnActivate = FormActivate OnCreate = FormCreate OnShow = FormShow Position = poMainFormCenter LCLVersion = '2.1.0.0' object ResetBtn: TButton - AnchorSideRight.Control = CancelBtn + AnchorSideRight.Control = ComputeBtn AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 334 + Left = 448 Height = 25 Top = 380 Width = 54 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 - BorderSpacing.Right = 12 + BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 Caption = 'Reset' OnClick = ResetBtnClick TabOrder = 3 end - object CancelBtn: TButton - AnchorSideRight.Control = ComputeBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 400 - Height = 25 - Top = 380 - Width = 62 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 12 - BorderSpacing.Top = 8 - BorderSpacing.Right = 12 - BorderSpacing.Bottom = 8 - Caption = 'Cancel' - ModalResult = 2 - OnClick = CancelBtnClick - TabOrder = 4 - end object ComputeBtn: TButton - AnchorSideRight.Control = ReturnBtn + AnchorSideRight.Control = CloseBtn AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 474 + Left = 510 Height = 25 Top = 380 Width = 76 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 - BorderSpacing.Right = 12 + BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 Caption = 'Compute' OnClick = ComputeBtnClick - TabOrder = 5 + TabOrder = 4 end - object ReturnBtn: TButton + object CloseBtn: TButton AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 562 + Left = 594 Height = 25 Top = 380 - Width = 61 + Width = 55 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 - Caption = 'Return' - ModalResult = 1 - OnClick = ReturnBtnClick - TabOrder = 6 + Caption = 'Close' + ModalResult = 11 + TabOrder = 5 end object HelpBtn: TButton Tag = 138 AnchorSideRight.Control = ResetBtn AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 271 + Left = 389 Height = 25 Top = 380 Width = 51 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 - BorderSpacing.Right = 12 + BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 Caption = 'Help' OnClick = HelpBtnClick @@ -114,14 +94,14 @@ object PolyDIFFrm: TPolyDIFFrm Left = 8 Height = 356 Top = 8 - Width = 411 + Width = 437 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 8 BorderSpacing.Top = 8 BorderSpacing.Right = 16 BevelOuter = bvNone ClientHeight = 356 - ClientWidth = 411 + ClientWidth = 437 Constraints.MinWidth = 400 TabOrder = 0 object Label1: TLabel @@ -137,7 +117,7 @@ object PolyDIFFrm: TPolyDIFFrm object Label2: TLabel AnchorSideLeft.Control = ItemsList AnchorSideTop.Control = Panel1 - Left = 236 + Left = 249 Height = 15 Top = 0 Width = 76 @@ -147,7 +127,7 @@ object PolyDIFFrm: TPolyDIFFrm object Label3: TLabel AnchorSideLeft.Control = ItemsList AnchorSideBottom.Control = GroupVarEdit - Left = 236 + Left = 249 Height = 15 Top = 296 Width = 94 @@ -166,19 +146,20 @@ object PolyDIFFrm: TPolyDIFFrm Left = 0 Height = 339 Top = 17 - Width = 174 + Width = 187 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 2 BorderSpacing.Right = 8 ItemHeight = 0 MultiSelect = True + OnSelectionChange = VarListSelectionChange TabOrder = 0 end object ItemInBtn: TBitBtn AnchorSideLeft.Control = Panel1 AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = VarList - Left = 191 + Left = 204 Height = 28 Top = 25 Width = 28 @@ -194,7 +175,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = ItemInBtn AnchorSideTop.Side = asrBottom - Left = 191 + Left = 204 Height = 28 Top = 57 Width = 28 @@ -210,7 +191,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideLeft.Side = asrCenter AnchorSideTop.Control = ItemOutBtn AnchorSideTop.Side = asrBottom - Left = 182 + Left = 195 Height = 25 Top = 89 Width = 46 @@ -225,7 +206,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideLeft.Control = Panel1 AnchorSideLeft.Side = asrCenter AnchorSideBottom.Control = GrpOutBtn - Left = 191 + Left = 204 Height = 28 Top = 288 Width = 28 @@ -242,7 +223,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideLeft.Side = asrCenter AnchorSideBottom.Control = VarList AnchorSideBottom.Side = asrBottom - Left = 191 + Left = 204 Height = 28 Top = 320 Width = 28 @@ -260,12 +241,13 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = GrpOutBtn AnchorSideBottom.Side = asrBottom - Left = 236 + Left = 249 Height = 23 Top = 313 - Width = 175 + Width = 188 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Bottom = 12 + ReadOnly = True TabOrder = 7 Text = 'GroupVarEdit' end @@ -277,15 +259,17 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Control = Panel1 AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = GrpInBtn - Left = 236 + Left = 249 Height = 247 Top = 17 - Width = 175 + Width = 188 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 8 BorderSpacing.Top = 2 BorderSpacing.Bottom = 24 ItemHeight = 0 + MultiSelect = True + OnSelectionChange = VarListSelectionChange TabOrder = 4 end end @@ -293,11 +277,11 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = ReturnBtn + AnchorSideBottom.Control = CloseBtn Left = 0 Height = 8 Top = 364 - Width = 631 + Width = 657 Anchors = [akLeft, akRight, akBottom] Shape = bsBottomLine end @@ -306,12 +290,11 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Bevel1 - Left = 435 + Left = 461 Height = 364 Top = 0 Width = 196 Anchors = [akTop, akRight, akBottom] - AutoSize = True BevelOuter = bvNone ClientHeight = 364 ClientWidth = 196 @@ -322,7 +305,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideTop.Side = asrCenter Left = 0 Height = 15 - Top = 12 + Top = 132 Width = 124 Caption = 'No. of Grouping Levels:' ParentColor = False @@ -333,7 +316,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideTop.Side = asrCenter Left = 0 Height = 15 - Top = 191 + Top = 16 Width = 99 Caption = 'Lowest Item Score:' ParentColor = False @@ -344,7 +327,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideTop.Side = asrCenter Left = 0 Height = 15 - Top = 218 + Top = 43 Width = 103 Caption = 'Highest Item Score:' ParentColor = False @@ -355,7 +338,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideTop.Side = asrCenter Left = 0 Height = 15 - Top = 245 + Top = 70 Width = 122 Caption = 'Reference Group Code:' ParentColor = False @@ -366,34 +349,36 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideTop.Side = asrCenter Left = 0 Height = 15 - Top = 272 + Top = 97 Width = 98 Caption = 'Focal Group Code:' ParentColor = False end object LevelsEdit: TEdit + AnchorSideTop.Control = TrgtGrpEdit + AnchorSideTop.Side = asrBottom AnchorSideRight.Control = GroupBox2 AnchorSideRight.Side = asrBottom Left = 140 Height = 23 - Top = 8 + Top = 128 Width = 40 Alignment = taRightJustify Anchors = [akTop, akRight] - BorderSpacing.Top = 8 + BorderSpacing.Top = 12 BorderSpacing.Right = 8 - OnExit = LevelsEditExit - TabOrder = 0 + OnEditingDone = LevelsEditEditingDone + TabOrder = 4 end object GroupBox1: TGroupBox AnchorSideLeft.Control = GroupBox2 - AnchorSideTop.Control = TrgtGrpEdit + AnchorSideTop.Control = GroupBox2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = GroupBox2 AnchorSideRight.Side = asrBottom Left = 0 Height = 51 - Top = 303 + Top = 307 Width = 188 Anchors = [akTop, akLeft, akRight] AutoSize = True @@ -417,19 +402,19 @@ object PolyDIFFrm: TPolyDIFFrm end object LowScoreEdit: TEdit AnchorSideLeft.Control = LevelsEdit - AnchorSideTop.Control = GroupBox2 - AnchorSideTop.Side = asrBottom + AnchorSideTop.Control = Panel3 AnchorSideRight.Control = GroupBox2 AnchorSideRight.Side = asrBottom Left = 140 Height = 23 - Top = 187 + Top = 12 Width = 40 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 12 BorderSpacing.Right = 8 - TabOrder = 2 + TabOrder = 0 + Text = 'LowScoreEdit' end object HiScoreEdit: TEdit AnchorSideLeft.Control = LowScoreEdit @@ -439,13 +424,13 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Side = asrBottom Left = 140 Height = 23 - Top = 214 + Top = 39 Width = 40 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 - TabOrder = 3 - Text = 'Edit1' + TabOrder = 1 + Text = 'HiScoreEdit' end object RefGrpEdit: TEdit AnchorSideLeft.Control = LowScoreEdit @@ -455,13 +440,13 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Side = asrBottom Left = 140 Height = 23 - Top = 241 + Top = 66 Width = 40 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 - TabOrder = 4 - Text = 'Edit1' + TabOrder = 2 + Text = 'RefGrpEdit' end object TrgtGrpEdit: TEdit AnchorSideLeft.Control = LowScoreEdit @@ -471,13 +456,13 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Side = asrBottom Left = 140 Height = 23 - Top = 268 + Top = 93 Width = 40 Alignment = taRightJustify Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 4 - TabOrder = 5 - Text = 'Edit1' + TabOrder = 3 + Text = 'TrgtGrpEdit' end object GroupBox2: TGroupBox AnchorSideLeft.Control = Panel3 @@ -487,7 +472,7 @@ object PolyDIFFrm: TPolyDIFFrm AnchorSideRight.Side = asrBottom Left = 0 Height = 132 - Top = 43 + Top = 163 Width = 188 AutoSize = True BorderSpacing.Top = 12 @@ -495,7 +480,7 @@ object PolyDIFFrm: TPolyDIFFrm Caption = 'Enter Bounds for Levels' ClientHeight = 112 ClientWidth = 184 - TabOrder = 1 + TabOrder = 5 object Panel2: TPanel Left = 8 Height = 104 @@ -584,25 +569,9 @@ object PolyDIFFrm: TPolyDIFFrm PageSize = 0 Position = 1 TabOrder = 0 - OnScroll = LevelScrollScroll - end - object LevelNoEdit: TEdit - AnchorSideTop.Control = Label8 - AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = Panel2 - AnchorSideRight.Side = asrBottom - Left = 129 - Height = 23 - Top = 19 - Width = 39 - Alignment = taRightJustify - Anchors = [akTop, akRight] - BorderSpacing.Top = 4 - TabOrder = 1 - Text = 'LevelNoEdit' + OnChange = LevelScrollChange end object LowBoundEdit: TEdit - AnchorSideTop.Control = LevelNoEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = Panel2 AnchorSideRight.Side = asrBottom @@ -613,7 +582,7 @@ object PolyDIFFrm: TPolyDIFFrm Alignment = taRightJustify Anchors = [akTop, akRight] BorderSpacing.Top = 8 - OnExit = LowBoundEditExit + OnEditingDone = LowBoundEditEditingDone TabOrder = 2 Text = 'LowBoundEdit' end @@ -629,10 +598,25 @@ object PolyDIFFrm: TPolyDIFFrm Alignment = taRightJustify Anchors = [akTop, akRight] BorderSpacing.Top = 8 - OnExit = UpBoundEditExit + OnEditingDone = UpBoundEditEditingDone TabOrder = 3 Text = 'Edit1' end + object LevelNoEdit: TStaticText + AnchorSideTop.Control = Label8 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Panel2 + AnchorSideRight.Side = asrBottom + Left = 129 + Height = 23 + Top = 19 + Width = 39 + Alignment = taRightJustify + Anchors = [akTop, akRight] + BorderSpacing.Top = 4 + BorderStyle = sbsSingle + TabOrder = 1 + end end end end diff --git a/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.pas b/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.pas index a91cded2b..f014ce199 100644 --- a/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.pas +++ b/applications/lazstats/source/forms/analysis/measurement_programs/polydifunit.pas @@ -1,3 +1,14 @@ +// Data file not clear, probably PolyDIFData.laz +// - lowest item score 1 +// - highest item score 5 +// - reference group score 1 +// - focus group score 2 +// - No of grouping levels 3 +// - Level 1: lower bound 0, upper bound 1 +// - Level 2: lower bound 2, upper bound 3 +// - Level 3: lower bound 4, upper bound 5 +// The results obtained this way match the pdf file. + unit PolyDifUnit; {$mode objfpc}{$H+} @@ -17,13 +28,13 @@ type Bevel1: TBevel; GroupBox2: TGroupBox; HelpBtn: TButton; + LevelNoEdit: TStaticText; Panel1: TPanel; Panel2: TPanel; Panel3: TPanel; ResetBtn: TButton; - CancelBtn: TButton; ComputeBtn: TButton; - ReturnBtn: TButton; + CloseBtn: TButton; LowScoreEdit: TEdit; HiScoreEdit: TEdit; RefGrpEdit: TEdit; @@ -38,7 +49,6 @@ type UpBoundEdit: TEdit; Label10: TLabel; Label9: TLabel; - LevelNoEdit: TEdit; Label6: TLabel; Label7: TLabel; Label8: TLabel; @@ -57,7 +67,6 @@ type LevelScroll: TScrollBar; VarList: TListBox; procedure AllBtnClick(Sender: TObject); - procedure CancelBtnClick(Sender: TObject); procedure ComputeBtnClick(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormCreate(Sender: TObject); @@ -67,22 +76,23 @@ type procedure HelpBtnClick(Sender: TObject); procedure ItemInBtnClick(Sender: TObject); procedure ItemOutBtnClick(Sender: TObject); - procedure LevelScrollScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); - procedure LevelsEditExit(Sender: TObject); - procedure LowBoundEditExit(Sender: TObject); + procedure LevelScrollChange(Sender: TObject); + procedure LevelsEditEditingDone(Sender: TObject); + procedure LowBoundEditEditingDone(Sender: TObject); procedure ResetBtnClick(Sender: TObject); - procedure ReturnBtnClick(Sender: TObject); - procedure UpBoundEditExit(Sender: TObject); + procedure UpBoundEditEditingDone(Sender: TObject); + procedure VarListSelectionChange(Sender: TObject; User: boolean); private { private declarations } - NoItems : integer; - FAutoSized: Boolean; - nocats : integer; - ColNoSelected : IntDyneVec; - ColLabels, RowLabels : StrDyneVec; - Ubounds : IntDyneVec; // upper and lower bounds of score groups - Lbounds : IntdyneVec; + FAutoSized: Boolean; + NoItems: integer; + nocats: integer; + ColNoSelected: IntDyneVec; + ColLabels, RowLabels: StrDyneVec; + Ubounds: IntDyneVec; // upper and lower bounds of score groups + Lbounds: IntdyneVec; + procedure UpdateBtnStates; + function ValidNumEdit(AEdit: TEdit; AName: String; out AValue: Integer): Boolean; public { public declarations } @@ -94,65 +104,61 @@ var implementation uses - Math; + Math, StrUtils, Utils; { TPolyDIFFrm } procedure TPolyDIFFrm.ResetBtnClick(Sender: TObject); -VAR i : integer; +var + i: integer; begin - VarList.Clear; - ItemsList.Clear; - GroupVarEdit.Text := ''; - ItemInBtn.Enabled := true; - ItemOutBtn.Enabled := false; - AllBtn.Enabled := true; - GrpInBtn.Enabled := true; - GrpOutBtn.Enabled := false; -// MHChk.Checked := true; - RefGrpEdit.Text := ''; - TrgtGrpEdit.Text := ''; - LowScoreEdit.Text := ''; - HiScoreEdit.Text := ''; - LevelsEdit.Text := ''; - for i := 1 to NoVariables do - VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); - if NoVariables > 0 then LevelScroll.Max := NoVariables; - LevelNoEdit.Text := '1'; - LowBoundEdit.Text := '0'; - UpBoundEdit.Text := '2'; - LevelScroll.Min := 1; - LevelScroll.Position := 1; - //allocate space on heap - SetLength(ColLabels,NoVariables+1); - SetLength(RowLabels,NoVariables+1); - SetLength(ColNoSelected,NoVariables); - SetLength(Lbounds,NoVariables * 10); - SetLength(Ubounds,NoVariables * 10); + //allocate space on heap + SetLength(ColLabels, NoVariables + 1); + SetLength(RowLabels, NoVariables + 1); + SetLength(ColNoSelected, NoVariables); + SetLength(Lbounds, NoVariables * 10); + SetLength(Ubounds, NoVariables * 10); + for i:=0 to High(LBounds) do LBounds[i] := -1; + for i:=0 to High(UBounds) do UBounds[i] := -1; + + VarList.Clear; + ItemsList.Clear; + GroupVarEdit.Text := ''; + RefGrpEdit.Text := ''; + TrgtGrpEdit.Text := ''; + LowScoreEdit.Text := ''; + HiScoreEdit.Text := ''; + for i := 1 to NoVariables do + VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); + LevelScroll.Min := 0; //1; + LevelScroll.Max := 0; //LevelScroll.Min; + LevelScroll.Position := 0; //1; + { + if NoVariables > 0 then + LevelScroll.Max := NoVariables; + } + LevelsEdit.Text := ''; //IntToStr(NoVariables); + LevelNoEdit.Caption := ''; //'1'; + LowBoundEdit.Text := ''; //'0'; + UpBoundEdit.Text := ''; //'2'; + ComputeBtn.Enabled := false; + + UpdateBtnStates; end; -procedure TPolyDIFFrm.ReturnBtnClick(Sender: TObject); +procedure TPolyDIFFrm.UpBoundEditEditingDone(Sender: TObject); +var + level: Integer; begin - Ubounds := nil; - Lbounds := nil; - ColNoSelected := nil; - RowLabels := nil; - ColLabels := nil; - Close; -end; - -procedure TPolyDIFFrm.UpBoundEditExit(Sender: TObject); -VAR i : integer; -begin - i := StrToInt(LevelNoEdit.Text); - Ubounds[i-1] := StrToInt(UpBoundEdit.Text); - if i = StrToInt(LevelsEdit.Text) then - begin - ComputeBtn.SetFocus; - exit; - end; - LowBoundEdit.Text := IntToStr(Ubounds[i-1] + 1); - LowBoundEdit.SetFocus; + level := StrToInt(LevelNoEdit.Caption) - 1; + Ubounds[level] := StrToInt(UpBoundEdit.Text); + if level + 1 = StrToInt(LevelsEdit.Text) then + begin + ComputeBtn.Enabled := true; + exit; + end; + LowBoundEdit.Text := IntToStr(UBounds[level]); //IntToStr(Ubounds[level] + 1); +// LowBoundEdit.SetFocus; end; procedure TPolyDIFFrm.FormActivate(Sender: TObject); @@ -162,12 +168,11 @@ begin if FAutoSized then exit; - w := MaxValue([HelpBtn.Width, ResetBtn.Width, CancelBtn.Width, ComputeBtn.Width, ReturnBtn.Width]); + w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]); HelpBtn.Constraints.MinWidth := w; ResetBtn.Constraints.MinWidth := w; - CancelBtn.Constraints.MinWidth := w; ComputeBtn.Constraints.MinWidth := w; - ReturnBtn.Constraints.MinWidth := w; + CloseBtn.Constraints.MinWidth := w; Constraints.MinHeight := Height; Constraints.MinWidth := Width; @@ -178,9 +183,6 @@ end; procedure TPolyDIFFrm.FormCreate(Sender: TObject); begin Assert(OS3MainFrm <> nil); - - if OutputFrm = nil then - Application.CreateForm(TOutputFrm, OutputFrm); if GraphFrm = nil then Application.CreateForm(TGraphFrm, GraphFrm); end; @@ -191,26 +193,26 @@ begin end; procedure TPolyDIFFrm.GrpInBtnClick(Sender: TObject); -VAR index : integer; +var + index: integer; begin - if VarList.ItemIndex < 0 then - begin - GrpInBtn.Enabled := false; - exit; - end; - index := VarList.ItemIndex; - GroupVarEdit.Text := VarList.Items.Strings[index]; - VarList.Items.Delete(index); - GrpInBtn.Enabled := false; - GrpOutBtn.Enabled := true; + index := VarList.ItemIndex; + if (index > -1) and (GroupVarEdit.Text = '') then + begin + GroupVarEdit.Text := VarList.Items[index]; + VarList.Items.Delete(index); + UpdateBtnStates; + end; end; procedure TPolyDIFFrm.GrpOutBtnClick(Sender: TObject); begin - VarList.Items.Add(GroupVarEdit.Text); - GroupVarEdit.Text := ''; - GrpOutBtn.Enabled := false; - GrpInBtn.Enabled := true; + if GroupVarEdit.Text <> '' then + begin + VarList.Items.Add(GroupVarEdit.Text); + GroupVarEdit.Text := ''; + UpdateBtnStates; + end; end; procedure TPolyDIFFrm.HelpBtnClick(Sender: TObject); @@ -221,400 +223,507 @@ begin end; procedure TPolyDIFFrm.ItemInBtnClick(Sender: TObject); -VAR i, index : integer; +var + i: integer; begin - if VarList.ItemIndex < 0 then - begin - ItemInBtn.Enabled := false; - exit; - end; - index := VarList.Items.Count; - i := 0; - while i < index do - begin - if (VarList.Selected[i]) then - begin - ItemsList.Items.Add(VarList.Items.Strings[i]); - VarList.Items.Delete(i); - index := index - 1; - i := 0; - end - else i := i + 1; - end; - ItemOutBtn.Enabled := true; + i := 0; + while i < VarList.Items.Count do + begin + if VarList.Selected[i] then + begin + ItemsList.Items.Add(VarList.Items[i]); + VarList.Items.Delete(i); + i := 0; + end + else + i := i + 1; + end; + UpdateBtnStates; + LevelsEdit.Text := IntToStr(ItemsList.Count); + LevelsEditEditingDone(nil); end; procedure TPolyDIFFrm.ItemOutBtnClick(Sender: TObject); -VAR index : integer; -begin - index := ItemsList.ItemIndex; - if index < 0 then - begin - ItemOutBtn.Enabled := false; - exit; - end; - VarList.Items.Add(ItemsList.Items.Strings[index]); - ItemsList.Items.Delete(index); - ItemInBtn.Enabled := true; -end; - -procedure TPolyDIFFrm.LevelScrollScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); var - scrlpos : integer; - level : integer; + i: integer; begin - level := StrToInt(LevelNoEdit.Text); - scrlpos := LevelScroll.Position; - if ((scrlpos > level) and (level <= StrToInt(LevelsEdit.Text))) then - begin - LevelNoEdit.Text := IntToStr(scrlpos); - LowBoundEdit.SetFocus; - exit; - end; - if scrlpos < level then - begin - level := scrlpos; - if level > 0 then - begin - LevelNoEdit.Text := IntToStr(level); - LowBoundEdit.Text := IntToStr(Lbounds[level-1]); - UpBoundEdit.Text := IntToStr(Ubounds[level-1]); - end; - LowBoundEdit.SetFocus; - end; + i := 0; + while i < ItemsList.Items.Count do + begin + if ItemsList.Selected[i] then + begin + VarList.Items.Add(ItemsList.Items[i]); + ItemsList.Items.Delete(i); + i := 0; + end + else + i := i + 1; + end; + UpdateBtnStates; + LevelsEdit.Text := IntToStr(ItemsList.Count); + LevelsEditEditingDone(nil); end; -procedure TPolyDIFFrm.LevelsEditExit(Sender: TObject); +procedure TPolyDIFFrm.LevelScrollChange(Sender: TObject); +var + level: integer; begin - LevelScroll.Max := StrToInt(LevelsEdit.Text); - LowBoundEdit.SetFocus; + level := LevelScroll.Position; + LevelNoEdit.Caption := IntToStr(level + 1); + + if LBounds[level] = -1 then + LowBoundEdit.Text := '' + else + LowBoundEdit.Text :=IntToStr(LBounds[level]); + + if UBounds[level] = -1 then + UpBoundEdit.Text := '' + else + UpBoundEdit.Text := IntToStr(UBounds[level]); end; -procedure TPolyDIFFrm.LowBoundEditExit(Sender: TObject); -VAR i : integer; + // wp: Setting focus to other controls makes the form very difficult to use. + +{ + level := StrToInt(LevelNoEdit.Text); + scrlpos := LevelScroll.Position; + if ((scrlpos > level) and (level <= StrToInt(LevelsEdit.Text))) then + begin + LevelNoEdit.Text := IntToStr(scrlpos); + LowBoundEdit.SetFocus; + exit; + end; + if scrlpos < level then + begin + level := scrlpos; + if level > 0 then + begin + LevelNoEdit.Text := IntToStr(level); + LowBoundEdit.Text := IntToStr(Lbounds[level-1]); + UpBoundEdit.Text := IntToStr(Ubounds[level-1]); + end; + LowBoundEdit.SetFocus; + end; +end; +} + +procedure TPolyDIFFrm.LevelsEditEditingDone(Sender: TObject); +var + L: Integer; begin - i := StrToInt(LevelNoEdit.Text); - Lbounds[i-1] := StrToInt(LowBoundEdit.Text); - UpBoundEdit.SetFocus; + if ValidNumEdit(LevelsEdit, 'No. of Grouping Levels', L) then + begin + LevelScroll.Max := Max(L - 1, 0); + LevelScroll.Min := 0; + LevelNoEdit.Caption := IntToStr(LevelScroll.Position + 1); + //LevelScroll.Enabled := true; + //LowBoundEdit.SetFocus; + end; end; -procedure TPolyDIFFrm.CancelBtnClick(Sender: TObject); +procedure TPolyDIFFrm.LowBoundEditEditingDone(Sender: TObject); +var + level: integer; begin - Ubounds := nil; - Lbounds := nil; - ColNoSelected := nil; - RowLabels := nil; - ColLabels := nil; - Close; + level := LevelScroll.Position; +// level := StrToInt(LevelNoEdit.Caption) - 1; + Lbounds[level] := StrToInt(LowBoundEdit.Text); + //UpBoundEdit.Set end; procedure TPolyDIFFrm.AllBtnClick(Sender: TObject); -VAR i : integer; +var + i: integer; begin - if VarList.Items.Count < 1 then exit; - for i := 0 to VarList.Items.Count - 1 do - ItemsList.Items.Add(VarList.Items.Strings[i]); - VarList.Clear; - ItemInBtn.Enabled := false; - ItemOutBtn.Enabled := true; + if VarList.Items.Count < 1 then + exit; + for i := 0 to VarList.Items.Count - 1 do + ItemsList.Items.Add(VarList.Items[i]); + VarList.Clear; + UpdateBtnStates; + LevelsEdit.Text := IntToStr(ItemsList.Count); + LevelsEditEditingDone(nil); end; procedure TPolyDIFFrm.ComputeBtnClick(Sender: TObject); var - i, j, k : integer; - itm, nolevels, level : integer; - grpvar : integer; - subjgrp : integer; - subjtot : integer; - value : integer; - cellstring : string; - title : string; - nsize : array [1..2] of integer; - FData : IntDyneCube; //no. of category values within item for focal group - RData : IntDyneCube; //no. of category values within item for reference group - TotData : IntDyneCube; // sum of the above two - t, Mf, Mb, Sf, Sb, Nb, Nf, df, d, Sd : DblDyneVec; - Zc, Vart, BigJ, SumE, SumV, Term1, MY, prob : double; - X, BigDnum, BigDden, BigD, BigDS, Zd, M2, E, VarE, Ti, dftot : double; - loscore, hiscore : integer; + i, j, k : integer; + itm, nolevels, level : integer; + grpvar : integer; + subjgrp : integer; + subjtot : integer; + value : integer; + cellstring : string; + title : string; + nsize : array [1..2] of integer; + FData : IntDyneCube; //no. of category values within item for focal group + RData : IntDyneCube; //no. of category values within item for reference group + TotData : IntDyneCube; // sum of the above two + t, Mf, Mb, Sf, Sb, Nb, Nf, df, d, Sd : DblDyneVec; + Zc, Vart, BigJ, SumE, SumV, Term1, MY, prob : double; + X, BigDnum, BigDden, BigD, BigDS, Zd, M2, E, VarE, Ti, dftot : double; + loscore, hiscore : integer; + lReport: TStrings; begin - OutputFrm.RichEdit.Clear; - OutputFrm.RichEdit.Lines.Add('Polytomous Item DIF Analysis adapted by Bill Miller from'); - OutputFrm.RichEdit.Lines.Add('Procedures for extending item bias detection techniques'); - OutputFrm.RichEdit.Lines.Add('by Catherine Welch and H.D. Hoover, 1993'); - OutputFrm.RichEdit.Lines.Add('Applied Measurement in Education 6(1), pages 1-19.'); - OutputFrm.RichEdit.Lines.Add(''); + NoItems := ItemsList.Items.Count; + if NoItems = 0 then + begin + MessageDlg('No items selected.', mtError, [mbOK], 0); + exit; + end; - NoItems := ItemsList.Items.Count; - loscore := StrToInt(LowScoreEdit.Text); - hiscore := StrToInt(HiScoreEdit.Text); - nocats := hiscore - loscore + 1; // 0 to highest score - nolevels := StrToInt(LevelsEdit.Text); - SetLength(FData,NoItems,hiscore+10,nolevels+10); - SetLength(RData,NoItems,hiscore+10,nolevels+10); - SetLength(TotData,NoItems,hiscore+10,nolevels+10); - SetLength(t,nolevels); - SetLength(Mf,nolevels); - SetLength(Mb,nolevels); - SetLength(Sf,nolevels); - SetLength(Sb,nolevels); - SetLength(Nb,nolevels); - SetLength(Nf,nolevels); - SetLength(df,nolevels); - SetLength(d,nolevels); - SetLength(Sd,nolevels); + if not ValidNumEdit(LevelsEdit, 'Number of Grouping Levels', noLevels) then + exit; + if not ValidNumEdit(LowScoreEdit, 'Lowest Item Score', loscore) then + exit; + if not ValidNumEdit(HiScoreEdit, 'Highest Item Score', hiscore) then + exit; + if not ValidNumEdit(RefGrpEdit, 'Reference Group Code', i) then + exit; + if not ValidNumEdit(TrgtGrpEdit, 'Focus Group Code', i) then + exit; - for k := 1 to 2 do nsize[k] := 0; + lReport := TStringList.Create; + try + lReport.Add('POLYTOMOUS ITEM DIF ANALYSIS'); + lReport.Add('adapted by Bill Miller from'); + lReport.Add('Procedures for extending item bias detection techniques'); + lReport.Add('by Catherine Welch and H.D. Hoover, 1993'); + lReport.Add('Applied Measurement in Education 6(1), pages 1-19.'); + lReport.Add(''); - // get items to analyze and their labels - for i := 1 to NoItems do // items to analyze - begin - for j := 1 to NoVariables do // variables in grid - begin - cellstring := OS3MainFrm.DataGrid.Cells[j,0]; - if cellstring = ItemsList.Items.Strings[i-1] then - begin // matched - save info - ColNoSelected[i-1] := j; - ColLabels[i-1] := cellstring; - RowLabels[i-1] := cellstring; - end; // end match - end; // next j - end; // next i - ColLabels[NoItems] := 'TOTAL'; - RowLabels[NoItems] := 'TOTAL'; + nocats := hiscore - loscore + 1; // 0 to highest score - // get the variable number of the grouping code - grpvar := 0; - for i := 1 to NoVariables do - begin - cellstring := OS3MainFrm.DataGrid.Cells[i,0]; - if cellstring = GroupVarEdit.Text then grpvar := i; - end; - if grpvar = 0 then - begin - ShowMessage('Error - No group variable found.'); - exit; - end; + SetLength(FData,NoItems,hiscore+10,nolevels+10); + SetLength(RData,NoItems,hiscore+10,nolevels+10); + SetLength(TotData,NoItems,hiscore+10,nolevels+10); + SetLength(t,nolevels); + SetLength(Mf,nolevels); + SetLength(Mb,nolevels); + SetLength(Sf,nolevels); + SetLength(Sb,nolevels); + SetLength(Nb,nolevels); + SetLength(Nf,nolevels); + SetLength(df,nolevels); + SetLength(d,nolevels); + SetLength(Sd,nolevels); - // read data (score group and items) - for i := 1 to NoCases do - begin - subjtot := 0; - // Get group (reference or target) - value := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[grpvar,i]))); - subjgrp := 0; - if value = StrToInt(RefGrpEdit.Text) then subjgrp := 1; // reference grp - if value = StrToInt(TrgtGrpEdit.Text) then subjgrp := 2; // target group - if subjgrp = 0 then - begin - ShowMessage('Error - Bad group code for a subject.'); - exit; - end; - nsize[subjgrp] := nsize[subjgrp] + 1; + for k := 1 to 2 do + nsize[k] := 0; - for j := 1 to NoItems do // get item score and subject total - begin - itm := ColNoSelected[j-1]; - value := Round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[itm,i]))); - subjtot := subjtot + value; - end; + // get items to analyze and their labels + for i := 1 to NoItems do // items to analyze + begin + for j := 1 to NoVariables do // variables in grid + begin + cellstring := OS3MainFrm.DataGrid.Cells[j,0]; + if cellstring = ItemsList.Items.Strings[i-1] then + begin // matched - save info + ColNoSelected[i-1] := j; + ColLabels[i-1] := cellstring; + RowLabels[i-1] := cellstring; + end; // end match + end; // next j + end; // next i + ColLabels[NoItems] := 'TOTAL'; + RowLabels[NoItems] := 'TOTAL'; - level := 0; - for k := 0 to NoLevels-1 do // get score level category - begin - if ((subjtot >= Lbounds[k]) and (subjtot <= Ubounds[k])) then - level := k; - end; + // get the variable number of the grouping code + grpvar := 0; + for i := 1 to NoVariables do + begin + cellstring := OS3MainFrm.DataGrid.Cells[i,0]; + if cellstring = GroupVarEdit.Text then grpvar := i; + end; + if grpvar = 0 then + begin + MessageDlg('No group variable found.', mtError, [mbOK], 0); + exit; + end; - for j := 1 to NoItems do // add to data - begin - itm := ColNoSelected[j-1]; - value := Round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[itm,i]))); - value := value - loscore; - if subjgrp = 1 then - RData[j-1,value,level] := RData[j-1,value,level] + 1 - else FData[j-1,value,level] := FData[j-1,value,level] + 1; - TotData[j-1,value,level] := TotData[j-1,value,level] + 1; - end; - end; // next case i + // read data (score group and items) + for i := 1 to NoCases do + begin + // Get group (reference or target) + value := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[grpvar,i]))); + subjgrp := 0; + if value = StrToInt(RefGrpEdit.Text) then subjgrp := 1; // reference grp + if value = StrToInt(TrgtGrpEdit.Text) then subjgrp := 2; // target group + if subjgrp = 0 then + begin + MessageDlg('Bad group code for a subject.', mtError, [mbOK], 0); + exit; + end; + nsize[subjgrp] := nsize[subjgrp] + 1; + + // get item score and subject total + subjtot := 0; + for j := 1 to NoItems do + begin + itm := ColNoSelected[j-1]; + value := Round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[itm,i]))); + subjtot := subjtot + value; + end; + + // get score level category + level := 0; + for k := 0 to NoLevels-1 do + if ((subjtot >= Lbounds[k]) and (subjtot <= Ubounds[k])) then + level := k; + + // add to data + for j := 1 to NoItems do + begin + itm := ColNoSelected[j-1]; + value := Round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[itm,i]))); + value := value - loscore; + if subjgrp = 1 then + RData[j-1,value,level] := RData[j-1,value,level] + 1 + else + FData[j-1,value,level] := FData[j-1,value,level] + 1; + TotData[j-1,value,level] := TotData[j-1,value,level] + 1; + end; + end; // next case i // Show upper and lower bounds for score group bins - OutputFrm.RichEdit.Lines.Add('Conditioning Levels'); - OutputFrm.RichEdit.Lines.Add('Lower Upper'); - for i := 0 to nolevels-1 do - begin - cellstring := format('%5d %5d',[Lbounds[i],Ubounds[i]]); - OutputFrm.RichEdit.Lines.Add(cellstring); - end; - OutputFrm.RichEdit.Lines.Add(''); + lReport.Add('Conditioning Levels'); + lReport.Add(''); + lReport.Add('Lower Upper'); + lReport.Add('----- -----'); + for i := 0 to nolevels-1 do + lReport.Add('%5d %5d', [Lbounds[i], Ubounds[i]]); + lReport.Add(''); + lReport.Add(DIVIDER); + lReport.Add(''); - // obtain statistics and print frequency in categories for each item - for i := 1 to NoItems do - begin - OutputFrm.RichEdit.Lines.Add('Observed Category Frequencies'); - OutputFrm.RichEdit.Lines.Add('Item Group Level Category Number'); - Title := ' '; - for j := 0 to nocats-1 do Title := Title + format('%10d',[j+loscore]); - OutputFrm.RichEdit.Lines.Add(Title); - Zc := 0.0; - dftot := 0.0; - BigDnum := 0.0; - BigDden := 0.0; - M2 := 0.0; - SumE := 0.0; // second term of M2 numerator - SumV := 0.0; // denominator of M2 - Term1 := 0.0; // first term of M2 numerator - for k := 0 to nolevels-1 do - begin - Mf[k] := 0.0; - Mb[k] := 0.0; - Sf[k] := 0.0; - Sb[k] := 0.0; - t[k] := 0.0; - Nb[k] := 0.0; - Nf[k] := 0.0; - df[k] := 0.0; - d[k] := 0.0; - Sd[k] := 0.0; - VarE := 0.0; - E := 0.0; - Ti := 0.0; - MY := 0.0; - Title := format('%3d Ref. %3d',[i,k+1]); - for j := 0 to nocats-1 do - begin - Title := Title + format('%10d',[RData[i-1,j,k]]); - X := RData[i-1,j,k] * (j+loscore); - Mb[k] := Mb[k] + X; - Sb[k] := Sb[k] + (X * X); - Nb[k] := Nb[k] + RData[i-1,j,k]; - end; - OutputFrm.RichEdit.Lines.Add(Title); - Title := format('%3d Focal %3d',[i,k+1]); - for j := 0 to nocats-1 do - begin - Title := Title + format('%10d',[FData[i-1,j,k]]); - X := FData[i-1,j,k] * (j + loscore); - Mf[k] := Mf[k] + X; - Sf[k] := Sf[k] + (X * X); - Nf[k] := Nf[k] + FData[i-1,j,k]; - end; - OutputFrm.RichEdit.Lines.Add(Title); - Title := format('%3d Total %3d',[i,k+1]); - for j := 0 to nocats-1 do - Title := Title + format('%10d',[TotData[i-1,j,k]]); - OutputFrm.RichEdit.Lines.Add(Title); - OutputFrm.RichEdit.Lines.Add(''); - for j := 0 to nocats-1 do - begin - Term1 := Term1 + FData[i-1,j,k] * (j+loscore); - X := TotData[i-1,j,k] * (j+loscore); - E := E + X; - Ti := Ti + TotData[i-1,j,k]; - MY := MY + TotData[i-1,j,k] * (j + loscore); - VarE := VarE + TotData[i-1,j,k] * (j + loscore)*(j + loscore); - end; - E := E / Ti; - E := Nf[k] * E; - SumE := SumE + E; // second term of num. of m2 - VarE := (Ti * VarE) - (MY * MY); - VarE := ((Nf[k] * Nb[k]) / (Ti * Ti * (Ti - 1.0))) * VarE; - SumV := SumV + VarE; // den. of M2 - if (Nf[k] + Nb[k]) < 5 then continue; - Sf[k] := Sf[k] - (Mf[k] * Mf[k] / Nf[k]); - Sf[k] := Sf[k] / (Nf[k] - 1.0); - Sb[k] := Sb[k] - (Mb[k] * Mb[k] / Nb[k]); - Sb[k] := Sb[k] / (Nb[k] - 1.0); - Mf[k] := Mf[k] / Nf[k]; - Mb[k] := Mb[k] / Nb[k]; - t[k] := Mf[k] - Mb[k]; - df[k] := Nb[k] + Nf[k] - 2.0; - Vart := ((Sf[k] * Nf[k]) + (Sb[k] * Nb[k])) / df[k]; - Vart := sqrt(Vart * ((1.0 / Nf[k]) + (1.0 / Nb[k]))); - t[k] := t[k] / Vart; - Zc := Zc + t[k]; - dftot := dftot + (df[k] / (df[k] - 2.0)); - BigJ := 1.0 - (3.0 / (4.0 * df[k] - 1.0)); - d[k] := BigJ * sqrt((Nb[k] * Nf[k]) / (Nb[k] * Nf[k])); - d[k] := d[k] * t[k]; - Sd[k] := (BigJ * BigJ) * (df[k] / (df[k] - 2.0)); - Sd[k] := Sd[k] * (Nb[k] + Nf[k]) / (Nb[k] * Nf[k]); - Sd[k] := Sd[k] + (d[k] * d[k]) * ((BigJ * BigJ * df[k])/(df[k]-2.0) - 1.0); - BigDnum := BigDnum + d[k] / Sd[k]; - BigDden := BigDden + 1.0 / Sd[k]; - end; // next level k - M2 := (Term1 - SumE) * (Term1 - SumE) / SumV; - Title := 't-test values for Reference and Focus Means for each level'; - OutputFrm.RichEdit.Lines.Add(Title); - for k := 0 to nolevels-1 do - begin - Title := format('Mean Reference = %10.3f SD = %10.3f N = %5.0f',[Mb[k],sqrt(Sb[k]),Nb[k]]); - OutputFrm.RichEdit.Lines.Add(Title); - Title := format('Mean Focal = %10.3f SD = %10.3f N = %5.0f',[Mf[k],sqrt(Sf[k]),Nf[k]]); - OutputFrm.RichEdit.Lines.Add(Title); - Title := format('Level %3d t = %8.3f with deg. freedom = %5.0f',[k+1,t[k],df[k]]); - OutputFrm.RichEdit.Lines.Add(Title); - end; - Zc := Zc / dftot; // HW1 statistic - prob := 1.0 - probz(Zc); - Title := format('Composite z statistic = %6.3f. Prob. > |z| = %6.3f',[Zc, prob]); - OutputFrm.RichEdit.Lines.Add(Title); - BigD := BigDnum / BigDden; - BigDS := 1.0 / sqrt(BigDden); - Zd := BigD / BigDS; // HW3 statistic - prob := 1.0 - probz(Zd); - Title := format('Weighted Composite z statistic = %6.3f. Prob. > |z| = %6.3f',[Zd, prob]); - OutputFrm.RichEdit.Lines.Add(Title); - prob := 1.0 - chisquaredprob(M2,1); - Title := format('Generalized Mantel-Haenszel = %10.3f with D.F. = 1 and Prob. > Chi-Sqr. = %6.3f',[M2, prob]); - OutputFrm.RichEdit.Lines.Add(Title); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear; - if GraphChk.Checked then - begin - GraphFrm.nosets := 2; - GraphFrm.nbars := nolevels; - GraphFrm.Heading := 'Level Means'; - GraphFrm.XTitle := 'Level'; - GraphFrm.YTitle := 'Mean'; - SetLength(GraphFrm.Ypoints,2,nolevels+1); - SetLength(GraphFrm.Xpoints,1,nolevels+1); - for k := 0 to nolevels-1 do - begin - GraphFrm.Ypoints[0,k] := Mb[k]; - GraphFrm.Xpoints[0,k] := k+1; - GraphFrm.Ypoints[1,k] := Mf[k]; - end; - GraphFrm.barwideprop := 0.5; - GraphFrm.AutoScaled := true; - GraphFrm.GraphType := 2; // 3d Vertical Bar Chart - GraphFrm.ShowLeftWall := true; - GraphFrm.ShowRightWall := true; - GraphFrm.ShowBottomWall := true; - GraphFrm.ShowBackWall := true; - GraphFrm.BackColor := clYellow; - GraphFrm.WallColor := clBlack; - GraphFrm.ShowModal; - end; - end; // next item + // obtain statistics and print frequency in categories for each item + for i := 1 to NoItems do + begin + lReport.Add('ITEM ' + IntToStr(i)); + lReport.Add(''); + lReport.Add('Observed Category Frequencies'); + lReport.Add('Item Group Level Category Number'); + Title := ' '; + for j := 0 to nocats-1 do + Title := Title + Format('%10d', [j+loscore]); + lReport.Add(Title); + lReport.Add('---- ----- ----- ' + DupeString('-', 10*NoCats)); //---------------'); - // clean up the heap - GraphFrm.Xpoints := nil; - GraphFrm.Ypoints := nil; - FData := nil; - RData := nil; - TotData := nil; - t := nil; - Mf := nil; - Mb := nil; - Sf := nil; - Sb := nil; - Nb := nil; - Nf := nil; - df := nil; - d := nil; - Sd:= nil; + Zc := 0.0; + dftot := 0.0; + BigDnum := 0.0; + BigDden := 0.0; + M2 := 0.0; + SumE := 0.0; // second term of M2 numerator + SumV := 0.0; // denominator of M2 + Term1 := 0.0; // first term of M2 numerator + for k := 0 to nolevels-1 do + begin + Mf[k] := 0.0; + Mb[k] := 0.0; + Sf[k] := 0.0; + Sb[k] := 0.0; + t[k] := 0.0; + Nb[k] := 0.0; + Nf[k] := 0.0; + df[k] := 0.0; + d[k] := 0.0; + Sd[k] := 0.0; + VarE := 0.0; + E := 0.0; + Ti := 0.0; + MY := 0.0; + Title := Format('%3d Ref. %3d ', [i, k+1]); + for j := 0 to nocats-1 do + begin + Title := Title + Format('%10d', [RData[i-1,j,k]]); + X := RData[i-1,j,k] * (j+loscore); + Mb[k] := Mb[k] + X; + Sb[k] := Sb[k] + (X * X); + Nb[k] := Nb[k] + RData[i-1,j,k]; + end; + lReport.Add(Title); + + Title := Format('%3d Focal %3d ', [i, k+1]); + for j := 0 to nocats-1 do + begin + Title := Title + Format('%10d', [FData[i-1,j,k]]); + X := FData[i-1,j,k] * (j + loscore); + Mf[k] := Mf[k] + X; + Sf[k] := Sf[k] + (X * X); + Nf[k] := Nf[k] + FData[i-1,j,k]; + end; + lReport.Add(Title); + + Title := Format('%3d Total %3d ', [i, k+1]); + for j := 0 to nocats-1 do + Title := Title + Format('%10d', [TotData[i-1,j,k]]); + lReport.Add(Title); + lReport.Add(''); + + for j := 0 to nocats-1 do + begin + Term1 := Term1 + FData[i-1,j,k] * (j+loscore); + X := TotData[i-1,j,k] * (j+loscore); + E := E + X; + Ti := Ti + TotData[i-1,j,k]; + MY := MY + TotData[i-1,j,k] * (j + loscore); + VarE := VarE + TotData[i-1,j,k] * (j + loscore)*(j + loscore); + end; + + if Ti = 0 then // wp: added to avoid crash when Ti is 0. Not clear why this happens in my test... + begin + lReport.Add('Ti = zero --> skip to avoid division by zero'); + Continue; + end; + + E := E / Ti; + E := Nf[k] * E; + SumE := SumE + E; // second term of num. of m2 + VarE := (Ti * VarE) - (MY * MY); + VarE := ((Nf[k] * Nb[k]) / (Ti * Ti * (Ti - 1.0))) * VarE; + SumV := SumV + VarE; // den. of M2 + if (Nf[k] + Nb[k]) < 5 then continue; + Sf[k] := Sf[k] - (Mf[k] * Mf[k] / Nf[k]); + Sf[k] := Sf[k] / (Nf[k] - 1.0); + Sb[k] := Sb[k] - (Mb[k] * Mb[k] / Nb[k]); + Sb[k] := Sb[k] / (Nb[k] - 1.0); + Mf[k] := Mf[k] / Nf[k]; + Mb[k] := Mb[k] / Nb[k]; + t[k] := Mf[k] - Mb[k]; + df[k] := Nb[k] + Nf[k] - 2.0; + Vart := ((Sf[k] * Nf[k]) + (Sb[k] * Nb[k])) / df[k]; + Vart := sqrt(Vart * ((1.0 / Nf[k]) + (1.0 / Nb[k]))); + t[k] := t[k] / Vart; + Zc := Zc + t[k]; + dftot := dftot + (df[k] / (df[k] - 2.0)); + BigJ := 1.0 - (3.0 / (4.0 * df[k] - 1.0)); + d[k] := BigJ * sqrt((Nb[k] * Nf[k]) / (Nb[k] * Nf[k])); + d[k] := d[k] * t[k]; + Sd[k] := (BigJ * BigJ) * (df[k] / (df[k] - 2.0)); + Sd[k] := Sd[k] * (Nb[k] + Nf[k]) / (Nb[k] * Nf[k]); + Sd[k] := Sd[k] + (d[k] * d[k]) * ((BigJ * BigJ * df[k])/(df[k]-2.0) - 1.0); + BigDnum := BigDnum + d[k] / Sd[k]; + BigDden := BigDden + 1.0 / Sd[k]; + end; // next level k + M2 := (Term1 - SumE) * (Term1 - SumE) / SumV; + + lReport.Add(''); + lReport.Add('t-test values for Reference and Focus Means for each level'); + lReport.Add(''); + for k := 0 to nolevels-1 do + begin + lReport.Add('Level %d', [k+1]); + lReport.Add(' Mean Reference: %10.3f SD: %10.3f N: %5.0f', [Mb[k], sqrt(Sb[k]), Nb[k]]); + lReport.Add(' Mean Focal: %10.3f SD: %10.3f N: %5.0f', [Mf[k], sqrt(Sf[k]), Nf[k]]); + lReport.Add(' t: %10.3f with %.f degrees of freedom', [t[k], df[k]]); + lReport.Add(''); + end; + + Zc := Zc / dftot; // HW1 statistic + prob := 1.0 - probz(Zc); + lReport.Add( 'Composite z statistic: %10.3f Probability > |z|: %6.3f', [Zc, prob]); + + BigD := BigDnum / BigDden; + BigDS := 1.0 / sqrt(BigDden); + Zd := BigD / BigDS; // HW3 statistic + prob := 1.0 - probz(Zd); + lReport.Add( 'Weighted Composite z statistic: %10.3f Probability > |z|: %6.3f', [Zd, prob]); + + prob := 1.0 - chisquaredprob(M2, 1); + lReport.Add( 'Generalized Mantel-Haenszel: %10.3f with D.F. = 1 and Prob. > Chi-Sqr. %.3f', [M2, prob]); + + lReport.Add(''); + lReport.Add(DIVIDER); + lReport.Add(''); + + if GraphChk.Checked then + begin + GraphFrm.nosets := 2; + GraphFrm.nbars := nolevels; + GraphFrm.Heading := 'Level Means'; + GraphFrm.XTitle := 'Level'; + GraphFrm.YTitle := 'Mean'; + SetLength(GraphFrm.Ypoints, 2, nolevels+1); + SetLength(GraphFrm.Xpoints, 1, nolevels+1); + for k := 0 to nolevels-1 do + begin + GraphFrm.Ypoints[0,k] := Mb[k]; + GraphFrm.Xpoints[0,k] := k+1; + GraphFrm.Ypoints[1,k] := Mf[k]; + end; + GraphFrm.barwideprop := 0.5; + GraphFrm.AutoScaled := true; + GraphFrm.GraphType := 2; // 3d Vertical Bar Chart + GraphFrm.ShowLeftWall := true; + GraphFrm.ShowRightWall := true; + GraphFrm.ShowBottomWall := true; + GraphFrm.ShowBackWall := true; + GraphFrm.BackColor := GRAPH_BACK_COLOR; + GraphFrm.WallColor := GRAPH_WALL_COLOR; + GraphFrm.FloorColor := GRAPH_FLOOR_COLOR; + GraphFrm.ShowModal; + end; + end; // next item + + DisplayReport(lReport); + + finally + lReport.Free; + GraphFrm.Xpoints := nil; + GraphFrm.Ypoints := nil; + FData := nil; + RData := nil; + TotData := nil; + t := nil; + Mf := nil; + Mb := nil; + Sf := nil; + Sb := nil; + Nb := nil; + Nf := nil; + df := nil; + d := nil; + Sd:= nil; + end; +end; + +procedure TPolyDIFFrm.UpdateBtnStates; +var + lSelected: Boolean; +begin + lSelected := AnySelected(VarList); + ItemInBtn.Enabled := lSelected; + GrpInBtn.Enabled := lSelected and (GroupVarEdit.Text = ''); + + ItemOutBtn.Enabled := AnySelected(ItemsList); + GrpOutBtn.Enabled := GroupVarEdit.Text <> ''; + + AllBtn.Enabled := VarList.Items.Count > 0; +end; + +function TPolyDIFFrm.ValidNumEdit(AEdit: TEdit; AName: String; + out AValue: Integer): Boolean; +begin + Result := false; + if AEdit.Text = '' then + begin + AEdit.SetFocus; + MessageDlg(AName + ' not specified.', mtError, [mbOK], 0); + exit; + end; + if not TryStrToInt(AEdit.Text, AValue) then + begin + AEdit.SetFocus; + MessageDlg(AName + ' is not a valid number.', mtError, [mbOk], 0); + exit; + end; + Result := true; +end; + +procedure TPolyDIFFrm.VarListSelectionChange(Sender: TObject; User: boolean); +begin + UpdateBtnStates; end;