Files
lazarus-ccr/applications/lazstats/source/forms/analysis/descriptive/xvsmultyunit.pas

444 lines
10 KiB
ObjectPascal
Raw Normal View History

// Use file "SchoolsData.laz" for testing
unit XvsMultYUnit;
{$MODE objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, ExtCtrls, Printers, ComCtrls,
MainUnit, Globals, ContextHelpUnit, DataProcs, MatrixLib,
ReportFrameUnit, ChartFrameUnit;
type
{ TXvsMultYForm }
TXvsMultYForm = class(TForm)
Bevel2: TBevel;
LinesBox: TCheckBox;
GroupBox1: TGroupBox;
PageControl1: TPageControl;
Panel1: TPanel;
ParamsPanel: TPanel;
ResetBtn: TButton;
ComputeBtn: TButton;
CloseBtn: TButton;
PlotTitleEdit: TEdit;
Label4: TLabel;
HelpBtn: TButton;
ParamsSplitter: TSplitter;
ReportPage: TTabSheet;
ChartPage: TTabSheet;
YBox: TListBox;
XEdit: TEdit;
Label2: TLabel;
Label3: TLabel;
XInBtn: TBitBtn;
YInBtn: TBitBtn;
Label1: TLabel;
XOutBtn: TBitBtn;
YOutBtn: TBitBtn;
VarList: TListBox;
procedure CloseBtnClick(Sender: TObject);
procedure ComputeBtnClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure HelpBtnClick(Sender: TObject);
procedure ResetBtnClick(Sender: TObject);
procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; User: boolean);
procedure XInBtnClick(Sender: TObject);
procedure XOutBtnClick(Sender: TObject);
procedure YInBtnClick(Sender: TObject);
procedure YOutBtnClick(Sender: TObject);
private
{ private declarations }
FReportFrame: TReportFrame;
FChartFrame: TChartFrame;
FAutoSized: Boolean;
selected: IntDyneVec;
procedure PlotXY(XValues: DblDyneVec; YValues: DblDyneMat);
procedure UpdateBtnStates;
public
{ public declarations }
procedure Reset;
end;
var
XvsMultYForm: TXvsMultYForm;
implementation
{$R *.lfm}
uses
TAChartUtils,
Math, Utils;
{ TXvsMultYForm }
procedure TXvsMultYForm.CloseBtnClick(Sender: TObject);
begin
Close;
end;
procedure TXvsMultYForm.ComputeBtnClick(Sender: TObject);
var
i, j, N, NoY, XCol, NoSelected: integer;
MinX, MaxX, MinY, MaxY: double;
Title: string;
RMatrix: DblDyneMat = nil;
XValues: DblDyneVec = nil;
YValues: DblDyneMat = nil;
Means: DblDyneVec = nil;
Variances: DblDyneVec = nil;
StdDevs: DblDyneVec = nil;
RowLabels: StrDyneVec = nil;
ColLabels: StrDyneVec = nil;
errorcode: boolean = false;
Ncases: integer = 0;
lReport: TStrings;
begin
if XEdit.Text = '' then
begin
ErrorMsg('No X variable selected.');
exit;
end;
if YBox.Items.Count = 0 then
begin
ErrorMsg('No Y variables selected.');
exit;
end;
MaxX := -Infinity;
MinX := Infinity;
MaxY := -Infinity;
MinY := Infinity;
NoY := YBox.Items.Count;
SetLength(selected, NoY + 1);
SetLength(RowLabels, NoVariables);
SetLength(ColLabels, NoVariables);
XCol := 0;
for i := 1 to NoVariables do
if Trim(XEdit.Text) = Trim(OS3MainFrm.DataGrid.Cells[i,0]) then
begin
XCol := i;
break;
end;
for j := 0 to NoY-1 do
begin
selected[j] := 0;
for i := 1 to NoVariables do
if Trim(YBox.Items[j]) = Trim(OS3MainFrm.DataGrid.Cells[i,0]) then
begin
selected[j] := i;
Break;
end;
end;
selected[NoY] := XCol;
NoSelected := NoY + 1;
for i := 0 to NoSelected-1 do
begin
RowLabels[i] := Trim(OS3MainFrm.DataGrid.Cells[selected[i],0]);
ColLabels[i] := RowLabels[i];
end;
Caption := RowLabels[0] + ' ' + RowLabels[1];
lReport := TStringList.Create;
try
SetLength(YValues, NoY, NoCases);
SetLength(XValues, NoCases);
SetLength(Means, NoSelected);
SetLength(Variances, NoSelected);
SetLength(StdDevs, NoSelected);
SetLength(RMatrix, NoSelected+1, NoSelected+1);
SetLength(selected, NoVariables+1);
for i := 0 to NoSelected - 1 do
begin
Means[i] := 0.0;
StdDevs[i] := 0.0;
for j := 0 to NoSelected-1 do RMatrix[i,j] := 0.0;
end;
N := 0;
// index rule: array index: i, grid-related index: i+1
for i := 0 to NoCases-1 do
begin
if not GoodRecord(i+1, NoSelected, selected) then continue;
inc(N);
XValues[i] := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[XCol, i+1]));
MaxX := Max(MaxX, XValues[i]);
MinX := Min(MinX, XValues[i]);
for j := 0 to NoY - 1 do
begin
// Unlike other usages of 2-D arrays in LazStats the 1st index is the
// curve index while the 2nd index is the point index here.
YValues[j, i] := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[selected[j], i+1]));
MaxY := Max(MaxY, YValues[j, i]);
MinY := Min(MinY, YValues[j, i]);
end;
end;
// get descriptive data
lReport.Add('X VERSUS MULTIPLE Y VALUES PLOT');
lReport.Add('');
Correlations(NoSelected,selected,RMatrix,Means,Variances,StdDevs,errorcode,Ncases);
//N := Ncases;
Title := 'CORRELATIONS';
MatPrint(RMatrix, NoSelected, NoSelected, Title, RowLabels, ColLabels, N, lReport);
Title := 'Means';
DynVectorPrint(Means, NoSelected, Title, RowLabels, N, lReport);
Title := 'Variances';
DynVectorPrint(Variances, NoSelected, Title, RowLabels, N, lReport);
Title := 'Standard Deviations';
DynVectorPrint(StdDevs, NoSelected, Title, RowLabels, N, lReport);
FReportFrame.DisplayReport(lReport);
// Sort on X
SortOnX(XValues, YValues);
// Plot x vs multiple y
PlotXY(XValues, YValues);
finally
lReport.Free;
RMatrix := nil;
StdDevs := nil;
Variances := nil;
Means := nil;
XValues := nil;
YValues := nil;
selected := nil;
ColLabels := nil;
RowLabels := nil;
end;
end;
procedure TXvsMultYForm.FormActivate(Sender: TObject);
var
w: Integer;
begin
if FAutoSized then
exit;
w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]);
HelpBtn.Constraints.MinWidth := w;
ResetBtn.Constraints.MinWidth := w;
ComputeBtn.Constraints.MinWidth := w;
CloseBtn.Constraints.MinWidth := w;
Panel1.Constraints.MinHeight := YOutBtn.Top + YOutBtn.Height;
ParamsPanel.Constraints.MinWidth := 4*w + 3*CloseBtn.BorderSpacing.Left;
ParamsPanel.Constraints.MinHeight := Panel1.Constraints.MinHeight + Panel1.BorderSpacing.Bottom +
PlotTitleEdit.Height + GroupBox1.Height + 2*GroupBox1.BorderSpacing.Top +
Bevel2.Height + CloseBtn.Height + CloseBtn.BorderSpacing.Top;
Constraints.MinHeight := ParamsPanel.Constraints.MinHeight + 2*ParamsPanel.BorderSpacing.Top;
Constraints.MinWidth := ParamsPanel.Constraints.MinWidth + 200;
if Height < Constraints.MinHeight then Height := 1; // enforce autosizing if needed
if Width < Constraints.MinWidth then Width :=1;
Position := poDesigned;
FAutoSized := true;
end;
procedure TXvsMultYForm.FormCreate(Sender: TObject);
begin
Assert(OS3MainFrm <> nil);
InitForm(self);
FReportFrame := TReportFrame.Create(self);
FReportFrame.Parent := ReportPage;
FReportFrame.Align := alClient;
FChartFrame := TChartFrame.Create(self);
FChartFrame.Parent := ChartPage;
FChartFrame.Align := alClient;
FChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80;
FChartFrame.Chart.BottomAxis.Intervals.MinLength := 30;
Reset;
end;
procedure TXvsMultYForm.HelpBtnClick(Sender: TObject);
begin
if ContextHelpForm = nil then
Application.CreateForm(TContextHelpForm, ContextHelpForm);
ContextHelpForm.HelpMessage((Sender as TButton).Tag);
end;
// Routine to plot X versus multiple Y values
// Unlike many other routines in LazStats the curve index in YValues is the
// first one, the point index is the second one.
procedure TXvsMultYForm.PlotXY(XValues: DblDyneVec; YValues: DblDyneMat);
var
N, Ny, Nc: Integer;
j: Integer;
pt: TPlotType;
begin
// Preparations
if LinesBox.Checked then pt := ptLinesAndSymbols else pt := ptSymbols;
N := Length(XValues);
Ny := Length(YValues);
Nc := Length(DATA_COLORS);
FChartFrame.Clear;
// Titles
FChartFrame.SetTitle(PlotTitleEdit.Text);
FChartFrame.SetXTitle(XEdit.Text);
FChartFrame.SetYTitle('Y Values');
// Plot a series for each y value
for j := 0 to Ny - 1 do
FChartFrame.PlotXY(pt, XValues, YValues[j], nil, nil, Trim(YBox.Items[j]), DATA_COLORS[j mod Nc]);
end;
procedure TXvsMultYForm.Reset;
var
i: integer;
begin
VarList.Clear;
YBox.Clear;
XEdit.Clear;
XInBtn.Enabled := true;
XOutBtn.Enabled := false;
YInBtn.Enabled := true;
YOutBtn.Enabled := false;
PlotTitleEdit.Text := '';
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
end;
procedure TXvsMultYForm.ResetBtnClick(Sender: TObject);
begin
Reset;
end;
procedure TXvsMultYForm.UpdateBtnStates;
var
lSelected: Boolean;
begin
lSelected := AnySelected(VarList);
XInBtn.Enabled := lSelected and (XEdit.Text = '');
YInBtn.Enabled := lSelected;
xOutBtn.Enabled := (XEdit.Text <> '');
YOutBtn.Enabled := AnySelected(YBox);
FReportFrame.UpdateBtnStates;
FChartFrame.UpdateBtnStates;
end;
procedure TXvsMultYForm.VarListDblClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if index > -1 then
begin
if XEdit.Text = '' then
XEdit.Text := VarList.Items[index]
else
YBox.Items.Add(VarList.Items[index]);
VarList.Items.Delete(index);
UpdateBtnStates;
end;
end;
procedure TXvsMultYForm.VarListSelectionChange(Sender: TObject; User: boolean);
begin
UpdateBtnStates;
end;
procedure TXvsMultYForm.XInBtnClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (XEdit.Text = '') then
begin
XEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TXvsMultYForm.XOutBtnClick(Sender: TObject);
begin
if (XEdit.Text <> '') then
begin
VarList.Items.Add(XEdit.Text);
XEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TXvsMultYForm.YInBtnClick(Sender: TObject);
var
i: integer;
begin
i := 0;
while i < VarList.Items.Count do
begin
if VarList.Selected[i] then
begin
YBox.Items.Add(VarList.Items[i]);
VarList.Items.Delete(i);
i := 0;
end else
inc(i);
end;
UpdateBtnStates;
end;
procedure TXvsMultYForm.YOutBtnClick(Sender: TObject);
var
i: integer;
begin
i := 0;
while i < YBox.Items.Count do
begin
if (YBox.Selected[i]) then
begin
VarList.Items.Add(YBox.Items[i]);
YBox.Items.Delete(i);
i := 0;
end else
i := i + 1;
end;
UpdateBtnStates;
end;
end.