// 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, Globals, BasicStatsReportAndChartFormUnit, ReportFrameUnit, ChartFrameUnit; type { TXvsMultYForm } TXvsMultYForm = class(TBasicStatsReportAndChartForm) LinesBox: TCheckBox; GroupBox1: TGroupBox; Panel1: TPanel; PlotTitleEdit: TEdit; Label4: TLabel; YBox: TListBox; XEdit: TEdit; Label2: TLabel; Label3: TLabel; XInBtn: TBitBtn; YInBtn: TBitBtn; Label1: TLabel; XOutBtn: TBitBtn; YOutBtn: TBitBtn; VarList: TListBox; procedure VarListDblClick(Sender: TObject); procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean); procedure XInBtnClick(Sender: TObject); procedure XOutBtnClick(Sender: TObject); procedure YInBtnClick(Sender: TObject); procedure YOutBtnClick(Sender: TObject); private procedure PlotXY(XValues: DblDyneVec; YValues: DblDyneMat); procedure WriteToReport(const ASelected: IntDyneVec; const ARowLabels, AColLabels: StrDyneVec); protected procedure AdjustConstraints; override; procedure Compute; override; procedure UpdateBtnStates; override; public constructor Create(AOwner: TComponent); override; procedure Reset; override; end; var XvsMultYForm: TXvsMultYForm; implementation {$R *.lfm} uses TAChartUtils, MainUnit, MatrixLib, MathUnit, GridProcs, Utils; { TXvsMultYForm } constructor TXvsMultYForm.Create(AOwner: TComponent); begin inherited; PageControl.ActivePage := ChartPage; end; procedure TXvsMultYForm.Compute; var i, j, N, nY, xCol, NoSelected: integer; xValues: DblDyneVec = nil; yValues: DblDyneMat = nil; RowLabels: StrDyneVec = nil; ColLabels: StrDyneVec = nil; selected: IntDyneVec = nil; 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; xCol := OS3MainFrm.DataGrid.Rows[0].IndexOf(Trim(XEdit.Text)); if xCol = -1 then begin ErrorMsg('X variable not found.'); exit; end; nY := YBox.Items.Count; SetLength(selected, nY + 1); // one more for the x column, needed by Correlations() for j := 0 to nY - 1 do selected[j] := OS3MainFrm.DataGrid.Rows[0].IndexOf(YBox.Items[j]); selected[nY] := xCol; NoSelected := nY + 1; SetLength(RowLabels, NoVariables); SetLength(ColLabels, NoVariables); for i := 0 to NoSelected-1 do begin RowLabels[i] := Trim(OS3MainFrm.DataGrid.Cells[selected[i],0]); ColLabels[i] := RowLabels[i]; end; // Extract x and y values xValues := CollectValues(OS3MainFrm.DataGrid, xCol, selected); SetLength(yValues, nY); for i := 0 to nY-1 do yValues[i] := CollectValues(OS3MainFrm.DataGrid, selected[i], selected); // Make sure that all y columns have the same length N := Length(yValues[0]); for i := 1 to nY-1 do if N <> Length(yValues[i]) then begin ErrorMsg('Different count of cases.'); exit; end; // Print out correclations, means, etc to report frame WriteToReport(selected, RowLabels, ColLabels); // Sort on X SortOnX(XValues, YValues); // Plot x vs multiple y PlotXY(XValues, YValues); end; procedure TXvsMultYForm.AdjustConstraints; begin Panel1.Constraints.MinHeight := YOutBtn.Top + YOutBtn.Height; ParamsPanel.Constraints.MinWidth := 4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left; ParamsPanel.Constraints.MinHeight := Panel1.Constraints.MinHeight + Panel1.BorderSpacing.Bottom + PlotTitleEdit.Height + GroupBox1.Height + 2*GroupBox1.BorderSpacing.Top + ButtonBevel.Height + CloseBtn.Height + CloseBtn.BorderSpacing.Top; Constraints.MinHeight := ParamsPanel.Constraints.MinHeight + 2*ParamsPanel.BorderSpacing.Top; Constraints.MinWidth := ParamsPanel.Constraints.MinWidth + 200; 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 Ny, Nc: Integer; j: Integer; pt: TPlotType; begin // Preparations if LinesBox.Checked then pt := ptLinesAndSymbols else pt := ptSymbols; 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]); if Assigned(FReportFrame) then FReportFrame.Clear; if Assigned(FChartFrame) then FChartFrame.Clear; 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); if Assigned(FReportFrame) then FReportFrame.UpdateBtnStates; if Assigned(FChartFrame) then 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.WriteToReport(const ASelected: IntDyneVec; const ARowLabels, AColLabels: StrDyneVec); var lReport: TStrings; i: Integer; means: DblDyneVec = nil; variances: DblDyneVec = nil; stdDevs: DblDyneVec = nil; RMatrix: DblDyneMat = nil; nSelected: Integer = 0; nCases: Integer = 0; error: Boolean = false; begin lReport := TStringList.Create; try // get descriptive data lReport.Add('X VERSUS MULTIPLE Y VALUES PLOT'); lReport.Add(''); nSelected := Length(ASelected); SetLength(means, nSelected); SetLength(variances, nSelected); SetLength(stdDevs, nSelected); SetLength(RMatrix, nSelected+1, nSelected+1); Correlations(nSelected, ASelected, RMatrix, means, variances, stdDevs, error, nCases); if error then begin lReport.Add('ERROR: zero variance detected.'); exit; end; //DynVectorPrint(means, nSelected, 'MEANS', ARowLabels, nSelected, lReport); //DynVectorPrint(variances, nSelected, 'VARIANCES', ARowLabels, nCases, lReport); //DynVectorPrint(stdDevs, nSelected, 'STANDARD DEVIATIONS', ARowLabels, nCases, lReport); lReport.Add( ' Variable Mean Variance Std.Dev. '); lReport.Add( '--------------- --------------- --------------- ---------------'); for i := 0 to nSelected-1 do lReport.Add('%-15s %15.3f %15.3f %15.3f', [ARowLabels[i], means[i], variances[i], stdDevs[i]]); lReport.Add(''); lReport.Add(''); MatPrint(RMatrix, nSelected, nSelected, 'CORRELATIONS', ARowLabels, AColLabels, nCases, lReport); FReportFrame.DisplayReport(lReport); finally lReport.Free; 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.