You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7868 8e941d3f-bd1b-0410-a28a-d453659cc2b4
832 lines
22 KiB
ObjectPascal
832 lines
22 KiB
ObjectPascal
// File for testing: boltsize.laz, use BoltLngth variable
|
|
|
|
// NOTE: THE OUTPUT DOES NOT EXACTLY MATCH THAT OF THE PDF DOCUMENTATION !!!!
|
|
|
|
unit SensUnit;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
|
StdCtrls, Buttons, ExtCtrls, ComCtrls,
|
|
MainUnit, Globals, FunctionsLib, MatrixLib,
|
|
ReportFrameUnit, ChartFrameUnit, BasicStatsReportFormUnit;
|
|
|
|
type
|
|
|
|
{ TSensForm }
|
|
|
|
TSensForm = class(TBasicStatsReportForm)
|
|
AllBtn: TBitBtn;
|
|
AlphaEdit: TEdit;
|
|
AvgSlopeChk: TCheckBox;
|
|
InBtn: TBitBtn;
|
|
Label1: TLabel;
|
|
Label2: TLabel;
|
|
Label3: TLabel;
|
|
PageControl: TPageControl;
|
|
SelectedList: TListBox;
|
|
OutBtn: TBitBtn;
|
|
RankedSlopesChartPage: TTabSheet;
|
|
DataPage: TTabSheet;
|
|
SlopesMatrixPage: TTabSheet;
|
|
RankedSlopesPage: TTabSheet;
|
|
SlopesPlotPage: TTabSheet;
|
|
RankedSlopesPlotPage: TTabSheet;
|
|
ResultsPage: TTabSheet;
|
|
StandardizeChk: TCheckBox;
|
|
VarList: TListBox;
|
|
PrtRanksChk: TCheckBox;
|
|
PrtSlopesChk: TCheckBox;
|
|
PrtDataChk: TCheckBox;
|
|
GroupBox3: TGroupBox;
|
|
PlotRankedSlopesChk: TCheckBox;
|
|
PlotSlopesChk: TCheckBox;
|
|
GroupBox2: TGroupBox;
|
|
GroupBox1: TGroupBox;
|
|
procedure AllBtnClick(Sender: TObject);
|
|
procedure InBtnClick(Sender: TObject);
|
|
procedure OutBtnClick(Sender: TObject);
|
|
procedure SelectedListDblClick(Sender: TObject);
|
|
procedure VarListDblClick(Sender: TObject);
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
|
private
|
|
FDataReportFrame: TReportFrame;
|
|
FSlopesReportFrame: TReportFrame;
|
|
FRankedSlopesReportFrame: TReportFrame;
|
|
|
|
FSlopesChartFrame: TChartFrame;
|
|
FRankedSlopesChartFrame: TChartFrame;
|
|
|
|
procedure DisplayData(const AValues: DblDyneMat; ANumSelected: Integer;
|
|
const ARowLabels, AColLabels: StrDyneVec);
|
|
|
|
procedure GetData(out ARowLabels, AColLabels: StrDyneVec;
|
|
out ANumSelected: Integer; out ASelected: IntDyneVec;
|
|
out AValues: DblDyneMat);
|
|
|
|
procedure GetMannKendall(AIndex: Integer; const AValues: DblDyneMat;
|
|
out MannKendall: Double; out ANumTies: Integer);
|
|
|
|
function GetMedianSlope(ARankedQ: DblDyneVec): Double;
|
|
|
|
procedure PlotRankedSlopes(AIndex: Integer; const ARankedQ: DblDyneVec; ATitle: String);
|
|
procedure PlotSlopes(AIndex: Integer; const AValues: DblDyneMat; ATitle: String);
|
|
|
|
procedure PrepareChart(AChartFrame: TChartFrame; ATitle, XTitle, YTitle: String);
|
|
|
|
procedure ProcessRankedQ(AReport: TStrings; const ASlopes: DblDyneMat;
|
|
const ATitle: String; out ARankedQ: DblDyneVec);
|
|
|
|
procedure ProcessSlopes(AReport: TStrings; AIndex: Integer;
|
|
const AValues: DblDyneMat; const ARowLabels, AColLabels: StrDyneVec;
|
|
const ATitle: String; out ASlopes: DblDyneMat);
|
|
|
|
procedure StandardizeValuesAndDisplay(AValues: DblDyneMat;
|
|
ASelected: IntDyneVec; ANumSelected: Integer; AReport: TStrings);
|
|
|
|
protected
|
|
procedure AdjustConstraints; override;
|
|
procedure Compute; override;
|
|
procedure UpdateBtnStates; override;
|
|
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
procedure Reset; override;
|
|
end;
|
|
|
|
var
|
|
SensForm: TSensForm;
|
|
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
Math,
|
|
TACustomSeries,
|
|
Utils, MatrixUnit, GridProcs;
|
|
|
|
|
|
{ TSensForm }
|
|
|
|
constructor TSensForm.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
|
|
FReportFrame.Parent := ResultsPage;
|
|
FReportFrame.BorderSpacing.Left := 0;
|
|
FReportFrame.BorderSpacing.Top := 0;
|
|
FReportFrame.BorderSpacing.Right := 0;
|
|
FReportFrame.BorderSpacing.Bottom := 0;
|
|
InitToolbar(FReportFrame.ReportToolbar, tpTop);
|
|
|
|
FDataReportFrame := TReportFrame.Create(self);
|
|
FDataReportFrame.Name := '';
|
|
FDataReportFrame.Parent := DataPage;
|
|
FDataReportFrame.Align := alClient;
|
|
|
|
FSlopesReportFrame := TReportFrame.Create(self);
|
|
FSlopesReportFrame.Name := '';
|
|
FSlopesReportFrame.Parent := SlopesMatrixPage;
|
|
FSlopesReportFrame.Align := alClient;
|
|
|
|
FRankedSlopesReportFrame := TReportFrame.Create(self);
|
|
FRankedSlopesReportFrame.Name := '';
|
|
FRankedSlopesReportFrame.Parent := RankedSlopesPage;
|
|
FRankedSlopesReportFrame.Align := alClient;
|
|
|
|
FSlopesChartFrame := TChartFrame.Create(self);
|
|
FSlopesChartFrame.Parent := SlopesPlotPage;
|
|
FSlopesChartFrame.Align := alClient;
|
|
FSlopesChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80;
|
|
FSlopesChartFrame.Chart.BottomAxis.Intervals.MinLength := 30;
|
|
|
|
FRankedSlopesChartFrame := TChartFrame.Create(self);
|
|
FRankedSlopesChartFrame.Parent := RankedSlopesPlotPage;
|
|
FRankedSlopesChartFrame.Align := alClient;
|
|
FRankedSlopesChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80;
|
|
FRankedSlopesChartFrame.Chart.BottomAxis.Intervals.MinLength := 30;
|
|
|
|
PageControl.ActivePageIndex := 0;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.AdjustConstraints;
|
|
begin
|
|
inherited;
|
|
ParamsPanel.Constraints.MinWidth := Max(
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
|
|
GroupBox1.Width
|
|
);
|
|
ParamsPanel.Constraints.MinHeight := AllBtn.Top + AllBtn.Height +
|
|
VarList.BorderSpacing.Bottom + GroupBox1.Height + GroupBox1.BorderSpacing.Bottom +
|
|
GroupBox3.Height + GroupBox3.BorderSpacing.Bottom +
|
|
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.AllBtnClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to VarList.Items.Count-1 do
|
|
SelectedList.Items.Add(VarList.Items[i]);
|
|
VarList.Clear;
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.Compute;
|
|
var
|
|
NoSelected, count, half, q, tp, low, hi: integer;
|
|
Values: DblDyneMat = nil;
|
|
Slopes: DblDyneMat = nil;
|
|
AvgSlopes: DblDyneMat = nil;
|
|
RankedQ: DblDyneVec = nil;
|
|
RowLabels: StrDyneVec = nil;
|
|
ColLabels: StrDyneVec = nil;
|
|
Selected: IntDyneVec = nil;
|
|
MedianSlope, MannKendall, Z, C, M1, M2, Alpha, mean, stddev: double;
|
|
lTitle: String;
|
|
i, j, k, no2do: integer;
|
|
lReport: TStrings;
|
|
lSlopesReport: TStrings;
|
|
lRankedReport: TStrings;
|
|
begin
|
|
Alpha := 1.0 - StrToFloat(AlphaEdit.Text);
|
|
|
|
// Prepare charts
|
|
if PlotSlopesChk.Checked then
|
|
PrepareChart(FSlopesChartFrame, 'Slopes', 'Time', 'Measure');
|
|
SlopesPlotPage.TabVisible := PlotSlopesChk.Checked;
|
|
|
|
if PlotRankedSlopesChk.Checked then
|
|
PrepareChart(FRankedSlopesChartFrame, 'Ranked Slopes', 'Rank', 'Slope');
|
|
RankedSlopesPlotPage.TabVisible := PlotRankedslopesChk.Checked;
|
|
|
|
// Get the data values from the grid, calc averages if needed.
|
|
GetData(RowLabels, ColLabels, NoSelected, selected, Values);
|
|
|
|
// Print data values
|
|
DisplayData(Values, NoSelected, RowLabels, ColLabels);
|
|
|
|
lReport := TStringList.Create;
|
|
lSlopesReport := TStringList.Create;
|
|
lRankedReport := TStringList.Create;
|
|
try
|
|
lReport.Add('SENS DETECTION AND ESTIMATION OF TRENDS');
|
|
lReport.Add('Number of data points: %4d', [NoCases]);
|
|
lReport.Add('Confidence Interval: %4.2f', [Alpha]);
|
|
|
|
// Standardize if more than one variable and standardization are selected
|
|
if (noSelected > 1) and StandardizeChk.Checked then
|
|
StandardizeValuesAndDisplay(Values, selected, NoSelected, lReport);
|
|
|
|
// Get interval slopes
|
|
if AvgSlopeChk.Checked then
|
|
no2do := NoSelected + 1
|
|
else
|
|
no2do := NoSelected;
|
|
|
|
for j := 0 to no2do-1 do
|
|
begin
|
|
if j < NoSelected then
|
|
lTitle := OS3MainFrm.DataGrid.Cells[selected[j], 0]
|
|
else
|
|
lTitle := 'Combined scores';
|
|
|
|
// Calculate slopes
|
|
ProcessSlopes(lSlopesReport, j, Values, RowLabels, ColLabels, lTitle, Slopes);
|
|
|
|
// Get ranked slopes and median estimator
|
|
ProcessRankedQ(lRankedReport, Slopes, lTitle, RankedQ);
|
|
count := Length(RankedQ);
|
|
|
|
// Get median slope
|
|
MedianSlope := GetMedianSlope(RankedQ);
|
|
|
|
// Get Mann-Kendall statistic based on tied values
|
|
GetMannKendall(j, Values, MannKendall, q);
|
|
Z := InverseZ(Alpha);
|
|
if MannKendall >= 0 then
|
|
begin
|
|
C := Z * sqrt(MannKendall);
|
|
M1 := (count - C) / 2.0;
|
|
M2 := (count + C) / 2.0;
|
|
low := round(M1 - 1.0);
|
|
if ((M1-1) - low) > 0.5 then low := round(M1-1);
|
|
hi := round(M2);
|
|
if (M2 - hi) > 0.5 then hi := round(M2); // ??? wp: This is the same as in the line above
|
|
end;
|
|
|
|
// show results
|
|
lReport.Add('');
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
lReport.Add('');
|
|
if j < noSelected then
|
|
lReport.Add('RESULTS FOR %s', [lTitle])
|
|
else
|
|
lReport.Add('RESULTS FOR AVERAGED VALUES');
|
|
lReport.Add('');
|
|
|
|
if (NoSelected > 1) and StandardizeChk.Checked then
|
|
begin
|
|
mean := 0.0;
|
|
stddev := 0.0;
|
|
for i := 0 to NoCases-1 do
|
|
begin
|
|
mean := mean + Values[i,j];
|
|
stddev := stddev + sqr(Values[i,j]);
|
|
end;
|
|
stddev := stddev - sqr(mean) / NoCases;
|
|
stddev := stddev / (NoCases - 1);
|
|
stddev := sqrt(stddev);
|
|
mean := mean / NoCases;
|
|
lReport.Add('Mean: %8.3f, Standard Deviation: %8.3f', [mean, stddev]);
|
|
end;
|
|
|
|
lReport.Add( 'Median Slope for %d values: %8.3f', [count, MedianSlope]);
|
|
if MannKendall > 0 then begin
|
|
lReport.Add('Mann-Kendall Variance statistic: %8.3f (%d ties)', [MannKendall, q]);
|
|
lReport.Add('Ranks of the lower and upper confidence: %8.3f ... %.3f', [M1, M2+1]);
|
|
if (low > 0) or (hi <= count) then
|
|
lReport.Add('Corresponding lower and upper slopes: %8.3f and %.3f', [RankedQ[low], RankedQ[hi]])
|
|
else
|
|
lReport.Add('INDEX ERROR: low rank = %d, hi rank = %d', [low, hi]);
|
|
end else
|
|
lReport.Add('ERROR: z = %.3f, Mann-Kendall = %.3f', [Z, MannKendall]);
|
|
|
|
// plot slopes if elected
|
|
if PlotSlopesChk.Checked then
|
|
begin
|
|
if j = NoSelected then lTitle := 'Average values';
|
|
PlotSlopes(j, Values, lTitle);
|
|
end;
|
|
|
|
// Plot ranked slopes if elected
|
|
if PlotRankedSlopesChk.Checked then
|
|
PlotRankedSlopes(j, RankedQ,lTitle);
|
|
|
|
end; // next variable j
|
|
|
|
// Average multiple measures
|
|
if AvgSlopeChk.Checked then
|
|
begin
|
|
SetLength(AvgSlopes, NoCases, NoCases);
|
|
for i := 0 to NoCases-2 do
|
|
for k := i + 1 to NoCases-1 do
|
|
AvgSlopes[i,k] := AvgSlopes[i,k] + Slopes[i,k];
|
|
|
|
for i := 0 to NoCases-2 do
|
|
for k := i + 1 to NoCases-1 do
|
|
AvgSlopes[i,k] := AvgSlopes[i,k] / noselected;
|
|
|
|
// Get ranked slopes and median estimator
|
|
count := 0;
|
|
for i := 0 to NoCases-2 do
|
|
begin
|
|
for j := i + 1 to NoCases-1 do
|
|
begin
|
|
RankedQ[count] := AvgSlopes[i,j];
|
|
count := count + 1;
|
|
end;
|
|
end;
|
|
SortOnX(RankedQ);
|
|
|
|
// Get median slope
|
|
half := count div 2;
|
|
if odd(count) then
|
|
MedianSlope := RankedQ[half + 1]
|
|
else
|
|
MedianSlope := (RankedQ[half] + RankedQ[half+1]) / 2.0;
|
|
|
|
// Get Mann-Kendall statistic based on tied values
|
|
MannKendall := 0.0;
|
|
q := 0;
|
|
i := -1;
|
|
while (i < count-1) do
|
|
begin
|
|
i := i + 1;
|
|
tp := 1; // no. of ties for pth (i) value
|
|
for j := i + 1 to count-1 do
|
|
begin
|
|
if RankedQ[j] <> RankedQ[i] then
|
|
begin
|
|
i := j - 1;
|
|
break;
|
|
end else
|
|
tp := tp + 1;
|
|
end;
|
|
if tp > 1 then
|
|
begin
|
|
q := q + 1;
|
|
MannKendall := MannKendall + (tp * (tp-1) * (2 * tp + 5));
|
|
end;
|
|
end; // end do while
|
|
MannKendall := (NoCases * (NoCases-1) * (2 * NoCases + 5) - MannKendall) / 18.0;
|
|
Z := inversez(Alpha);
|
|
if MannKendall >= 0.0 then
|
|
begin
|
|
C := Z * sqrt(MannKendall);
|
|
M1 := (count - C) / 2.0;
|
|
M2 := (count + C) / 2.0;
|
|
low := round(M1) - 1;
|
|
if ((M1-1) - low) > 0.5 then low := round(M1 - 1);
|
|
hi := round(M2);
|
|
if (M2 - hi) > 0.5 then hi := round(M2);
|
|
end;
|
|
|
|
// Show results
|
|
lReport.Add('');
|
|
lReport.Add(DIVIDER_AUTO);
|
|
lReport.Add( '');
|
|
lReport.Add( 'RESULTS FOR AVERAGED SLOPES');
|
|
lReport.Add( '');
|
|
lReport.Add( 'Median Slope for %3d values: %8.3f for averaged measures', [count, MedianSlope]);
|
|
|
|
if MannKendall >= 0 then
|
|
begin
|
|
lReport.Add('Mann-Kendall Variance statistic: %8.3f (%d ties observed)', [MannKendall, q]);
|
|
lReport.Add('Ranks of the lower and upper confidence: %8.3f ... %.3f', [M1, M2]);
|
|
lReport.Add('Corresponding lower and upper slopes: %8.3f and %.3f)', [RankedQ[low],RankedQ[hi]]);
|
|
end else
|
|
lReport.Add('ERROR in calculating Mann-Kendall: %.3f. Cannot be negative.', [MannKendall]);
|
|
end;
|
|
|
|
FReportFrame.DisplayReport(lReport);
|
|
FSlopesReportFrame.DisplayReport(lSlopesReport);
|
|
FRankedSlopesReportFrame.DisplayReport(lRankedReport);
|
|
|
|
finally
|
|
lReport.Free;
|
|
lSlopesReport.Free;
|
|
lRankedReport.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.DisplayData(const AValues: DblDyneMat; ANumSelected: Integer;
|
|
const ARowLabels, AColLabels: StrDyneVec);
|
|
var
|
|
lReport: TStrings;
|
|
begin
|
|
DataPage.TabVisible := PrtDataChk.Checked;
|
|
if PrtDataChk.Checked then
|
|
begin
|
|
lReport := TStringList.Create;
|
|
try
|
|
MatPrint(AValues, NoCases, ANumSelected, 'CASE', ARowLabels, AColLabels, NoCases, lReport);
|
|
FDataReportFrame.DisplayReport(lReport);
|
|
finally
|
|
lReport.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.GetData(out ARowLabels, AColLabels: StrDyneVec;
|
|
out ANumSelected: Integer; out ASelected: IntDyneVec;
|
|
out AValues: DblDyneMat);
|
|
var
|
|
i, j, col: Integer;
|
|
begin
|
|
ARowLabels := nil;
|
|
AColLabels := nil;
|
|
SetLength(ARowLabels, NoCases);
|
|
SetLength(AColLabels, NoCases);
|
|
for i := 0 to NoCases-1 do
|
|
begin
|
|
ARowLabels[i] := OS3MainFrm.DataGrid.Cells[0 ,i+1];
|
|
AColLabels[i] := ARowLabels[i];
|
|
end;
|
|
|
|
ANumSelected := SelectedList.Items.Count;
|
|
|
|
// Get indices of selected variables
|
|
ASelected := nil;
|
|
SetLength(ASelected, ANumSelected);
|
|
for i := 0 to ANumSelected-1 do
|
|
ASelected[i] := GetVariableIndex(OS3MainFrm.DataGrid, SelectedList.Items[i]);
|
|
|
|
// Get the data
|
|
AValues := nil;
|
|
SetLength(AValues, NoCases, ANumSelected+1); // +1 for AvgSlope
|
|
|
|
for j := 0 to ANumSelected-1 do
|
|
begin
|
|
col := ASelected[j];
|
|
for i := 0 to NoCases-1 do
|
|
begin
|
|
AValues[i, j] := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col, i+1]));
|
|
if AvgSlopeChk.Checked then
|
|
AValues[i, ANumSelected] := AValues[i, ANumSelected] + AValues[i, j];
|
|
end;
|
|
end;
|
|
|
|
// average the values if elected
|
|
if AvgSlopeChk.Checked then
|
|
for i := 0 to NoCases - 1 do
|
|
AValues[i, ANumSelected] := AValues[i, ANumSelected] / ANumSelected;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.GetMannKendall(AIndex: Integer; const AValues: DblDyneMat;
|
|
out MannKendall: Double; out ANumTies: Integer);
|
|
var
|
|
i, k, q, tp: Integer;
|
|
sorted: DblDyneVec = nil;
|
|
begin
|
|
SetLength(sorted, NoCases);
|
|
for i := 0 to NoCases-1 do
|
|
sorted[i] := AValues[i, AIndex];
|
|
SortOnX(sorted);
|
|
|
|
MannKendall := 0.0;
|
|
q := 0;
|
|
i := -1;
|
|
while (i < NoCases-2) do
|
|
begin
|
|
i := i + 1;
|
|
tp := 1; // no. of ties for pth (i) value
|
|
for k := i + 1 to NoCases-1 do
|
|
begin
|
|
if Sorted[k] <> Sorted[i] then
|
|
begin
|
|
i := k-1;
|
|
break;
|
|
end else
|
|
tp := tp + 1;
|
|
end; // next k
|
|
|
|
if tp > 1 then
|
|
begin
|
|
q := q + 1;
|
|
MannKendall := MannKendall + (tp * (tp-1) * (2 * tp + 5));
|
|
end;
|
|
end;
|
|
MannKendall := (NoCases * (NoCases-1) * (2 * NoCases + 5) - MannKendall) / 18.0;
|
|
ANumTies := q;
|
|
end;
|
|
|
|
|
|
function TSensForm.GetMedianSlope(ARankedQ: DblDyneVec): Double;
|
|
var
|
|
half, count: Integer;
|
|
begin
|
|
count := Length(ARankedQ);
|
|
half := count div 2;
|
|
if odd(count) then
|
|
Result := ARankedQ[half]
|
|
else
|
|
Result := (ARankedQ[half-1] + ARankedQ[half]) * 0.5;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.InBtnClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := 0;
|
|
while i < VarList.Items.Count do
|
|
begin
|
|
if VarList.Selected[i] then
|
|
begin
|
|
SelectedList.Items.Add(VarList.Items[i]);
|
|
VarList.Items.Delete(i);
|
|
i := 0;
|
|
end else
|
|
i := i + 1;
|
|
end;
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.OutBtnClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := 0;
|
|
while i < SelectedList.Items.Count do
|
|
begin
|
|
if SelectedList.Selected[i] then
|
|
begin
|
|
VarList.Items.Add(SelectedList.Items[i]);
|
|
SelectedList.Items.Delete(i);
|
|
i := 0;
|
|
end else
|
|
i := i + 1;
|
|
end;
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
|
|
// Plot slopes
|
|
procedure TSensForm.PlotSlopes(AIndex: Integer; const AValues: DblDyneMat; ATitle: String);
|
|
var
|
|
ser: TChartSeries;
|
|
i: Integer;
|
|
begin
|
|
ser := FSlopesChartFrame.PlotXY(ptLinesAndSymbols, nil, nil, nil, nil, ATitle,
|
|
DATA_COLORS[AIndex mod Length(DATA_COLORS)]);
|
|
for i := 0 to NoCases - 1 do
|
|
ser.AddXY(i+1, AValues[i, AIndex]);
|
|
end;
|
|
|
|
|
|
procedure TSensForm.PlotRankedSlopes(AIndex: Integer; const ARankedQ: DblDyneVec;
|
|
ATitle: String);
|
|
var
|
|
ser: TChartSeries;
|
|
i, count: Integer;
|
|
begin
|
|
count := Length(ARankedQ);
|
|
ser := FRankedSlopesChartFrame.PlotXY(ptLines, nil, nil, nil, nil, ATitle,
|
|
DATA_COLORS[AIndex mod Length(DATA_COLORS)]);
|
|
for i := 0 to count-1 do
|
|
ser.AddXY(i+1, ARankedQ[i]);
|
|
end;
|
|
|
|
|
|
procedure TSensForm.PrepareChart(AChartFrame: TChartFrame;
|
|
ATitle, XTitle, YTitle: String);
|
|
begin
|
|
AChartFrame.Clear;
|
|
AChartFrame.SetTitle(ATitle);
|
|
AChartFrame.SetXTitle(XTitle);
|
|
AChartFrame.SetYTitle(YTitle);
|
|
end;
|
|
|
|
|
|
procedure TSensForm.ProcessRankedQ(AReport: TStrings; const ASlopes: DblDyneMat;
|
|
const ATitle: String; out ARankedQ: DblDyneVec);
|
|
var
|
|
count: Integer;
|
|
i, k: Integer;
|
|
begin
|
|
ARankedQ := nil;
|
|
SetLength(ARankedQ, 500); // prelimiary dimension to some length, trim later.
|
|
|
|
count := 0;
|
|
for i := 0 to NoCases-2 do
|
|
for k := i+1 to NoCases-1 do
|
|
begin
|
|
ARankedQ[count] := ASlopes[i, k];
|
|
count := count + 1;
|
|
if count = Length(ARankedQ) then
|
|
SetLength(ARankedQ, Length(ARankedQ) + 500);
|
|
end;
|
|
|
|
// Trim to length needed.
|
|
SetLength(ARankedQ, count);
|
|
|
|
// Sort into ascending order
|
|
SortOnX(ARankedQ);
|
|
|
|
if PrtRanksChk.Checked then
|
|
begin
|
|
AReport.Add('RANKED SLOPES FOR ' + ATitle);
|
|
AReport.Add('');
|
|
AReport.Add(' Label Ranked Q');
|
|
AReport.Add('---------- ----------');
|
|
for i := 0 to count-1 do
|
|
AReport.Add('%8d %9.4f', [i+1, ARankedQ[i]]);
|
|
|
|
AReport.Add('');
|
|
AReport.Add(DIVIDER_SMALL_AUTO);
|
|
AReport.Add('');
|
|
end;
|
|
|
|
RankedSlopesPage.TabVisible := PrtRanksChk.Checked;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.ProcessSlopes(AReport: TStrings; AIndex: Integer;
|
|
const AValues: DblDyneMat; const ARowLabels, AColLabels: StrDyneVec;
|
|
const ATitle: String; out ASlopes: DblDyneMat);
|
|
var
|
|
i, k: Integer;
|
|
begin
|
|
ASlopes := nil;
|
|
SetLength(ASlopes, NoCases, NoCases);
|
|
|
|
for i := 0 to NoCases-2 do
|
|
for k := i + 1 to NoCases-1 do
|
|
ASlopes[i,k] := (AValues[k, AIndex] - AValues[i, AIndex]) / (k-i);
|
|
|
|
if PrtSlopesChk.Checked then
|
|
begin
|
|
MatPrint(ASlopes, NoCases, NoCases, ATitle, ARowLabels, AColLabels, NoCases, AReport);
|
|
AReport.Add('');
|
|
AReport.Add(DIVIDER_SMALL_AUTO);
|
|
AReport.Add('');
|
|
end;
|
|
|
|
SlopesMatrixPage.TabVisible := PrtSlopesChk.Checked;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.Reset;
|
|
var
|
|
i: integer;
|
|
begin
|
|
inherited;
|
|
|
|
DataPage.TabVisible := false;
|
|
SlopesMatrixPage.TabVisible := false;
|
|
RankedSlopesPage.TabVisible := false;
|
|
SlopesPlotPage.TabVisible := false;
|
|
RankedSlopesPlotPage.TabVisible := false;
|
|
|
|
if FDataReportFrame <> nil then
|
|
FDataReportFrame.Clear;
|
|
if FSlopesReportFrame <> nil then
|
|
FSlopesReportFrame.Clear;
|
|
if FRankedSlopesReportFrame <> nil then
|
|
FRankedSlopesReportFrame.Clear;
|
|
|
|
if FSlopesChartFrame <> nil then
|
|
FSlopesChartFrame.Clear;
|
|
if FRankedSlopesChartFrame <> nil then
|
|
FRankedSlopesChartFrame.Clear;
|
|
|
|
AlphaEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
|
|
StandardizeChk.Checked := false;
|
|
PlotSlopesChk.Checked := false;
|
|
PlotRankedSlopesChk.Checked := false;
|
|
AvgSlopeChk.Checked := false;
|
|
SelectedList.Clear;
|
|
VarList.Clear;
|
|
for i := 1 to NoVariables do
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.SelectedListDblClick(Sender: TObject);
|
|
var
|
|
index: Integer;
|
|
begin
|
|
index := SelectedList.ItemIndex;
|
|
if index > -1 then
|
|
begin
|
|
VarList.Items.Add(SelectedList.Items[index]);
|
|
SelectedList.Items.Delete(index);
|
|
UpdateBtnStates;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.StandardizeValuesAndDisplay(AValues: DblDyneMat;
|
|
ASelected: IntDyneVec; ANumSelected: Integer; AReport: TStrings);
|
|
var
|
|
i, j: Integer;
|
|
mean, stddev: Double;
|
|
col: Integer;
|
|
begin
|
|
AReport.Add('');
|
|
AReport.Add(' Variable Mean Std.Dev. ');
|
|
AReport.Add('------------ ---------- ----------');
|
|
|
|
for j := 0 to ANumSelected-1 do
|
|
begin
|
|
mean := 0.0;
|
|
stddev := 0.0;
|
|
for i := 0 to NoCases-1 do
|
|
begin
|
|
mean := mean + AValues[i, j];
|
|
stddev := stddev + sqr(AValues[i, j]);
|
|
end;
|
|
stddev := stddev - sqr(mean) / NoCases;
|
|
stddev := stddev / (NoCases - 1);
|
|
stddev := sqrt(stddev);
|
|
mean := mean / NoCases;
|
|
|
|
for i := 0 to NoCases-1 do
|
|
AValues[i,j] := (AValues[i,j] - mean) / stddev;
|
|
|
|
col := ASelected[j];
|
|
AReport.Add('%12s %10.3f %10.3f', [OS3MainFrm.DataGrid.Cells[col, 0], mean, stddev]);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.UpdateBtnStates;
|
|
begin
|
|
inherited;
|
|
|
|
if FDataReportFrame <> nil then
|
|
FDataReportFrame.UpdateBtnStates;
|
|
if FSlopesReportFrame <> nil then
|
|
FSlopesReportFrame.UpdateBtnStates;
|
|
if FRankedSlopesReportFrame <> nil then
|
|
FRankedSlopesReportFrame.UpdateBtnStates;
|
|
|
|
if FSlopesChartFrame <> nil then
|
|
FSlopesChartFrame.UpdateBtnStates;
|
|
if FRankedSlopesChartFrame <> nil then
|
|
FRankedSlopesChartFrame.UpdateBtnStates;
|
|
|
|
InBtn.Enabled := AnySelected(VarList);
|
|
OutBtn.Enabled := AnySelected(SelectedList);
|
|
AllBtn.Enabled := Varlist.Items.Count > 0;
|
|
end;
|
|
|
|
|
|
function TSensForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
|
var
|
|
x: Double;
|
|
begin
|
|
Result := false;
|
|
|
|
if SelectedList.Items.Count = 0 then
|
|
begin
|
|
AMsg := 'First select variables to analyze.';
|
|
AControl := SelectedList;
|
|
exit;
|
|
end;
|
|
|
|
if AlphaEdit.Text = '' then begin
|
|
AControl := AlphaEdit;
|
|
AMsg := 'Input required.';
|
|
exit;
|
|
end;
|
|
|
|
if not TryStrToFloat(AlphaEdit.Text, x) or (x <= 0) or (x >= 1) then
|
|
begin
|
|
AControl := AlphaEdit;
|
|
AMsg := 'Numeric value required in range > 0 and < 1.';
|
|
exit;
|
|
end;
|
|
|
|
Result := true;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.VarListDblClick(Sender: TObject);
|
|
var
|
|
index: Integer;
|
|
begin
|
|
index := VarList.ItemIndex;
|
|
if index > -1 then
|
|
begin
|
|
SelectedList.Items.Add(VarList.Items[index]);
|
|
VarList.Items.Delete(index);
|
|
UpdateBtnStates;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSensForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
begin
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
|
|
end.
|
|
|