2020-11-02 22:58:55 +00:00
|
|
|
// Test file: srh.tab
|
|
|
|
// Created with data from https://rcompanion.org/handbook/F_14.html
|
|
|
|
// - Dependent variable: Yield
|
|
|
|
// - Factor 1: Crop
|
|
|
|
// - Factor 2: Fertilizer
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
unit SRHTestUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-10-29 22:17:02 +00:00
|
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
2020-11-02 22:58:55 +00:00
|
|
|
StdCtrls, Buttons, ExtCtrls, ComCtrls,
|
|
|
|
TASources, TACustomSeries, TAStyles,
|
|
|
|
MainUnit, Globals, FunctionsLib, BasicStatsReportAndChartFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
TSRHResults = record
|
|
|
|
TotalCount: Integer; // N
|
|
|
|
|
|
|
|
CellCounts: IntDyneMat;
|
|
|
|
CellSums: DblDyneMat;
|
|
|
|
CellVars: DblDyneMat;
|
|
|
|
|
|
|
|
RowSums, ColSums: DblDyneVec;
|
|
|
|
RowCount, ColCount: IntDyneVec;
|
|
|
|
|
|
|
|
MeanDep, MeanF1, MeanF2: double;
|
|
|
|
|
|
|
|
SSDep, SSErr, SSF1, SSF2, SSF1F2: double;
|
|
|
|
MSDep, MSErr, MSF1, MSF2, MSF1F2: double;
|
|
|
|
DFTot, DFErr, DFF1, DFF2, DFF1F2: double;
|
|
|
|
Omega, OmegaF1, OmegaF2, OmegaF1F2: double;
|
|
|
|
FF1, FF2, FF1F2: Double;
|
|
|
|
ProbF1, ProbF2, ProbF1F2: double;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
{ TSRHTestForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
TSRHTestForm = class(TBasicStatsReportAndChartForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
Bevel1: TBevel;
|
2020-11-02 22:58:55 +00:00
|
|
|
ChartStyles: TChartStyles;
|
2020-03-30 18:01:44 +00:00
|
|
|
DepIn: TBitBtn;
|
|
|
|
DepOut: TBitBtn;
|
|
|
|
DepVar: TEdit;
|
|
|
|
Fact1In: TBitBtn;
|
|
|
|
Fact1Out: TBitBtn;
|
|
|
|
Fact2In: TBitBtn;
|
|
|
|
Fact2Out: TBitBtn;
|
|
|
|
Factor1: TEdit;
|
|
|
|
Factor2: TEdit;
|
|
|
|
Label1: TLabel;
|
|
|
|
Label3: TLabel;
|
|
|
|
OverallAlpha: TEdit;
|
|
|
|
StaticText1: TStaticText;
|
|
|
|
StaticText2: TStaticText;
|
|
|
|
StaticText3: TStaticText;
|
|
|
|
VarList: TListBox;
|
|
|
|
procedure DepInClick(Sender: TObject);
|
|
|
|
procedure DepOutClick(Sender: TObject);
|
|
|
|
procedure Fact1InClick(Sender: TObject);
|
|
|
|
procedure Fact1OutClick(Sender: TObject);
|
|
|
|
procedure Fact2InClick(Sender: TObject);
|
|
|
|
procedure Fact2OutClick(Sender: TObject);
|
2020-11-02 22:58:55 +00:00
|
|
|
procedure VarListDblClick(Sender: TObject);
|
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-11-01 23:04:21 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
private
|
2020-11-02 22:58:55 +00:00
|
|
|
F1Labels: StrDyneVec;
|
|
|
|
F2Labels: StrDyneVec;
|
|
|
|
|
2020-11-03 10:45:14 +00:00
|
|
|
procedure GetColsSelected(out AColsSelected: IntDyneVec);
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
function GetLabels(AColsSelected: IntDyneVec): Boolean;
|
|
|
|
|
|
|
|
function Calc2Way(const AColsSelected: IntDyneVec;
|
|
|
|
var AResults: TSRHResults) : Boolean;
|
|
|
|
|
|
|
|
procedure TwoWayTable(const AResults: TSRHResults);
|
|
|
|
|
|
|
|
procedure TwoWayPlot(const AResults: TSRHResults);
|
|
|
|
|
|
|
|
private
|
|
|
|
FChartSeries: TChartSeries;
|
|
|
|
FChartSources: array[0..3] of TListChartSource;
|
|
|
|
FSeriesButtons: array[0..3] of TToolButton;
|
|
|
|
procedure PrepareStyles(const ALabels: StrDyneVec);
|
|
|
|
procedure SelectPlot(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
protected
|
|
|
|
procedure AdjustConstraints; override;
|
|
|
|
procedure Compute; override;
|
|
|
|
procedure UpdateBtnStates; override;
|
2020-11-02 22:58:55 +00:00
|
|
|
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
public
|
2020-11-01 23:04:21 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
|
procedure Reset; override;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
2020-11-01 23:04:21 +00:00
|
|
|
SRHTestForm: TSRHTestForm;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
implementation
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
uses
|
2020-11-02 22:58:55 +00:00
|
|
|
Math,
|
|
|
|
TAChartUtils, TACustomSource, TALegend, TASeries,
|
|
|
|
Utils, MathUnit, GridProcs, ChartFrameUnit;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
{ TSRHTestForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
constructor TSRHTestForm.Create(AOwner: TComponent);
|
2020-11-02 22:58:55 +00:00
|
|
|
var
|
|
|
|
tb: TToolButton;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-01 23:04:21 +00:00
|
|
|
inherited;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
FChartSources[0] := TListChartSource.Create(FChartFrame);
|
|
|
|
FChartSources[1] := TListChartSource.Create(FChartFrame);
|
|
|
|
FChartSources[2] := TListChartSource.Create(FChartFrame);
|
|
|
|
FChartSources[3] := TListChartSource.Create(FChartFrame);
|
|
|
|
|
|
|
|
FChartFrame.ChartToolbar.ShowCaptions := true;
|
|
|
|
FChartFrame.Charttoolbar.ButtonHeight := 40;
|
|
|
|
|
|
|
|
tb := TToolButton.Create(FChartFrame.ChartToolbar);
|
|
|
|
tb.Style := tbsDivider;
|
|
|
|
AddButtonToToolbar(tb, FChartFrame.ChartToolbar);
|
|
|
|
|
|
|
|
FSeriesButtons[0] := TToolButton.Create(FChartFrame.ChartToolbar);
|
|
|
|
FSeriesButtons[0].Caption := 'Factor 1';
|
|
|
|
FSeriesButtons[0].ShowCaption := true;
|
|
|
|
FSeriesButtons[0].Style := tbsCheck;
|
|
|
|
FSeriesButtons[0].Grouped := true;
|
|
|
|
FSeriesButtons[0].Tag := 10;
|
|
|
|
FSeriesButtons[0].OnClick := @SelectPlot;
|
|
|
|
AddButtonToToolbar(FSeriesButtons[0], FChartFrame.ChartToolbar);
|
|
|
|
|
|
|
|
FSeriesButtons[1] := TToolButton.Create(FChartFrame.ChartToolbar);
|
|
|
|
FSeriesButtons[1].Caption := 'Factor 2';
|
|
|
|
FSeriesButtons[1].ShowCaption := true;
|
|
|
|
FSeriesButtons[1].Style := tbsCheck;
|
|
|
|
FSeriesButtons[1].Grouped := true;
|
|
|
|
FSeriesButtons[1].Tag := 11;
|
|
|
|
FSeriesButtons[1].OnClick := @SelectPlot;
|
|
|
|
AddButtonToToolbar(FSeriesButtons[1], FChartFrame.ChartToolbar);
|
|
|
|
|
|
|
|
FSeriesButtons[2] := TToolButton.Create(FChartFrame.ChartToolbar);
|
|
|
|
FSeriesButtons[2].Caption := 'Factor 1 * Factor 2';
|
|
|
|
FSeriesButtons[2].ShowCaption := true;
|
|
|
|
FSeriesButtons[2].Style := tbsCheck;
|
|
|
|
FSeriesButtons[2].Grouped := true;
|
|
|
|
FSeriesButtons[2].Tag := 12;
|
|
|
|
FSeriesButtons[2].OnClick := @SelectPlot;
|
|
|
|
AddButtonToToolbar(FSeriesButtons[2], FChartFrame.ChartToolbar);
|
|
|
|
|
|
|
|
FSeriesButtons[3] := TToolButton.Create(FChartFrame.ChartToolbar);
|
|
|
|
FSeriesButtons[3].Caption := 'Factor 1 * Factor 2 (rotated)';
|
|
|
|
FSeriesButtons[3].ShowCaption := true;
|
|
|
|
FSeriesButtons[3].Style := tbsCheck;
|
|
|
|
FSeriesButtons[3].Grouped := true;
|
|
|
|
FSeriesButtons[3].Tag := 13;
|
|
|
|
FSeriesButtons[3].OnClick := @SelectPlot;
|
|
|
|
AddButtonToToolbar(FSeriesButtons[3], FChartFrame.ChartToolbar);
|
2020-11-01 23:04:21 +00:00
|
|
|
|
|
|
|
PageControl.ActivePageIndex := 0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-01 23:04:21 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
ParamsPanel.Constraints.MinWidth := Max(
|
|
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
|
|
|
|
2*(Label3.Width + OverallAlpha.BorderSpacing.Left + OverallAlpha.Width) - Fact1In.Width);
|
2020-11-02 22:58:55 +00:00
|
|
|
ParamsPanel.Constraints.MinHeight := OverallAlpha.Top + OverallAlpha.Height +
|
2020-11-01 23:04:21 +00:00
|
|
|
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Returns false if an error has occured.
|
|
|
|
function TSRHTestForm.Calc2Way(const AColsSelected: IntDyneVec;
|
|
|
|
var AResults: TSRHResults): Boolean;
|
2020-11-01 23:04:21 +00:00
|
|
|
var
|
2020-11-02 22:58:55 +00:00
|
|
|
X, Xsq: Double;
|
|
|
|
i, j: integer;
|
|
|
|
grpName: String;
|
|
|
|
grp1, grp2: integer;
|
|
|
|
constant, rowsTotCnt, colsTotCnt, SSCells: double;
|
|
|
|
groupSize: Integer;
|
|
|
|
numF1, numF2: Integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
Result := true;
|
|
|
|
|
|
|
|
numF1 := Length(F1Labels);
|
|
|
|
numF2 := Length(F2Labels);
|
|
|
|
|
|
|
|
// Allocate memory for arrays
|
|
|
|
AResults.CellCounts := nil;
|
|
|
|
AResults.CellSums := nil;
|
|
|
|
AResults.CellVars := nil;
|
|
|
|
AResults.RowSums := nil;
|
|
|
|
AResults.ColSums := nil;
|
|
|
|
AResults.RowCount := nil;
|
|
|
|
AResults.ColCount := nil;
|
|
|
|
SetLength(AResults.CellCounts, numF1, numF2);
|
|
|
|
SetLength(AResults.CellSums, numF1, numF2);
|
|
|
|
SetLength(AResults.CellVars, numF1, numF2);
|
|
|
|
SetLength(AResults.RowSums, numF1);
|
|
|
|
SetLength(AResults.ColSums, numF2);
|
|
|
|
SetLength(AResults.RowCount, numF1);
|
|
|
|
SetLength(AResults.ColCount, numF2);
|
|
|
|
|
|
|
|
AResults.TotalCount := 0;
|
|
|
|
AResults.MeanDep := 0.0;
|
|
|
|
AResults.MeanF1 := 0;
|
|
|
|
AResults.MeanF2 := 0;
|
|
|
|
AResults.SSDep := 0.0;
|
|
|
|
AResults.SSF1 := 0;
|
|
|
|
AResults.SSF2 := 0;
|
|
|
|
AResults.SSF1F2 := 0;
|
|
|
|
SSCells := 0.0;
|
|
|
|
rowsTotCnt := 0.0;
|
|
|
|
colsTotCnt := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Get working totals
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, AColsSelected) then continue;
|
|
|
|
|
|
|
|
// Note: AColsSelected contains: 0: GrpVar, 1: Factor1, 2: Factor2
|
|
|
|
X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[AColsSelected[0], i]));
|
|
|
|
Xsq := X*X;
|
|
|
|
grpName := Trim(OS3MainFrm.DataGrid.Cells[AColsSelected[1], i]);
|
|
|
|
grp1 := IndexOfString(F1Labels, grpName);
|
|
|
|
grpName := Trim(OS3MainFrm.DataGrid.Cells[AColsSelected[2], i]);
|
|
|
|
grp2 := IndexOfString(F2Labels, grpName);
|
|
|
|
AResults.CellCounts[grp1, grp2] := AResults.CellCounts[grp1, grp2] + 1;
|
|
|
|
AResults.CellSums[grp1, grp2] := AResults.CellSums[grp1, grp2] + X;
|
|
|
|
AResults.CellVars[grp1, grp2] := AResults.CellVars[grp1, grp2] + Xsq;
|
|
|
|
AResults.RowSums[grp1] := AResults.RowSums[grp1] + X;
|
|
|
|
AResults.ColSums[grp2] := AResults.ColSums[grp2] + X;
|
|
|
|
AResults.RowCount[grp1] := AResults.RowCount[grp1] + 1;
|
|
|
|
AResults.ColCount[grp2] := AResults.ColCount[grp2] + 1;
|
|
|
|
AResults.MeanDep := AResults.MeanDep + X;
|
|
|
|
AResults.SSDep := AResults.SSDep + Xsq;
|
|
|
|
AResults.TotalCount := AResults.TotalCount + 1;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Check for equal groups
|
|
|
|
groupSize := AResults.CellCounts[0, 0];
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
if AResults.CellCounts[i, j] <> groupSize then
|
|
|
|
begin
|
|
|
|
ErrorMsg('All groups must have the same size.');
|
|
|
|
Result := false;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Calculate results
|
|
|
|
for i := 0 to numF1-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
AResults.SSF1 := AResults.SSF1 + (sqr(AResults.RowSums[i]) / AResults.RowCount[i]);
|
|
|
|
RowsTotCnt := RowsTotCnt + AResults.RowCount[i];
|
|
|
|
end;
|
|
|
|
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
begin
|
|
|
|
AResults.SSF2 := AResults.SSF2 + (sqr(AResults.ColSums[j]) / AResults.ColCount[j]);
|
|
|
|
ColsTotCnt := ColsTotCnt + AResults.ColCount[j];
|
|
|
|
end;
|
|
|
|
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
if AResults.CellCounts[i,j] > 0 then
|
|
|
|
SSCells := SSCells + (sqr(AResults.CellSums[i,j]) / AResults.CellCounts[i,j]);
|
|
|
|
|
|
|
|
if AResults.TotalCount > 0 then
|
|
|
|
constant := sqr(AResults.MeanDep) / AResults.TotalCount
|
|
|
|
else
|
|
|
|
constant := 0.0;
|
|
|
|
|
|
|
|
AResults.SSF1 := AResults.SSF1 - constant;
|
|
|
|
AResults.SSF2 := AResults.SSF2 - constant;
|
|
|
|
AResults.SSF1F2 := SSCells - AResults.SSF1 - AResults.SSF2 - constant;
|
|
|
|
AResults.SSErr := AResults.SSDep - SSCells;
|
|
|
|
AResults.SSDep := AResults.SSDep - constant;
|
|
|
|
|
|
|
|
if (AResults.SSF1F2 < 0) or (AResults.SSF1 < 0) or (AResults.SSF2 < 0) then
|
|
|
|
begin
|
|
|
|
ErrorMsg('A negative sum of squares has been found. Unbalanced design? Ending analysis.');
|
|
|
|
Result := false;
|
|
|
|
exit;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Degrees of freedom
|
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
DFTot := TotalCount - 1;
|
|
|
|
DFF1 := numF1 - 1;
|
|
|
|
DFF2 := numF2 - 1;
|
|
|
|
DFF1F2 := DFF1 * DFF2;
|
|
|
|
DFErr := DFTot - DFF1 - DFF2 - DFF1F2;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Mean standard error
|
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
MSF1 := SSF1 / DFF1;
|
|
|
|
MSF2 := SSF2 / DFF2;
|
|
|
|
MSF1F2 := SSF1F2 / DFF1F2;
|
|
|
|
MSErr := SSErr / DFErr;
|
|
|
|
MSDep := SSDep / DFTot;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Omega
|
|
|
|
with AResults do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr);
|
|
|
|
OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr);
|
|
|
|
OmegaF1F2 := (SSF1F2 - DFF1F2 * MSErr) / (SSDep + MSErr);
|
|
|
|
Omega := OmegaF1 + OmegaF2 + OmegaF1F2;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Mean of dependent variable
|
|
|
|
with AResults do
|
|
|
|
MeanDep := MeanDep / TotalCount;
|
|
|
|
|
|
|
|
// F tests for fixed effects
|
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
FF1 := abs(MSF1 / MSErr);
|
|
|
|
FF2 := abs(MSF2 / MSErr);
|
|
|
|
FF1F2 := abs(MSF1F2 / MSErr);
|
|
|
|
|
|
|
|
ProbF1 := ProbF(FF1, DFF1, DFErr);
|
|
|
|
ProbF2 := ProbF(FF2, DFF2, DFErr);
|
|
|
|
ProbF1F2 := ProbF(FF1F2, DFF1F2, DFErr);
|
|
|
|
if (ProbF1 > 1.0) then ProbF1 := 1.0;
|
|
|
|
if (ProbF2 > 1.0) then ProbF2 := 1.0;
|
|
|
|
if (ProbF1F2 > 1.0) then ProbF1F2 := 1.0;
|
|
|
|
|
|
|
|
// Obtain omega squared (proportion of dependent variable explained)
|
|
|
|
if (OmegaF1 < 0.0) then OmegaF1 := 0.0;
|
|
|
|
if (OmegaF2 < 0.0) then OmegaF2 := 0.0;
|
|
|
|
if (OmegaF1F2 < 0.0) then OmegaF1F2 := 0.0;
|
|
|
|
if (Omega < 0.0) then Omega := 0.0;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.Compute;
|
|
|
|
var
|
|
|
|
colNoSelected: IntDyneVec = nil;
|
|
|
|
res: TSRHResults;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
// Get column numbers of dependent variable and factors
|
2020-11-03 10:45:14 +00:00
|
|
|
GetColsSelected(colNoSelected);
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
// get labels for each factor level
|
|
|
|
if not GetLabels(colNoSelected) then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
// Calculate two-way ANOVA
|
|
|
|
res := Default(TSRHResults);
|
|
|
|
if not Calc2Way(colNoSelected, res) then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
// Display the ANOVA etc in a report
|
|
|
|
TwoWayTable(res);
|
|
|
|
|
|
|
|
// Plot the means.
|
|
|
|
TwoWayPlot(res);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.DepInClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index : integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
2020-11-02 22:58:55 +00:00
|
|
|
if (index > -1) and (DepVar.Text = '') then
|
|
|
|
begin
|
|
|
|
DepVar.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.DepOutClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
if DepVar.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(DepVar.Text);
|
|
|
|
DepVar.Text := '';
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.Fact1InClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
2020-11-02 22:58:55 +00:00
|
|
|
if (index > -1 ) and (Factor1.Text = '') then
|
|
|
|
begin
|
|
|
|
Factor1.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.Fact1OutClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
if Factor1.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(Factor1.Text);
|
|
|
|
Factor1.Text := '';
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
procedure TSRHTestForm.Fact2InClick(Sender: TObject);
|
2020-10-29 22:17:02 +00:00
|
|
|
var
|
2020-11-02 22:58:55 +00:00
|
|
|
index: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (Factor2.Text = '') then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
Factor2.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-11-02 22:58:55 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TSRHTestForm.Fact2OutClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if Factor2.Text <> '' then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
VarList.Items.Add(Factor2.Text);
|
|
|
|
Factor2.Text := '';
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
2020-11-03 10:45:14 +00:00
|
|
|
procedure TSRHTestForm.GetColsSelected(out AColsSelected: IntDyneVec);
|
|
|
|
begin
|
|
|
|
AColsSelected := nil;
|
|
|
|
SetLength(AColsSelected, 3);
|
|
|
|
AColsSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, DepVar.Text);
|
|
|
|
AColsSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, Factor1.Text);
|
|
|
|
AColsSelected[2] := GetVariableIndex(OS3MainFrm.DataGrid, Factor2.Text);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
function TSRHTestForm.GetLabels(AColsSelected: IntDyneVec): Boolean;
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-11-02 22:58:55 +00:00
|
|
|
i, nF1, nF2: integer;
|
|
|
|
floatVal: Double;
|
|
|
|
s: String;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
Result := false;
|
|
|
|
|
|
|
|
// Check validity of values of dependent variable
|
2020-03-30 18:01:44 +00:00
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, AColsSelected) then continue;
|
|
|
|
if not TryStrToFloat(OS3MainFrm.DataGrid.Cells[AColsSelected[0], i], floatVal) then
|
|
|
|
begin
|
|
|
|
ErrorMsg('No valid number in cell at row %d and column %d', [i, AColsSelected[0]]);
|
|
|
|
exit;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Extract labels of the Factor 1 and Factor 2 cases.
|
|
|
|
F1Labels := nil;
|
|
|
|
F2Labels := nil;
|
|
|
|
Setlength(F1Labels, NoCases); // over-dimensioned, will be trimmed later.
|
|
|
|
SetLength(F2Labels, NoCases);
|
|
|
|
nF1 := 0;
|
|
|
|
nF2 := 0;
|
|
|
|
for i := 1 to NoCases do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, AColsSelected) then continue;
|
|
|
|
|
|
|
|
// Index 1 identifies Factor 1
|
|
|
|
s := OS3MainFrm.DataGrid.Cells[AColsSelected[1], i];
|
|
|
|
if IndexOfString(F1Labels, s) = -1 then
|
|
|
|
begin
|
|
|
|
F1Labels[nF1] := s;
|
|
|
|
inc(nF1);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Index 2 indentifies Factor 2
|
|
|
|
s := OS3MainFrm.DataGrid.Cells[AColsSelected[2], i];
|
|
|
|
if IndexOfString(F2Labels, s) = -1 then
|
|
|
|
begin
|
|
|
|
F2Labels[nF2] := s;
|
|
|
|
inc(nF2);
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Trim the label arrays to correct length
|
|
|
|
SetLength(F1Labels, nF1);
|
|
|
|
SetLength(F2Labels, nF2);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
Result := true;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.TwoWayTable(const AResults: TSRHResults);
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-11-02 22:58:55 +00:00
|
|
|
MinVar, MaxVar, sumvars, sumDFrecip: double;
|
|
|
|
i, j, groupSize, numF1, numF2: integer;
|
|
|
|
XBar, V, S, RowSS, ColSS: double;
|
|
|
|
sumFreqLogVar, c, bartlett, cochran, hartley, chiProb: double;
|
|
|
|
H, HProb: double;
|
|
|
|
lReport: TStrings;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('TWO WAY ANALYSIS OF VARIANCE');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Variable analyzed: %s', [DepVar.Text]);
|
|
|
|
lReport.Add('Factor A (rows) variable: %s', [Factor1.Text]);
|
|
|
|
lReport.Add('Factor B (columns) variable: %s', [Factor2.Text]);
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Sqr. H H Prob.');
|
|
|
|
lReport.Add('------------- ---- ---------- ---------- -------- -------- ---------- ------ -------');
|
|
|
|
|
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
H := SSF1 / MSDep;
|
|
|
|
HProb := 1.0 - ChiSquaredProb(H,round(DFF1));
|
|
|
|
lReport.Add('Among Rows %4.0f %10.3f %10.3f %8.3f %8.3f %6.3f %6.3f %6.3f',
|
|
|
|
[DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1, H, HProb]);
|
|
|
|
|
|
|
|
H := SSF2 / MSDep;
|
|
|
|
HProb := 1.0 - ChiSquaredProb(H,round(DFF2));
|
|
|
|
lReport.Add('Among Columns %4.0f %10.3f %10.3f %8.3f %8.3f %6.3f %6.3f %6.3f',
|
|
|
|
[DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2, H, HProb]);
|
|
|
|
|
|
|
|
H := SSF1F2 / MSDep;
|
|
|
|
HProb := 1.0 - ChiSquaredProb(H,round(DFF1F2));
|
|
|
|
lReport.Add('Interaction %4.0f %10.3f %10.3f %8.3f %8.3f %6.3f %6.3f %6.3f',
|
|
|
|
[DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2, H, HProb]);
|
|
|
|
lReport.Add('Within Groups %4.0f %10.3f %10.3f',
|
|
|
|
[DFErr, SSErr, MSErr]);
|
|
|
|
lReport.Add('Total %4.0f %10.3f %10.3f',
|
|
|
|
[DFTot, SSDep, MSDep]);
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Omega squared for combined effects: %10.3f', [Omega]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
lReport.Add('DESCRIPTIVE STATISTICS');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('GROUP Row Col. N MEAN VARIANCE STD.DEV. ');
|
|
|
|
lReport.Add('----- ---------- ---------- ---- -------- ---------- ----------');
|
|
|
|
|
|
|
|
MaxVar := -1E304;
|
|
|
|
MinVar := 1E304;
|
|
|
|
sumvars := 0.0;
|
|
|
|
sumFreqLogVar := 0.0;
|
|
|
|
sumDFrecip := 0.0;
|
|
|
|
|
|
|
|
// Display cell means, variances, standard deviations
|
|
|
|
numF1 := Length(F1Labels);
|
|
|
|
numF2 := Length(F2Labels);
|
|
|
|
|
|
|
|
V := 0.0;
|
|
|
|
XBar := 0.0;
|
|
|
|
S := 0.0;
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
begin
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
begin
|
|
|
|
if AResults.CellCounts[i,j] > 1 then
|
|
|
|
begin
|
|
|
|
XBar := AResults.CellSums[i,j] / AResults.CellCounts[i,j];
|
|
|
|
V := AResults.CellVars[i,j] - sqr(AResults.CellSums[i,j]) / AResults.CellCounts[i,j];
|
|
|
|
V := V / (AResults.CellCounts[i,j] - 1.0);
|
|
|
|
S := sqrt(V);
|
|
|
|
sumVars := sumVars + V;
|
|
|
|
if V > MaxVar then MaxVar := V;
|
|
|
|
if V < MinVar then MinVar := V;
|
|
|
|
sumDFrecip := sumDFrecip + (1.0 / (AResults.CellCounts[i,j] - 1));
|
|
|
|
sumFreqLogVar := sumFreqLogVar + ((AResults.CellCounts[i,j] - 1) * ln(V));
|
|
|
|
end;
|
|
|
|
lReport.Add('Cell %-10s %-10s %4d %8.3f %10.3f %10.3f',
|
|
|
|
[F1Labels[i], F2Labels[j], AResults.CellCounts[i, j], XBar, V, S]);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
//Display Row means, variances, standard deviations
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
begin
|
|
|
|
XBar := AResults.RowSums[i] / AResults.RowCount[i];
|
|
|
|
RowSS := 0.0;
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
RowSS := RowSS + AResults.CellVars[i,j];
|
|
|
|
V := RowSS - sqr(AResults.RowSums[i]) / AResults.RowCount[i];
|
|
|
|
V := V / (AResults.RowCount[i] - 1);
|
|
|
|
S := sqrt(V);
|
|
|
|
lReport.Add('Row %-10s %4d %8.3f %10.3f %10.3f',
|
|
|
|
[F1Labels[i], AResults.RowCount[i], XBar, V, S]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
//Display means, variances and standard deviations for columns
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
begin
|
|
|
|
XBar := AResults.ColSums[j] / AResults.ColCount[j];
|
|
|
|
ColSS := 0.0;
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
ColSS := ColSS + AResults.CellVars[i,j];
|
|
|
|
|
|
|
|
V := NaN;
|
|
|
|
S := NaN;
|
|
|
|
if AResults.ColCount[j] > 0 then
|
|
|
|
begin
|
|
|
|
V := ColSS - sqr(AResults.ColSums[j]) / AResults.ColCount[j];
|
|
|
|
if AResults.ColCount[j] > 1 then
|
|
|
|
begin
|
|
|
|
V := V / (AResults.ColCount[j] - 1);
|
|
|
|
if V > 0.0 then
|
|
|
|
S := sqrt(V);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
lReport.Add('Col %-10s %4d %8.3f %10.3f %10.3f',
|
|
|
|
[F2Labels[j], AResults.ColCount[j], XBar, V, S]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
lReport.Add( 'TOTAL %4d %8.3f %10.3f %10.3f',
|
|
|
|
[AResults.TotalCount, AResults.MeanDep, AResults.MSDep, sqrt(AResults.MSDep)]);
|
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
c := 1.0 + (1.0 / (3.0 * numF1 * numF2 - 1.0)) * (sumDFrecip - (1.0 / AResults.DFErr));
|
|
|
|
bartlett := (2.303 / c) * ((AResults.DFErr * ln(AResults.MSErr)) - sumfreqlogvar);
|
|
|
|
chiProb := 1.0 - chisquaredprob(bartlett,round(numF1 * numF2 - 1));
|
|
|
|
cochran := maxvar / sumvars;
|
|
|
|
hartley := maxvar / minvar;
|
|
|
|
groupSize := AResults.CellCounts[0, 0];
|
|
|
|
|
|
|
|
LReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Hartley FMax test statistic: %10.3f', [hartley]);
|
|
|
|
lReport.Add(' with %d and %d degrees of freedom', [numF1*numF2, groupsize-1]);
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Cochran C statistic: %10.3f', [cochran]);
|
|
|
|
lReport.Add(' with %d and %d degrees of freedom', [numF1*numF2, groupsize - 1]);
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Bartlett Chi-square statistic: %10.3f', [bartlett]);
|
|
|
|
lReport.Add(' with %d degrees and freedom', [numF1*numF2-1]);
|
|
|
|
lReport.Add(' and probability > value %10.3f', [chiprob]);
|
|
|
|
|
|
|
|
FReportFrame.DisplayReport(lReport);
|
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-11-02 22:58:55 +00:00
|
|
|
end;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
procedure TSRHTestForm.TwoWayPlot(const AResults: TSRHResults);
|
|
|
|
var
|
|
|
|
i, j, idx, numF1, numF2: Integer;
|
|
|
|
item: PChartDataItem;
|
|
|
|
begin
|
|
|
|
FChartFrame.Clear;
|
|
|
|
FChartFrame.SetYTitle('Mean');
|
|
|
|
|
|
|
|
numF1 := Length(F1Labels);
|
|
|
|
numF2 := Length(F2Labels);
|
|
|
|
|
|
|
|
// Chart source for Factor A
|
|
|
|
FChartSources[0].Clear;
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
FChartSources[0].Add(i+1, AResults.RowSums[i] / AResults.RowCount[i], F1Labels[i]);
|
|
|
|
|
|
|
|
// Chart source for Factor B
|
|
|
|
FChartSources[1].Clear;
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
FChartSources[1].Add(j+1, AResults.ColSums[j] / AResults.ColCount[j], F2Labels[j]);
|
|
|
|
|
|
|
|
// Chart source for interaction for Factors A and B: x = Factor 2
|
|
|
|
FChartSources[2].Clear;
|
|
|
|
FChartSources[2].YCount := numF1;
|
|
|
|
for j := 0 to numF2-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
idx := FChartSources[2].Add(j+1, NaN, F2Labels[j]); // y values will be added separately
|
|
|
|
item := FChartSources[2].Item[idx];
|
|
|
|
for i := 0 to numF1-1 do
|
|
|
|
item^.SetY(i, AResults.CellSums[i,j] / AResults.CellCounts[i,j]);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Chart source for interaction for Factors A and B: x = Factor 1
|
|
|
|
FChartSources[3].Clear;
|
|
|
|
FChartSources[3].YCount := numF2;
|
|
|
|
for i := 0 to numF1-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
idx := FChartSources[3].Add(i+1, NaN, F1Labels[i]); // y values will be added separately
|
|
|
|
item := FChartSources[3].Item[idx];
|
|
|
|
for j := 0 to numF2-1 do
|
|
|
|
item^.SetY(j, AResults.CellSums[i,j] / AResults.CellCounts[i,j]);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
// Create series if required
|
|
|
|
if FChartSeries = nil then
|
|
|
|
FChartSeries := FChartFrame.PlotXY(ptLinesAndSymbols, nil, nil, nil, nil, '', DATA_COLORS[0]);
|
|
|
|
|
|
|
|
(FChartSeries as TLineSeries).Styles := ChartStyles;
|
|
|
|
|
|
|
|
// by default display Factor A
|
|
|
|
SelectPlot(FSeriesButtons[0]);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
procedure TSRHTestForm.PrepareStyles(const ALabels: StrDyneVec);
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-11-02 22:58:55 +00:00
|
|
|
i: Integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-02 22:58:55 +00:00
|
|
|
ChartStyles.Styles.Clear;
|
|
|
|
for i := 0 to High(ALabels) do
|
|
|
|
with TChartStyle(ChartStyles.Styles.Add) do
|
|
|
|
begin
|
|
|
|
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
|
|
|
|
Pen.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
|
|
|
|
Text := ALabels[i];
|
|
|
|
UsePen := true;
|
|
|
|
UseBrush := true;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TSRHTestForm.SelectPlot(Sender: TObject);
|
|
|
|
var
|
|
|
|
tb: TToolButton;
|
|
|
|
begin
|
|
|
|
tb := Sender as TToolButton;
|
|
|
|
tb.Down := true;
|
|
|
|
|
2020-11-03 10:45:14 +00:00
|
|
|
if FChartSeries = nil then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
FChartSeries.Source := FChartSources[tb.Tag - 10];
|
2020-11-02 22:58:55 +00:00
|
|
|
case tb.Tag-10 of
|
|
|
|
0: begin // x = Factor 1
|
|
|
|
FChartFrame.SetTitle(Factor1.Text);
|
|
|
|
FChartFrame.SetXTitle('Variable ' + Factor1.Text);
|
|
|
|
FChartFrame.Chart.Legend.Visible := false;
|
|
|
|
FChartSeries.Legend.Multiplicity := lmSingle;
|
|
|
|
end;
|
|
|
|
1: begin // x = Factor 2
|
|
|
|
FChartFrame.SetTitle(Factor2.Text);
|
|
|
|
FChartFrame.SetXTitle('Variable ' + Factor2.Text);
|
|
|
|
FChartFrame.Chart.Legend.Visible := false;
|
|
|
|
FChartSeries.Legend.Multiplicity := lmSingle;
|
|
|
|
end;
|
|
|
|
2: begin // x = Factor 2, multiple curves for all factors 1
|
|
|
|
FChartFrame.SetTitle(Factor1.Text + ' * ' + Factor2.Text);
|
|
|
|
FChartFrame.SetXTitle('Variable ' + Factor2.Text);
|
|
|
|
FChartFrame.Chart.Legend.Visible := true;
|
|
|
|
FChartSeries.Legend.Multiplicity := lmStyle;
|
|
|
|
PrepareStyles(F1Labels);
|
|
|
|
end;
|
|
|
|
3: begin // x = Factor 1, multiple curves for all factors 2
|
|
|
|
FChartFrame.SetTitle(Factor1.Text + ' * ' + Factor2.Text);
|
|
|
|
FChartFrame.SetXTitle('Variable ' + Factor1.Text);
|
|
|
|
FChartFrame.Chart.Legend.Visible := true;
|
|
|
|
FChartSeries.Legend.Multiplicity := lmStyle;
|
|
|
|
PrepareStyles(F2Labels);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-11-02 22:58:55 +00:00
|
|
|
|
2020-11-06 00:04:57 +00:00
|
|
|
FChartFrame.Chart.BottomAxis.Marks{%H-}.Source := FChartSeries.Source;
|
|
|
|
FChartFrame.Chart.BottomAxis.Marks{%H-}.Style := smsLabel;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
procedure TSRHTestForm.Reset;
|
|
|
|
var
|
|
|
|
i : integer;
|
|
|
|
begin
|
2020-11-03 10:45:14 +00:00
|
|
|
FreeAndNil(FChartSeries);
|
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
inherited;
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
if FChartSources[0] <> nil then
|
|
|
|
begin
|
2020-11-03 10:45:14 +00:00
|
|
|
//SelectPlot(FSeriesButtons[0]);
|
2020-11-02 22:58:55 +00:00
|
|
|
for i := 0 to High(FChartSources) do
|
|
|
|
FChartSources[i].Clear;
|
|
|
|
end;
|
|
|
|
|
2020-11-01 23:04:21 +00:00
|
|
|
DepVar.Clear;
|
|
|
|
Factor1.Clear;
|
|
|
|
Factor2.Clear;
|
|
|
|
OverAllalpha.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
|
2020-11-02 22:58:55 +00:00
|
|
|
VarList.Clear;
|
2020-11-01 23:04:21 +00:00
|
|
|
for i := 1 to NoVariables do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i, 0]);
|
|
|
|
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TSRHTestForm.UpdateBtnStates;
|
|
|
|
begin
|
|
|
|
inherited;
|
2020-11-02 22:58:55 +00:00
|
|
|
|
|
|
|
DepIn.Enabled := (VarList.ItemIndex > -1) and (DepVar.Text = '');
|
|
|
|
Fact1In.Enabled := (Varlist.ItemIndex > -1) and (Factor1.Text = '');
|
|
|
|
Fact2In.Enabled := (VarList.ItemIndex > -1) and (Factor2.Text = '');
|
|
|
|
|
|
|
|
DepOut.Enabled := DepVar.Text <> '';
|
|
|
|
Fact1Out.Enabled := Factor1.Text <> '';
|
|
|
|
Fact2Out.Enabled := Factor2.Text <> '';
|
2020-11-01 23:04:21 +00:00
|
|
|
end;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-02 22:58:55 +00:00
|
|
|
function TSRHTestForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
|
|
|
var
|
|
|
|
floatVal: Double;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
|
|
|
|
if DepVar.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := DepVar;
|
|
|
|
AMsg := 'No dependent variable selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if Factor1.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := Factor1;
|
|
|
|
AMsg := 'Factor 1 variable not selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if Factor2.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := Factor2;
|
|
|
|
AMsg := 'Factor 2 variable not selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if OverallAlpha.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := OverallAlpha;
|
|
|
|
AMsg := 'Alpha level not selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if not TryStrToFloat(OverallAlpha.Text, floatVal) or (floatVal <= 0) or (floatVal >= 1) then
|
|
|
|
begin
|
|
|
|
AControl := OverallAlpha;
|
|
|
|
AMsg := 'Alpha level must be a valid number between 0 and 1.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TSRHTestForm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
s: String;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
s := VarList.Items[index];
|
|
|
|
if DepVar.Text = '' then
|
|
|
|
DepVar.Text := s
|
|
|
|
else if Factor1.Text = '' then
|
|
|
|
Factor1.Text := s
|
|
|
|
else if Factor2.Text = '' then
|
|
|
|
Factor2.Text := s;
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TSRHTestForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
end.
|
|
|
|
|