LazStats: More refactoring in CompareDistUnit.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7722 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-09-30 10:19:19 +00:00
parent c50e122263
commit 0e50c16f6b
5 changed files with 679 additions and 228 deletions

View File

@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<CONFIG> <CONFIG>
<ProjectOptions> <ProjectOptions>
<Version Value="11"/> <Version Value="12"/>
<PathDelim Value="\"/> <PathDelim Value="\"/>
<General> <General>
<Flags>
<CompatibilityMode Value="True"/>
</Flags>
<SessionStorage Value="InProjectDir"/> <SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Scaled Value="True"/> <Scaled Value="True"/>
<UseXPManifest Value="True"/> <UseXPManifest Value="True"/>
<XPManifest> <XPManifest>
@ -93,7 +95,6 @@
</PublishOptions> </PublishOptions>
<RunParams> <RunParams>
<FormatVersion Value="2"/> <FormatVersion Value="2"/>
<Modes Count="0"/>
</RunParams> </RunParams>
<RequiredPackages Count="7"> <RequiredPackages Count="7">
<Item1> <Item1>

View File

@ -1,19 +1,19 @@
inherited CompareDistFrm: TCompareDistFrm inherited CompareDistFrm: TCompareDistFrm
Left = 671 Left = 459
Height = 413 Height = 504
Top = 327 Top = 178
Width = 924 Width = 924
HelpType = htKeyword HelpType = htKeyword
HelpKeyword = 'html/ComparisonsWithTheoreticalDistri.htm' HelpKeyword = 'html/ComparisonsWithTheoreticalDistri.htm'
Caption = 'Compare Cumulative Distributions' Caption = 'Compare Cumulative Distributions'
ClientHeight = 413 ClientHeight = 504
ClientWidth = 924 ClientWidth = 924
OnActivate = FormActivate OnActivate = FormActivate
OnCreate = FormCreate OnCreate = FormCreate
Position = poMainFormCenter Position = poMainFormCenter
object ParamsPanel: TPanel[0] object ParamsPanel: TPanel[0]
Left = 8 Left = 8
Height = 397 Height = 488
Top = 8 Top = 8
Width = 288 Width = 288
Align = alLeft Align = alLeft
@ -22,7 +22,7 @@ inherited CompareDistFrm: TCompareDistFrm
BorderSpacing.Right = 4 BorderSpacing.Right = 4
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
BevelOuter = bvNone BevelOuter = bvNone
ClientHeight = 397 ClientHeight = 488
ClientWidth = 288 ClientWidth = 288
TabOrder = 0 TabOrder = 0
object ResetBtn: TButton object ResetBtn: TButton
@ -31,7 +31,7 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 87 Left = 87
Height = 25 Height = 25
Top = 372 Top = 463
Width = 54 Width = 54
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
AutoSize = True AutoSize = True
@ -47,7 +47,7 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 149 Left = 149
Height = 25 Height = 25
Top = 372 Top = 463
Width = 76 Width = 76
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
AutoSize = True AutoSize = True
@ -65,7 +65,7 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 233 Left = 233
Height = 25 Height = 25
Top = 372 Top = 463
Width = 55 Width = 55
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
AutoSize = True AutoSize = True
@ -83,7 +83,7 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideBottom.Control = ResetBtn AnchorSideBottom.Control = ResetBtn
Left = 0 Left = 0
Height = 8 Height = 8
Top = 356 Top = 447
Width = 288 Width = 288
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
Shape = bsBottomLine Shape = bsBottomLine
@ -93,14 +93,14 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideBottom.Control = Bevel1 AnchorSideBottom.Control = Bevel1
Left = 0 Left = 0
Height = 83 Height = 83
Top = 273 Top = 364
Width = 302 Width = 298
Anchors = [akLeft, akBottom] Anchors = [akLeft, akBottom]
AutoSize = True AutoSize = True
BorderSpacing.Top = 8 BorderSpacing.Top = 8
Caption = 'Option:' Caption = 'Option:'
ClientHeight = 63 ClientHeight = 63
ClientWidth = 298 ClientWidth = 294
TabOrder = 3 TabOrder = 3
object BothChk: TCheckBox object BothChk: TCheckBox
AnchorSideLeft.Control = OptionsGroup AnchorSideLeft.Control = OptionsGroup
@ -108,15 +108,15 @@ inherited CompareDistFrm: TCompareDistFrm
Left = 16 Left = 16
Height = 19 Height = 19
Top = 6 Top = 6
Width = 270 Width = 266
BorderSpacing.Left = 16 BorderSpacing.Left = 16
BorderSpacing.Top = 6 BorderSpacing.Top = 6
BorderSpacing.Right = 12 BorderSpacing.Right = 12
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
Caption = 'Plot both Frequency and cumulative Frequency' Caption = 'Plot both frequency and cumulative frequency'
TabOrder = 0 TabOrder = 0
end end
object VertBarBtn: TSpeedButton object BarPlotBtn: TSpeedButton
AnchorSideLeft.Control = OptionsGroup AnchorSideLeft.Control = OptionsGroup
AnchorSideTop.Control = BothChk AnchorSideTop.Control = BothChk
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
@ -126,35 +126,25 @@ inherited CompareDistFrm: TCompareDistFrm
Width = 23 Width = 23
BorderSpacing.Left = 16 BorderSpacing.Left = 16
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
Down = True
GroupIndex = 1
Images = MainDataModule.ImageList Images = MainDataModule.ImageList
ImageIndex = 8 ImageIndex = 8
end end
object LinePlotBtn: TSpeedButton object LinePlotBtn: TSpeedButton
AnchorSideLeft.Control = VertBarBtn AnchorSideLeft.Control = BarPlotBtn
AnchorSideLeft.Side = asrBottom AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = VertBarBtn AnchorSideTop.Control = BarPlotBtn
AnchorSideTop.Side = asrCenter AnchorSideTop.Side = asrCenter
Left = 43 Left = 43
Height = 22 Height = 22
Top = 33 Top = 33
Width = 23 Width = 23
BorderSpacing.Left = 4 BorderSpacing.Left = 4
GroupIndex = 1
Images = MainDataModule.ImageList Images = MainDataModule.ImageList
ImageIndex = 10 ImageIndex = 10
end end
object ThreeDChk: TCheckBox
AnchorSideLeft.Control = LinePlotBtn
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = VertBarBtn
AnchorSideTop.Side = asrCenter
Left = 82
Height = 19
Top = 35
Width = 34
BorderSpacing.Left = 16
Caption = '3D'
TabOrder = 1
end
end end
object Label1: TLabel object Label1: TLabel
AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Control = ParamsPanel
@ -173,7 +163,7 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideRight.Control = Var1InBtn AnchorSideRight.Control = Var1InBtn
AnchorSideBottom.Control = OptionsGroup AnchorSideBottom.Control = OptionsGroup
Left = 0 Left = 0
Height = 248 Height = 339
Top = 17 Top = 17
Width = 99 Width = 99
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
@ -287,49 +277,155 @@ inherited CompareDistFrm: TCompareDistFrm
AnchorSideRight.Control = CompareGroup AnchorSideRight.Control = CompareGroup
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 105 Left = 105
Height = 60 Height = 191
Top = 165 Top = 165
Width = 183 Width = 183
PageIndex = 1 PageIndex = 0
AutoSize = True AutoSize = True
Anchors = [akTop, akLeft, akRight] Anchors = [akTop, akLeft, akRight]
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
TabOrder = 9 TabOrder = 9
object TheoreticalDistPage: TPage object TheoreticalDistPage: TPage
object DistGroup: TRadioGroup object DistGroup: TGroupBox
AnchorSideLeft.Control = TheoreticalDistPage AnchorSideLeft.Control = TheoreticalDistPage
AnchorSideTop.Control = TheoreticalDistPage AnchorSideTop.Control = TheoreticalDistPage
AnchorSideRight.Control = TheoreticalDistPage AnchorSideRight.Control = TheoreticalDistPage
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 0 Left = 0
Height = 139 Height = 191
Top = 16 Top = 0
Width = 183 Width = 183
Anchors = [akTop, akLeft, akRight] Anchors = [akTop, akLeft, akRight]
AutoFill = True
AutoSize = True AutoSize = True
BorderSpacing.Top = 16 Caption = 'Theoretical Distribution'
Caption = 'Theoretical Distributions:' ClientHeight = 171
ChildSizing.LeftRightSpacing = 18
ChildSizing.TopBottomSpacing = 8
ChildSizing.VerticalSpacing = 2
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 119
ClientWidth = 179 ClientWidth = 179
Items.Strings = (
'Normal Distribution'
't-Distribution'
'Chi-Sq Distribution'
'F Distribution'
'Poisson Distribution'
)
OnClick = DistGroupClick
TabOrder = 0 TabOrder = 0
object NormalDistChk: TRadioButton
AnchorSideLeft.Control = DistGroup
AnchorSideTop.Control = DistGroup
Left = 16
Height = 19
Top = 2
Width = 125
BorderSpacing.Left = 16
BorderSpacing.Top = 2
BorderSpacing.Right = 16
Caption = 'Normal Distribution'
OnChange = DistChange
TabOrder = 0
end
object tDistChk: TRadioButton
AnchorSideLeft.Control = NormalDistChk
AnchorSideTop.Control = NormalDistChk
AnchorSideTop.Side = asrBottom
Left = 16
Height = 19
Top = 23
Width = 89
BorderSpacing.Top = 2
Caption = 't Distribution'
OnChange = DistChange
TabOrder = 1
end
object ChiSqDistChk: TRadioButton
AnchorSideLeft.Control = NormalDistChk
AnchorSideTop.Control = tDistChk
AnchorSideTop.Side = asrBottom
Left = 16
Height = 19
Top = 44
Width = 121
BorderSpacing.Top = 2
BorderSpacing.Right = 12
Caption = 'Chi-Sq Distribution'
OnChange = DistChange
TabOrder = 2
end
object FDistChk: TRadioButton
AnchorSideLeft.Control = NormalDistChk
AnchorSideTop.Control = ChiSqDistChk
AnchorSideTop.Side = asrBottom
Left = 16
Height = 19
Top = 65
Width = 91
BorderSpacing.Top = 2
Caption = 'F Distribution'
OnChange = DistChange
TabOrder = 3
end
object PoissonDistChk: TRadioButton
AnchorSideLeft.Control = NormalDistChk
AnchorSideTop.Control = FDistChk
AnchorSideTop.Side = asrBottom
Left = 16
Height = 19
Top = 86
Width = 126
BorderSpacing.Top = 2
BorderSpacing.Right = 12
BorderSpacing.Bottom = 8
Caption = 'Poisson Distribution'
OnChange = DistChange
TabOrder = 4
end
object DF1Label: TLabel
AnchorSideTop.Control = DF1Edit
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = DF1Edit
Left = 48
Height = 15
Top = 117
Width = 29
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
Caption = 'D.F. 1'
ParentColor = False
end
object DF1Edit: TEdit
AnchorSideTop.Control = PoissonDistChk
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = DistGroup
AnchorSideRight.Side = asrBottom
Left = 85
Height = 23
Top = 113
Width = 82
Anchors = [akTop, akRight]
BorderSpacing.Right = 12
BorderSpacing.Bottom = 4
TabOrder = 5
Text = 'DF1Edit'
end
object DF2Edit: TEdit
AnchorSideLeft.Control = DF1Edit
AnchorSideTop.Control = DF1Edit
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = DF1Edit
AnchorSideRight.Side = asrBottom
Left = 85
Height = 23
Top = 140
Width = 82
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Bottom = 8
TabOrder = 6
Text = 'DF2Edit'
end
object DF2Label: TLabel
AnchorSideTop.Control = DF2Edit
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = DF2Edit
Left = 48
Height = 15
Top = 144
Width = 29
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
Caption = 'D.F. 2'
ParentColor = False
end
end end
end end
object VariablePage: TPage object VariablePage: TPage
@ -396,27 +492,30 @@ inherited CompareDistFrm: TCompareDistFrm
end end
object PageControl1: TPageControl[1] object PageControl1: TPageControl[1]
Left = 309 Left = 309
Height = 397 Height = 488
Top = 8 Top = 8
Width = 607 Width = 607
ActivePage = ReportPage ActivePage = CumFreqChartPage
Align = alClient Align = alClient
BorderSpacing.Left = 4 BorderSpacing.Left = 4
BorderSpacing.Top = 8 BorderSpacing.Top = 8
BorderSpacing.Right = 8 BorderSpacing.Right = 8
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
TabIndex = 0 TabIndex = 1
TabOrder = 1 TabOrder = 1
object ReportPage: TTabSheet object ReportPage: TTabSheet
Caption = 'Report' Caption = 'Report'
end end
object ChartPage: TTabSheet object CumFreqChartPage: TTabSheet
Caption = 'Chart' Caption = 'Cumulative frequency plot'
end
object FreqChartPage: TTabSheet
Caption = 'Frequency plot'
end end
end end
object ParamsSplitter: TSplitter[2] object ParamsSplitter: TSplitter[2]
Left = 300 Left = 300
Height = 413 Height = 504
Top = 0 Top = 0
Width = 5 Width = 5
ResizeStyle = rsPattern ResizeStyle = rsPattern

