Files
lazarus-ccr/applications/lazstats/source/forms/analysis/nonparametric/sensunit.pas
2020-11-14 12:43:20 +00:00

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.