View File

@ -13,18 +13,30 @@ uses
BasicStatsFormUnit, ReportFrameUnit, ChartFrameUnit; BasicStatsFormUnit, ReportFrameUnit, ChartFrameUnit;
type type
TCompareTo = (ctTheoreticalDistrib, ctVariable);
TCompareDist = (cd_Normal, cd_t, cd_ChiSq, cd_F, cd_Poisson);
{ TCompareDistFrm } { TCompareDistFrm }
TCompareDistFrm = class(TBasicStatsForm) TCompareDistFrm = class(TBasicStatsForm)
Bevel1: TBevel; Bevel1: TBevel;
DF1Edit: TEdit;
DF2Edit: TEdit;
DistGroup: TGroupBox;
DF1Label: TLabel;
DF2Label: TLabel;
PageControl1: TPageControl; PageControl1: TPageControl;
ParamsSplitter: TSplitter; ParamsSplitter: TSplitter;
NormalDistChk: TRadioButton;
FreqChartPage: TTabSheet;
tDistChk: TRadioButton;
ChiSqDistChk: TRadioButton;
FDistChk: TRadioButton;
PoissonDistChk: TRadioButton;
ReportPage: TTabSheet; ReportPage: TTabSheet;
ChartPage: TTabSheet; CumFreqChartPage: TTabSheet;
ThreeDChk: TCheckBox;
Notebook: TNotebook; Notebook: TNotebook;
VertBarBtn: TSpeedButton; BarPlotBtn: TSpeedButton;
LinePlotBtn: TSpeedButton; LinePlotBtn: TSpeedButton;
TheoreticalDistPage: TPage; TheoreticalDistPage: TPage;
VariablePage: TPage; VariablePage: TPage;
@ -35,7 +47,6 @@ type
ComputeBtn: TButton; ComputeBtn: TButton;
CloseBtn: TButton; CloseBtn: TButton;
CompareGroup: TRadioGroup; CompareGroup: TRadioGroup;
DistGroup: TRadioGroup;
VarOneEdit: TEdit; VarOneEdit: TEdit;
VarTwoEdit: TEdit; VarTwoEdit: TEdit;
Label2: TLabel; Label2: TLabel;
@ -49,9 +60,9 @@ type
procedure CloseBtnClick(Sender: TObject); procedure CloseBtnClick(Sender: TObject);
procedure CompareGroupClick(Sender: TObject); procedure CompareGroupClick(Sender: TObject);
procedure ComputeBtnClick(Sender: TObject); procedure ComputeBtnClick(Sender: TObject);
procedure DistGroupClick(Sender: TObject);
procedure FormActivate(Sender: TObject); procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject); procedure FormCreate(Sender: TObject);
procedure DistChange(Sender: TObject);
procedure ResetBtnClick(Sender: TObject); procedure ResetBtnClick(Sender: TObject);
procedure Var1InBtnClick(Sender: TObject); procedure Var1InBtnClick(Sender: TObject);
procedure Var1OutBtnClick(Sender: TObject); procedure Var1OutBtnClick(Sender: TObject);
@ -62,11 +73,22 @@ type
private private
FReportFrame: TReportFrame; FReportFrame: TReportFrame;
FChartFrame: TChartFrame; FCumFreqChartFrame: TChartFrame;
FFreqChartFrame: TChartFrame;
FAutoSized: Boolean; FAutoSized: Boolean;
CompareTo: integer; CompareTo: TCompareTo;
DistType: integer; CompareDist: TCompareDist;
procedure CalcFreq(XValues, FreqValues, CumFreqValues: DblDyneVec;
AMin, AMax: Double; ANumIntervals, ANumCases: Integer; DF1: Integer = -1;
DF2: Integer = -1);
procedure CalcTheoreticalDist(XValues, FreqValues, CumFreqValues: DblDyneVec;
ANumIntervals, ANumCases: Integer; out AName: String);
procedure Plot(AChartFrame: TChartFrame; Y1Values, Y2Values: DblDyneVec;
AName1, AName2: String);
procedure UpdateBtnStates; procedure UpdateBtnStates;
procedure UpdateDF1;
function Validate(ANumCases: Integer;
out AMsg: String; out AControl: TWinControl): Boolean;
public public
procedure Reset; override; procedure Reset; override;
@ -83,11 +105,125 @@ implementation
uses uses
Math, Math,
TACustomSeries, TASeries,
Utils, MathUnit; Utils, MathUnit;
{ TCompareDistFrm } { TCompareDistFrm }
procedure TCompareDistFrm.CalcFreq(XValues, FreqValues, CumFreqValues: DblDyneVec;
AMin, AMax: Double; ANumIntervals, ANumCases: Integer; DF1: Integer = -1;
DF2: Integer = -1);
var
dx: Double;
i: Integer;
procedure Calc(AProb1, AProb2: Double);
begin
FreqValues[i] := abs(AProb2 - AProb1) * ANumCases;
end;
begin
dx := (AMax - AMin) / ANumIntervals;
for i := 0 to ANumIntervals do
XValues[i] := AMin + i * dx;
for i := 0 to ANumIntervals - 1 do
case CompareDist of
cd_Normal:
Calc(NormalDist(XValues[i]), NormalDist(XValues[i+1]));
cd_t:
Calc(0.5 * ProbT(XValues[i], DF1), 0.5 * ProbT(XValues[i+1], DF1));
cd_ChiSq:
Calc(ChiSquaredProb(XValues[i], DF1), ChiSquaredProb(XValues[i+1], DF1));
cd_F:
Calc(ProbF(XValues[i], DF1, DF2), ProbF(XValues[i+1], DF1, DF2));
cd_Poisson:
Calc(PoissonCDF(round(XValues[i]), DF1), PoissonCDF(round(XValues[i+1]), DF1));
// Calc(PoissonPDF(round(XValues[i]), DF1), 0);
end;
CumFreqValues[0] := FreqValues[0];
for i := 1 to ANumIntervals - 1 do
CumFreqValues[i] := CumFreqValues[i-1] + FreqValues[i];
end;
procedure TCompareDistFrm.CalcTheoreticalDist(XValues, FreqValues, CumFreqValues: DblDyneVec;
ANumIntervals, ANumCases: Integer; out AName: String);
var
min, max: Double;
DF1: Integer = -1;
DF2: Integer = -1;
a: Double;
begin
if TryStrToFloat(DF1Edit.Text, a) then
DF1 := round(a);
if TryStrToFloat(DF2Edit.Text, a) then
DF2 := round(a);
case CompareDist of
cd_Normal:
begin
min := -3.0;
max := 3.0;
AName := 'Normal dist';
end;
cd_t:
begin
min := -3.0;
max := 3.0;
AName := 't dist';
end;
cd_ChiSq:
begin
min := 0.0;
max := 20.0;
AName := 'Chi-sq dist';
end;
cd_F:
begin
min := 0.0;
max := 2.0;
AName := 'F dist';
end;
cd_Poisson:
; // will be handled separately
end;
CalcFreq(XValues, FreqValues, CumFreqValues, min, max, ANumIntervals, ANumCases, DF1, DF2);
end;
(*
if NormalDistChk.Checked then // normal distribution curve
begin
name2 := 'Normal';
min2 := -3.0;
max2 := 3.0;
range2 := max2 - min2;
incrsize2 := range2 / noints;
Xvalue2[0] := min2;
Xvalue2[noints] := max2;
for i := 1 to noInts do
begin
Xvalue2[i-1] := min2 + (i-1) * incrSize2;
Xvalue2[i] := min2 + (i) * incrSize2;
prob1 := probz(abs(Xvalue2[i-1]));
prob2 := probz(abs(Xvalue2[i]));
if prob1 > prob2 then
Var2Freq[i-1] := round((prob1 - prob2) * nCases)
else
Var2Freq[i-1] := round((prob2 - prob1) * nCases)
end;
Cumfreq2[0] := Var2Freq[0];
for i := 1 to noints do
Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i];
end
end;
*)
procedure TCompareDistFrm.CloseBtnClick(Sender: TObject); procedure TCompareDistFrm.CloseBtnClick(Sender: TObject);
begin begin
Close; Close;
@ -96,58 +232,52 @@ end;
procedure TCompareDistFrm.CompareGroupClick(Sender: TObject); procedure TCompareDistFrm.CompareGroupClick(Sender: TObject);
begin begin
compareTo := CompareGroup.ItemIndex; CompareTo := TCompareTo(CompareGroup.ItemIndex);
Notebook.PageIndex := CompareGroup.ItemIndex; Notebook.PageIndex := CompareGroup.ItemIndex;
{
Label3.Enabled := (compareTo = 1);
VarTwoEdit.Enabled := (compareTo = 1);
Var2InBtn.Enabled := (compareTo = 1);
Var2OutBtn.Enabled := (compareTo = 1);
}
end; end;
procedure TCompareDistFrm.ComputeBtnClick(Sender: TObject); procedure TCompareDistFrm.ComputeBtnClick(Sender: TObject);
var var
Var1Freq : IntDyneVec = nil; var1Freq: DblDyneVec = nil; // could be IntDyneVec, but simpler charting this way
Var2Freq : IntDyneVec = nil; var2Freq: DblDyneVec = nil;
XValue1 : DblDyneVec = nil; xValue1: DblDyneVec = nil;
XValue2 : DblDyneVec = nil; xValue2: DblDyneVec = nil;
Cumfreq1 : DblDyneVec = nil; cumfreq1: DblDyneVec = nil;
Cumfreq2 : DblDyneVec = nil; cumfreq2: DblDyneVec = nil;
i, j, k, col1, col2, Ncases, noints : integer; i, j, k, col1, col2, nCases, noInts: integer;
min1, max1, min2, max2, range1, range2, value : double; min1, max1, min2, max2, range1, range2, value: double;
incrsize1, incrsize2, prob1,prob2, {%H-}KS, mean, DegFree : double; incrSize1, incrSize2, {%H-}KS: double;
cellval, name1, name2 : string; cellVal, name1, name2: string;
df1, df2 : integer;
xtitle : string;
msg: String; msg: String;
C: TWinControl;
lReport: TStrings; lReport: TStrings;
begin begin
SetLength(Var1Freq, NoCases + 1); SetLength(var1Freq, NoCases + 1);
SetLength(Var2Freq, NoCases + 1); SetLength(var2Freq, NoCases + 1);
SetLength(XValue1, NoCases + 1); SetLength(xValue1, NoCases + 1);
SetLength(XValue2, NoCases + 1); SetLength(xValue2, NoCases + 1);
SetLength(Cumfreq1, NoCases + 1); SetLength(cumfreq1, NoCases + 1);
SetLength(Cumfreq2, NoCases + 1); SetLength(cumfreq2, NoCases + 1);
// Get columns of the variables // Get columns of the variables
col1 := 0; col1 := 0;
col2 := 0;
for i := 1 to NoVariables do for i := 1 to NoVariables do
begin if VarOneEdit.Text = OS3MainFrm.DataGrid.Cells[i, 0] then col1 := i;
if VarOneEdit.Text = OS3MainFrm.DataGrid.Cells[i,0] then col1 := i;
if compareto = 1 then
begin
if VarTwoEdit.Text = OS3MainFrm.DataGrid.Cells[i,0] then col2 := i;
end;
end;
col2 := 0;
if CompareTo = ctVariable then
for i := 1 to NoVariables do
if VarTwoEdit.Text = OS3MainFrm.DataGrid.Cells[i, 0] then col2 := i;
// Check existence of required variables
msg := ''; msg := '';
case CompareTo of case CompareTo of
0: if col1 = 0 then ctTheoreticalDistrib:
if col1 = 0 then
msg := 'Variable not specified.'; msg := 'Variable not specified.';
1: if col1 = 0 then ctVariable:
if col1 = 0 then
msg := 'Variable One is not specified.' msg := 'Variable One is not specified.'
else if col2 = 0 then else if col2 = 0 then
msg := 'Variable Two is not specified.'; msg := 'Variable Two is not specified.';
@ -158,88 +288,110 @@ begin
exit; exit;
end; end;
// get min and max values for variable in col1 // Get min and max values for variable in col1, as well as true number of cases
min1 := 1.0e308; min1 := Infinity;
max1 := -1.0e308; max1 := -Infinity;
Ncases := 0; nCases := 0;
for j := 1 to NoCases do for j := 1 to NoCases do
begin begin
if not ValidValue(j,col1) then continue; if not ValidValue(j, col1) then continue;
value := StrToFloat(OS3MainFrm.DataGrid.Cells[col1,j]); value := StrToFloat(OS3MainFrm.DataGrid.Cells[col1, j]);
if value > max1 then max1 := value; if value > max1 then max1 := value;
if value < min1 then min1 := value; if value < min1 then min1 := value;
inc(Ncases); inc(nCases);
end; end;
noints := NoCases - 1; // number of intervals // Validate
if noints > 20 then noints := 20; if not Validate(nCases, msg, C) then begin
C.SetFocus;
ErrorMsg(msg);
end;
// Get number of intervals
noInts := NoCases - 1; // wp: why NoCases here, and not nCases?
if noInts > 20 then noints := 20;
range1 := max1 - min1 + 1.0; range1 := max1 - min1 + 1.0;
incrsize1 := range1 / noints; incrSize1 := range1 / noInts;
name1 := VarOneEdit.Text; name1 := VarOneEdit.Text;
if compareTo = 1 then // Repeat for variable 2 (if Compare To is selected as "Another variable")
if CompareTo = ctVariable then
begin begin
min2 := 1.0e32; min2 := Infinity;
max2 := -1.0e32; max2 := -Infinity;
for j := 1 to NoCases do for j := 1 to NoCases do
begin begin
if Not ValidValue(j,col2) then continue; if not ValidValue(j, col2) then continue;
value := StrToFloat(OS3MainFrm.DataGrid.Cells[col2,j]); value := StrToFloat(OS3MainFrm.DataGrid.Cells[col2, j]);
if value > max2 then max2 := value; if value > max2 then max2 := value;
if value < min2 then min2 := value; if value < min2 then min2 := value;
end; end;
range2 := max2 - min2 + 1.0; range2 := max2 - min2 + 1.0;
incrsize2 := range2 / noints; incrSize2 := range2 / noInts;
name2 := VarTwoEdit.Text; name2 := VarTwoEdit.Text;
end; end;
//Now, get frequency of cases in each interval // Get frequency of cases in each interval
for j := 1 to noints+1 do for j := 1 to noints+1 do
Var1Freq[j-1] := 0; var1Freq[j-1] := 0;
for j := 1 to NoCases do for j := 1 to NoCases do
begin begin
if Not ValidValue(j,col1) then continue; if not ValidValue(j, col1) then continue;
value := StrToFloat(OS3MainFrm.DataGrid.Cells[col1,j]); value := StrToFloat(OS3MainFrm.DataGrid.Cells[col1, j]);
for k := 1 to noints do for k := 1 to noInts do
begin begin
if (value >= min1 + ((k-1) * incrsize1)) and if (value >= min1 + (k-1) * incrSize1) and (value < min1 + k * incrSize1) then
(value < min1 + (k * incrsize1)) var1Freq[k-1] := var1Freq[k-1] + 1;
then
Var1Freq[k-1] := Var1Freq[k-1] + 1;
end; end;
end; end;
Cumfreq1[0] := Var1Freq[0];
for j := 1 to noints+1 do
XValue1[j-1] := min1 + (j-1) * incrsize1;
for j := 1 to noints do
Cumfreq1[j] := Cumfreq1[j-1] + Var1Freq[j];
if compareTo = 1 then // do same for second variable
begin
for j := 1 to noints+1 do
Var2Freq[j-1] := 0;
for j := 1 to NoCases do
begin
if Not ValidValue(j,col2) then continue;
value := StrToFloat(OS3MainFrm.DataGrid.Cells[col2,j]);
for k := 1 to noints do
begin
if (value >= min2 + ((k-1) * incrsize2)) and
(value < min2 + (k * incrsize2))
then
Var2Freq[k-1] := Var2Freq[k-1] + 1;
end;
end;
Cumfreq2[0] := Var2Freq[0];
for j := 1 to noints+1 do
XValue2[j-1] := min2 + (j-1) * incrsize2;
for j := 1 to noints do
Cumfreq2[j] := Cumfreq2[j-1] + Var2Freq[j];
end;
// Get theoretical distribution frequencies for selected dist. cumFreq1[0] := var1Freq[0];
if compareTo = 0 then for j := 1 to noInts+1 do
xValue1[j-1] := min1 + (j-1) * incrSize1;
for j := 1 to noInts do
cumFreq1[j] := cumFreq1[j-1] + var1Freq[j];
// Repeat for 2nd variable, if required
if CompareTo = ctVariable then
begin begin
if DistGroup.ItemIndex = 0 then // normal curve for j := 1 to noInts+1 do
var2Freq[j-1] := 0;
for j := 1 to NoCases do
begin
if not ValidValue(j, col2) then continue;
value := StrToFloat(OS3MainFrm.DataGrid.Cells[col2, j]);
for k := 1 to noInts do
begin
if (value >= min2 + (k-1) * incrsize2) and (value < min2 + k * incrsize2) then
var2Freq[k-1] := var2Freq[k-1] + 1;
end;
end;
cumfreq2[0] := var2Freq[0];
for j := 1 to noInts+1 do
xValue2[j-1] := min2 + (j-1) * incrSize2;
for j := 1 to noInts do
cumFreq2[j] := cumFreq2[j-1] + var2Freq[j];
end;
// Get theoretical distribution frequencies for selected distribution, if required.
if CompareDist = cd_Poisson then
begin
CalcFreq(xValue2, var2Freq, cumFreq2, min1, min2, noInts, nCases, StrToInt(DF1Edit.Text));
name2 := 'Poisson';
end
else
CalcTheoreticalDist(xValue2, var2Freq, cumFreq2, noInts, nCases, name2);
(*
if CompareTo = ctTheoreticalDistrib then
begin
if NormalDistChk.Checked then // normal distribution curve
begin begin
name2 := 'Normal'; name2 := 'Normal';
min2 := -3.0; min2 := -3.0;
@ -248,76 +400,76 @@ begin
incrsize2 := range2 / noints; incrsize2 := range2 / noints;
Xvalue2[0] := min2; Xvalue2[0] := min2;
Xvalue2[noints] := max2; Xvalue2[noints] := max2;
for i := 1 to noints do for i := 1 to noInts do
begin begin
Xvalue2[i-1] := min2 + (i-1) * incrsize2; Xvalue2[i-1] := min2 + (i-1) * incrSize2;
Xvalue2[i] := min2 + (i) * incrsize2; Xvalue2[i] := min2 + (i) * incrSize2;
prob1 := probz(abs(Xvalue2[i-1])); prob1 := probz(abs(Xvalue2[i-1]));
prob2 := probz(abs(Xvalue2[i])); prob2 := probz(abs(Xvalue2[i]));
if prob1 > prob2 then if prob1 > prob2 then
Var2Freq[i-1] := round((prob1-prob2) * Ncases) Var2Freq[i-1] := round((prob1 - prob2) * nCases)
else else
Var2Freq[i-1] := round((prob2-prob1) * Ncases) Var2Freq[i-1] := round((prob2 - prob1) * nCases)
end; end;
Cumfreq2[0] := Var2Freq[0]; Cumfreq2[0] := Var2Freq[0];
for i := 1 to noints do for i := 1 to noints do
Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i]; Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i];
end end
else else
if DistGroup.ItemIndex = 1 then // t-distribution if tDistChk.Checked then // t-distribution
begin begin
name2 := 't-Dist.'; name2 := 't-Dist.';
min2 := -3.0; min2 := -3.0;
max2 := 3.0; max2 := 3.0;
df1 := Ncases - 1; df1 := nCases - 1;
range2 := max2 - min2; range2 := max2 - min2;
incrsize2 := range2 / noints; incrsize2 := range2 / noints;
Xvalue2[0] := min2; Xvalue2[0] := min2;
Xvalue2[noints] := max2; Xvalue2[noints] := max2;
for i := 1 to noints do for i := 1 to noInts do
begin begin
Xvalue2[i-1] := min2 + (i-1) * incrsize2; Xvalue2[i-1] := min2 + (i-1) * incrSize2;
Xvalue2[i] := min2 + (i) * incrsize2; Xvalue2[i] := min2 + (i) * incrSize2;
prob1 := 0.5 * probt(Xvalue2[i-1],df1); prob1 := 0.5 * probt(Xvalue2[i-1],df1);
prob2 := 0.5 * probt(Xvalue2[i],df1); prob2 := 0.5 * probt(Xvalue2[i],df1);
if prob1 > prob2 then if prob1 > prob2 then
Var2Freq[i-1] := round((prob1-prob2) * Ncases) Var2Freq[i-1] := round((prob1-prob2) * nCases)
else else
Var2Freq[i-1] := round((prob2-prob1) * Ncases) Var2Freq[i-1] := round((prob2-prob1) * nCases)
end; end;
Cumfreq2[0] := Var2Freq[0]; Cumfreq2[0] := Var2Freq[0];
for i := 1 to noints do for i := 1 to noInts do
Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i]; Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i];
end end
else else
if DistGroup.ItemIndex = 2 then // chi squared distribution if ChiSqDistChk.Checked then // chi squared distribution
begin begin
cellval := InputBox('Deg. Freedom 1 Entry','DF 1',''); cellval := InputBox('Deg. Freedom 1 Entry','DF 1','');
df1 := StrToInt(cellval); df1 := StrToInt(cellval);
name2 := 'Chi Sqrd'; name2 := 'Chi Sq';
min2 := 0.0; min2 := 0.0;
max2 := 20.0; max2 := 20.0;
range2 := max2 - min2; range2 := max2 - min2;
incrsize2 := range2 / noints; incrSize2 := range2 / noInts;
Xvalue2[0] := min2; xValue2[0] := min2;
Xvalue2[noints] := max2; xValue2[noInts] := max2;
for i := 1 to noints do for i := 1 to noints do
begin begin
Xvalue2[i-1] := min2 + (i-1) * incrsize2; Xvalue2[i-1] := min2 + (i-1) * incrSize2;
Xvalue2[i] := min2 + (i) * incrsize2; Xvalue2[i] := min2 + (i) * incrSize2;
prob1 := chisquaredprob(Xvalue2[i-1],df1); prob1 := chisquaredprob(Xvalue2[i-1],df1);
prob2 := chisquaredprob(Xvalue2[i],df1); prob2 := chisquaredprob(Xvalue2[i],df1);
if prob1 > prob2 then if prob1 > prob2 then
Var2Freq[i-1] := round((prob1-prob2) * Ncases) Var2Freq[i-1] := round((prob1-prob2) * nCases)
else else
Var2Freq[i-1] := round((prob2-prob1) * Ncases) Var2Freq[i-1] := round((prob2-prob1) * nCases)
end; end;
Cumfreq2[0] := Var2Freq[0]; cumfreq2[0] := var2Freq[0];
for i := 1 to noints do for i := 1 to noints do
Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i]; cumfreq2[i] := cumfreq2[i-1] + var2Freq[i];
end end
else else
if DistGroup.ItemIndex = 3 then // F distribution if FDistChk.Checked then // F distribution
begin begin
// get degrees of freedom // get degrees of freedom
cellval := InputBox('Deg. Freedom 1 Entry','DF 1',''); cellval := InputBox('Deg. Freedom 1 Entry','DF 1','');
@ -331,23 +483,23 @@ begin
incrsize2 := range2 / noints; incrsize2 := range2 / noints;
Xvalue2[0] := min2; Xvalue2[0] := min2;
Xvalue2[noints] := max2; Xvalue2[noints] := max2;
for i := 1 to noints do for i := 1 to noInts do
begin begin
Xvalue2[i-1] := min2 + (i-1) * incrsize2; Xvalue2[i-1] := min2 + (i-1) * incrSize2;
Xvalue2[i] := min2 + (i) * incrsize2; Xvalue2[i] := min2 + (i) * incrSize2;
prob1 := ProbF(Xvalue2[i-1],df1,df2); prob1 := ProbF(Xvalue2[i-1],df1,df2);
prob2 := ProbF(Xvalue2[i],df1,df2); prob2 := ProbF(Xvalue2[i],df1,df2);
if prob1 > prob2 then if prob1 > prob2 then
Var2Freq[i-1] := round((prob1-prob2) * Ncases) Var2Freq[i-1] := round((prob1-prob2) * nCases)
else else
Var2Freq[i-1] := round((prob2-prob1) * Ncases) Var2Freq[i-1] := round((prob2-prob1) * nCases)
end; end;
Cumfreq2[0] := Var2Freq[0]; cumfreq2[0] := Var2Freq[0];
for i := 1 to noints do for i := 1 to noInts do
Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i]; cumfreq2[i] := cumfreq2[i-1] + var2Freq[i];
end end
else else
if DistGroup.ItemIndex = 4 then // Poisson distribution if PoissonDistChk.Checked then // Poisson distribution
begin begin
name2 := 'Poisson'; name2 := 'Poisson';
mean := 0; // use as parameter a in pdf call mean := 0; // use as parameter a in pdf call
@ -358,33 +510,34 @@ begin
ErrorMsg('Value > 13 found. Factorial too large - exiting.'); ErrorMsg('Value > 13 found. Factorial too large - exiting.');
exit; exit;
end; end;
for i := 1 to Ncases do for i := 1 to nCases do
mean := mean + StrToFloat(OS3MainFrm.DataGrid.Cells[col1,i]); mean := mean + StrToFloat(OS3MainFrm.DataGrid.Cells[col1, i]);
mean := mean / Ncases; mean := mean / nCases;
cellval := IntToStr(round(mean)); cellval := IntToStr(round(mean));
cellval := InputBox('Parameter Entry (mean)','DF 1',cellval); cellval := InputBox('Parameter Entry (mean)', 'DF 1', cellval);
degfree := StrToFloat(cellval); degfree := StrToFloat(cellval);
range2 := max2 - min2; range2 := max2 - min2;
incrsize2 := range2 / noints; incrsize2 := range2 / noInts;
// Xvalue2[0] := min2; // Xvalue2[0] := min2;
Xvalue2[noints] := max2; Xvalue2[noints] := max2;
for i := 1 to noints do for i := 1 to noints do
begin begin
Xvalue2[i-1] := min2 + (i-1) * incrsize2; Xvalue2[i-1] := min2 + (i-1) * incrSize2;
Xvalue2[i] := min2 + (i) * incrsize2; Xvalue2[i] := min2 + (i) * incrSize2;
poisson_pdf ( round(Xvalue2[i-1]), degfree, prob1 ); poisson_pdf ( round(Xvalue2[i-1]), degfree, prob1 );
// prob1 := (Xvalue2[i-1],df1); // prob1 := (Xvalue2[i-1],df1);
// prob2 := chisquaredprob(Xvalue2[i],df1); // prob2 := chisquaredprob(Xvalue2[i],df1);
// if prob1 > prob2 then // if prob1 > prob2 then
Var2Freq[i-1] := round((prob1) * Ncases); Var2Freq[i-1] := round((prob1) * nCases);
// else Var2Freq[i-1] := round((prob2-prob1) * Ncases) // else Var2Freq[i-1] := round((prob2-prob1) * Ncases)
end; end;
Cumfreq2[0] := Var2Freq[0]; cumfreq2[0] := var2Freq[0];
for i := 1 to noints do for i := 1 to noInts do
Cumfreq2[i] := Cumfreq2[i-1] + Var2Freq[i]; cumfreq2[i] := cumfreq2[i-1] + var2Freq[i];
end; end;
end; end;
*)
lReport := TStringList.Create; lReport := TStringList.Create;
try try
lReport.Add('DISTRIBUTION COMPARISON by Bill Miller'); lReport.Add('DISTRIBUTION COMPARISON by Bill Miller');
@ -395,12 +548,14 @@ begin
lReport.Add('%10s %10s %10s %10s %10s %10s', [ lReport.Add('%10s %10s %10s %10s %10s %10s', [
'X1 Value', 'Frequency', 'Cum. Freq.', 'X2 Value', 'Frequency', 'Cum. Freq.' 'X1 Value', 'Frequency', 'Cum. Freq.', 'X2 Value', 'Frequency', 'Cum. Freq.'
]); ]);
lReport.Add('---------- ---------- ---------- ---------- ---------- ----------');
for i := 1 to noints do for i := 1 to noints do
lReport.Add('%10.3f %10d %10.3f %10.3f %10d %10.3f', [ lReport.Add('%10.3f %10.0f %10.3f %10.3f %10.0f %10.3f', [
XValue1[i-1], Var1Freq[i-1], Cumfreq1[i-1], XValue2[i-1], Var2Freq[i-1], Cumfreq2[i-1] XValue1[i-1], Var1Freq[i-1], Cumfreq1[i-1], XValue2[i-1], Var2Freq[i-1], Cumfreq2[i-1]
]); ]);
lReport.Add('');
cellval := 'D'; cellval := 'D';
KS := KolmogorovTest(noints, Cumfreq1,noints, Cumfreq2, cellval, lReport); KS := KolmogorovTest(noInts, Cumfreq1, noInts, Cumfreq2, cellVal, lReport);
// lReport.Add('Kolmogorov-Smirnov statistic := %5.3f', [KS]); // lReport.Add('Kolmogorov-Smirnov statistic := %5.3f', [KS]);
FReportFrame.DisplayReport(lReport); FReportFrame.DisplayReport(lReport);
@ -409,6 +564,17 @@ begin
end; end;
// plot the cdfs // plot the cdfs
Plot(FCumFreqChartFrame, cumFreq1, cumFreq2, VarOneEdit.Text, name2);
if BothChk.Checked then
Plot(FFreqChartFrame, var1Freq, var2Freq, VarOneEdit.Text, name2);
FreqChartPage.TabVisible := BothChk.Checked;
(*
xtitle := 'Red = ' + VarOneEdit.Text + ' Blue = ' + name2; xtitle := 'Red = ' + VarOneEdit.Text + ' Blue = ' + name2;
cellval := 'Plot of Cumulative Distributions'; cellval := 'Plot of Cumulative Distributions';
{ {
@ -489,6 +655,7 @@ begin
GraphFrm.Xpoints := nil; GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil; GraphFrm.Ypoints := nil;
end; end;
*)
// clean up // clean up
Cumfreq2 := nil; Cumfreq2 := nil;
@ -500,9 +667,36 @@ begin
end; end;
procedure TCompareDistFrm.DistGroupClick(Sender: TObject); procedure TCompareDistFrm.DistChange(Sender: TObject);
begin begin
DistType := DistGroup.ItemIndex; DF1Edit.Visible := CompareDist <> cd_Normal;
DF1Label.Visible := DF1Edit.Visible;
DF1Label.Caption := 'D.F.';
DF2Edit.Visible := CompareDist = cd_F;
DF2Label.Visible := DF2Edit.Visible;
if NormalDistChk.Checked then
CompareDist := cd_Normal
else if tDistChk.Checked then
begin
CompareDist := cd_t;
UpdateDF1;
end
else if ChiSqDistChk.Checked then
CompareDist := cd_ChiSq
else if FDistChk.Checked then
begin
CompareDist := cd_F;
DF1Label.Caption := 'D.F. 1';
end
else if PoissonDistChk.Checked then
begin
CompareDist := cd_Poisson;
DF1Label.Caption := 'Mean';
UpdateDF1;
end else
raise Exception.Create('Distribution not supported.');
end; end;
@ -534,7 +728,7 @@ begin
if Width < Constraints.MinWidth then Width := 1; if Width < Constraints.MinWidth then Width := 1;
if Height < Constraints.MinHeight then Height := 1; if Height < Constraints.MinHeight then Height := 1;
Notebook.AutoSize := false; // Notebook.AutoSize := false;
Position := poDesigned; Position := poDesigned;
FAutoSized := true; FAutoSized := true;
end; end;
@ -551,31 +745,81 @@ begin
FReportFrame.Parent := ReportPage; FReportFrame.Parent := ReportPage;
FReportFrame.Align := alClient; FReportFrame.Align := alClient;
FChartFrame := TChartFrame.Create(self); FCumFreqChartFrame := TChartFrame.Create(self);
FChartFrame.Parent := ChartPage; FCumFreqChartFrame.Parent := CumFreqChartPage;
FChartFrame.Align := alClient; FCumFreqChartFrame.Align := alClient;
FChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80; FCumFreqChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80;
FChartFrame.Chart.BottomAxis.Intervals.MinLength := 30; FCumFreqChartFrame.Chart.BottomAxis.Intervals.MinLength := 30;
FCumFreqChartFrame.SetYTitle('Cumulative frequency');
FCumFreqChartFrame.SetTitle('Plot of Cumulative Distributions');
FFreqChartFrame := TChartFrame.Create(self);
FFreqChartFrame.Parent := FreqChartPage;
FFreqChartFrame.Align := alClient;
FFreqChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80;
FFreqChartFrame.Chart.BottomAxis.Intervals.MinLength := 30;
FFreqChartFrame.SetYTitle('Frequency');
FFreqChartFrame.SetTitle('Plot of Distributions');
Reset; Reset;
end; end;
procedure TCompareDistFrm.Plot(AChartFrame: TChartFrame; Y1Values, Y2Values: DblDyneVec;
AName1, AName2: String);
var
ser1, ser2: TChartSeries;
plotType: TPlotType;
begin
AChartFrame.Clear;
if BarPlotBtn.Down then
plotType := ptBars
else
plotType := ptLines;
ser1 := AChartFrame.PlotXY(plotType, nil, Y1Values, nil, nil, AName1, DATA_COLORS[0]);
ser2 := AChartFrame.PlotXY(plotType, nil, Y2Values, nil, nil, AName2, DATA_Colors[1]);
if (ser1 is TBarSeries) then
begin
with ser1 as TBarSeries do
begin
BarWidthPercent := 40;
BarOffsetPercent := -20;
end;
with ser2 as TBarSeries do
begin
BarWidthPercent := 40;
BarOffsetPercent := +20;
end;
end;
end;
procedure TCompareDistFrm.Reset; procedure TCompareDistFrm.Reset;
var var
i: integer; i: integer;
begin begin
VarList.Clear; VarList.Clear;
VarOneEdit.Text := ''; VarOneEdit.Text := '';
VarTwoEdit.Text := ''; VarTwoEdit.Text := '';
DF1Edit.Text := '';
DF2Edit.Text := '';
for i := 1 to NoVariables do for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
CompareGroup.ItemIndex := 0; CompareGroup.ItemIndex := 0;
CompareGroupClick(nil); CompareGroupClick(nil);
DistGroup.ItemIndex := 0; NormalDistChk.Checked := true;
DistChange(nil);
FReportFrame.Clear; FReportFrame.Clear;
FChartFrame.Clear; FCumFreqChartFrame.Clear;
FFreqChartFrame.Clear;
FreqChartPage.TabVisible := false;
end; end;
@ -593,7 +837,109 @@ begin
Var2OutBtn.Enabled := VarTwoEdit.Text <> ''; Var2OutBtn.Enabled := VarTwoEdit.Text <> '';
FReportFrame.UpdateBtnStates; FReportFrame.UpdateBtnStates;
FChartFrame.UpdateBtnStates; FCumFreqChartFrame.UpdateBtnStates;
FFreqChartFrame.UpdateBtnStates;
end;
procedure TCompareDistFrm.UpdateDF1;
procedure DFCandidates(AVarName: String; out AMean: Double; out ANumCases: Integer);
var
col, i: Integer;
begin
for col := 1 to NoVariables do
if AVarName = OS3MainFrm.DataGrid.Cells[col, 0] then
begin
AMean := 0;
ANumCases := 0;
for i := 1 to NoCases do
if ValidValue(i, col) then
begin
AMean := AMean + StrToFloat(OS3MainFrm.DataGrid.Cells[col, i]);
inc(ANumCases);
end;
if ANumCases > 1 then
AMean := AMean / ANumCases
else
AMean := NaN;
exit;
end;
AMean := NaN;
ANumCases := -1;
end;
var
m: Double;
n: Integer;
begin
if (CompareTo = ctTheoreticalDistrib) then
begin
DFCandidates(VarOneEdit.Text, m, n);
case CompareDist of
cd_t :
if n > 0 then
DF1Edit.Text := IntToStr(n-1);
cd_Poisson:
if not IsNaN(m) then
DF1Edit.Text := FormatFloat('0', m);
end;
end;
end;
function TCompareDistFrm.Validate(ANumCases: Integer;
out AMsg: String; out AControl: TWinControl): Boolean;
var
n: Integer = 0;
begin
Result := false;
if CompareDist <> cd_Normal then
begin
if DF1Edit.Text = '' then
begin
AMsg := 'This control cannot be empty.';
AControl := DF1Edit;
exit;
end;
if not TryStrToInt(DF1Edit.Text, n) or (n < 0) then
begin
AMsg := 'Positive integer value required.';
AControl := DF1Edit;
exit;
end;
if (n >= ANumCases) and (CompareDist <> cd_Poisson) then
begin
AMsg := 'Degrees of freedom cannot be greater than the number of cases.';
AControl := DF1Edit;
exit;
end;
end;
if CompareDist = cd_F then
begin
if DF2Edit.Text = '' then
begin
AMsg := 'This control cannot be empty.';
AControl := DF2Edit;
exit;
end;
if not TryStrToInt(DF2Edit.Text, n) or (n < 0) then
begin
AMsg := 'Positive integer value required.';
AControl := DF2Edit;
exit;
end;
if n >= ANumCases then
begin
AMsg := 'Degrees of freedom cannot be greater than the number of cases.';
AControl := DF2Edit;
exit;
end;
end;
Result := true;
end; end;
@ -613,6 +959,7 @@ begin
inc(i); inc(i);
end; end;
UpdateBtnStates; UpdateBtnStates;
UpdateDF1;
end; end;

View File

@ -69,6 +69,7 @@ uses
constructor TChartFrame.Create(AOwner: TComponent); constructor TChartFrame.Create(AOwner: TComponent);
begin begin
inherited; inherited;
Name := '';
{$IF LCL_FullVersion >= 2010000} {$IF LCL_FullVersion >= 2010000}
ZoomDragTool.LimitToExtent := [zdDown]; ZoomDragTool.LimitToExtent := [zdDown];
PanDragTool.LimitToExtent := [pdDown]; PanDragTool.LimitToExtent := [pdDown];
@ -174,7 +175,10 @@ begin
end; end;
end; end;
ptBars: ptBars:
begin
Result := TBarSeries.Create(self); Result := TBarSeries.Create(self);
TBarSeries(Result).BarBrush.Color := AColor;
end;
ptArea: ptArea:
Result := TAreaSeries.Create(self); Result := TAreaSeries.Create(self);
else else