LazStats: Refactor GroupFreqUnit (to inherit from TBasicStatsChartForm).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7726 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-10-01 14:06:47 +00:00
parent 8df06eb3c3
commit 349f9b039b
3 changed files with 396 additions and 384 deletions

View File

@@ -63,3 +63,4 @@ correlation, means, standard deviations and confidence interval for each correla
159=Directions: Firs, click in the variable name that represents the sample lot numbers. Next, click on the variable that represents the measurement. Click on the sigma button to change the default and click on any of the optional check boxes and enter specifications desired. Click the Compute button to obtain the results. 159=Directions: Firs, click in the variable name that represents the sample lot numbers. Next, click on the variable that represents the measurement. Click on the sigma button to change the default and click on any of the optional check boxes and enter specifications desired. Click the Compute button to obtain the results.
160=Correspondence analysis is a method for examining the relationship between two sets of categorical variables much as in a Chi-Squared analysis of a two-way contingency table. In fact, a typical chi-squared analysis is completed as part of this procedure. In addition, visualization of the relationships among the columns or rows of the analysis is performed in a manner similar to factor analysis. The data analyzed in the visualization is the table of relative proportions, that is, the original frequency values divided by the sum of all frequencies. The relative proportions of the row sums and the column sums are termed the �masses� of the rows or columns. The method used to analyze the relative proportions involves what is now called the �Generalized Singular Value Decomposition� or more simply the generalized SVD. This method obtains roots and vectors of a rectangular matrix by decomposing that matrix into three portions: a matrix of left singular column vectors (A) that has n rows and q columns (n � q), a square diagonal matrix with q rows and columns of singular values (D), and a transposed matrix (B�) that is m x q in size of right generalized singular vectors (m = q-1). Completing this analysis involves several steps. The first is to obtain the (regular) SVD analysis of a matrix Q defined as Dr-1/2PDc -1/2 where Dr and Dc are diagonal matrices of row and column relative proportions and P is the matrix of relative proportions. The SVD of Q gives Q = U D V� where D is the desired diagonal matrix of eigenvalues and U�U = V�V = I. It should be noted that the first of the q roots is trivial and to be ignored. At this point we obtain A = Dr1/2U and B = Dc 1/2 V. The results of this SVD analysis is available on the output. Now P = ADB�. The row coordinates F and column coordinates G are then computed according to the table: Analysis Choice Button Selected Row Coordinates Column Coordinates Row Profile Row F = Dr-1AD G = Dc-1B Column Profile Column F = Dr-1A G = Dc-1BD Both Profiles Both F = Dr-1AD G = Dc-1BD If Row profiles are computed, the row coordinates are weighted centroids of the column coordinates and the inertias D2 refer only to the row points. If the column profiles are computed, the column coordinates are weighted eentroids of the row coordinates and the inertias D2 refer only to the column points. If both profiles are selected, neither row or column coordinates are weighted centroids of the other but the inertias D2 refer to both sets of points. The q-1 inertias are plotted in a manner similar to a scree plot of roots in a factor analysis. The total inertia is, in fact, the chi-squared statistic divided by the total of all cell frequencies. You may elect to plot the coordinates for any two pairs of coordinates. This will provide a graphical representation of the separation of the row or column categories similar to a plot of variables in a discriminant function analysis or factors in a factor analysis. A way of looking at correspondence analysis is to consider it as a method for decomposing the overall inertia by identifying a small number of dimensions in which the deviations from the expected values can be represented. This is similar to factor analysis where the total variance is decomposed so as to arrive at a lower dimensional representation of variables. 160=Correspondence analysis is a method for examining the relationship between two sets of categorical variables much as in a Chi-Squared analysis of a two-way contingency table. In fact, a typical chi-squared analysis is completed as part of this procedure. In addition, visualization of the relationships among the columns or rows of the analysis is performed in a manner similar to factor analysis. The data analyzed in the visualization is the table of relative proportions, that is, the original frequency values divided by the sum of all frequencies. The relative proportions of the row sums and the column sums are termed the �masses� of the rows or columns. The method used to analyze the relative proportions involves what is now called the �Generalized Singular Value Decomposition� or more simply the generalized SVD. This method obtains roots and vectors of a rectangular matrix by decomposing that matrix into three portions: a matrix of left singular column vectors (A) that has n rows and q columns (n � q), a square diagonal matrix with q rows and columns of singular values (D), and a transposed matrix (B�) that is m x q in size of right generalized singular vectors (m = q-1). Completing this analysis involves several steps. The first is to obtain the (regular) SVD analysis of a matrix Q defined as Dr-1/2PDc -1/2 where Dr and Dc are diagonal matrices of row and column relative proportions and P is the matrix of relative proportions. The SVD of Q gives Q = U D V� where D is the desired diagonal matrix of eigenvalues and U�U = V�V = I. It should be noted that the first of the q roots is trivial and to be ignored. At this point we obtain A = Dr1/2U and B = Dc 1/2 V. The results of this SVD analysis is available on the output. Now P = ADB�. The row coordinates F and column coordinates G are then computed according to the table: Analysis Choice Button Selected Row Coordinates Column Coordinates Row Profile Row F = Dr-1AD G = Dc-1B Column Profile Column F = Dr-1A G = Dc-1BD Both Profiles Both F = Dr-1AD G = Dc-1BD If Row profiles are computed, the row coordinates are weighted centroids of the column coordinates and the inertias D2 refer only to the row points. If the column profiles are computed, the column coordinates are weighted eentroids of the row coordinates and the inertias D2 refer only to the column points. If both profiles are selected, neither row or column coordinates are weighted centroids of the other but the inertias D2 refer to both sets of points. The q-1 inertias are plotted in a manner similar to a scree plot of roots in a factor analysis. The total inertia is, in fact, the chi-squared statistic divided by the total of all cell frequencies. You may elect to plot the coordinates for any two pairs of coordinates. This will provide a graphical representation of the separation of the row or column categories similar to a plot of variables in a discriminant function analysis or factors in a factor analysis. A way of looking at correspondence analysis is to consider it as a method for decomposing the overall inertia by identifying a small number of dimensions in which the deviations from the expected values can be represented. This is similar to factor analysis where the total variance is decomposed so as to arrive at a lower dimensional representation of variables.
161=Directions:\n(1) Select the X variable common to all of the Y variables to be selected.\n(2) Select the Y variables.\n(3) Enter a label for the plot.\n(4) Select the options desired.\n(5) Click the Compute button to obtain results. 161=Directions:\n(1) Select the X variable common to all of the Y variables to be selected.\n(2) Select the Y variables.\n(3) Enter a label for the plot.\n(4) Select the options desired.\n(5) Click the Compute button to obtain results.
162=This procedure plots the frequency of cases in each of the groups in a group variable. The group variable should be defined as an integer variable.\n\nSelect the variable and type of plot and click the Compute button for the results.

View File

@@ -1,222 +1,189 @@
object GroupFreqForm: TGroupFreqForm inherited GroupFreqForm: TGroupFreqForm
Left = 513 Height = 212
Height = 341
Top = 233
Width = 444
HelpType = htKeyword
HelpKeyword = 'html/GroupFrequencyHistograms.htm'
AutoSize = True
Caption = 'Group Frequency Analysis' Caption = 'Group Frequency Analysis'
ClientHeight = 341 ClientHeight = 212
ClientWidth = 444 inherited ParamsPanel: TPanel
OnActivate = FormActivate Height = 196
OnCreate = FormCreate ClientHeight = 196
OnShow = ResetBtnClick inherited CloseBtn: TButton
Position = poMainFormCenter Top = 171
LCLVersion = '2.0.10.0' end
object Label1: TLabel inherited ComputeBtn: TButton
AnchorSideLeft.Control = Owner Top = 171
AnchorSideTop.Control = Memo1 end
AnchorSideTop.Side = asrBottom inherited ResetBtn: TButton
Left = 8 Top = 171
end
inherited HelpBtn: TButton
Tag = 162
Top = 171
end
inherited ButtonBevel: TBevel
Top = 155
end
object Label1: TLabel[5]
AnchorSideLeft.Control = ParamsPanel
AnchorSideTop.Control = ParamsPanel
Left = 0
Height = 15 Height = 15
Top = 84 Top = 0
Width = 100 Width = 100
BorderSpacing.Left = 8
BorderSpacing.Top = 16
Caption = 'Available Variables:' Caption = 'Available Variables:'
ParentColor = False ParentColor = False
end end
object Label2: TLabel object VarList: TListBox[6]
AnchorSideLeft.Control = GrpInBtn AnchorSideLeft.Control = ParamsPanel
AnchorSideLeft.Side = asrBottom
AnchorSideBottom.Control = GrpVarEdit
Left = 237
Height = 15
Top = 109
Width = 77
Anchors = [akLeft, akBottom]
BorderSpacing.Left = 12
BorderSpacing.Bottom = 2
Caption = 'Group Variable'
ParentColor = False
end
object VarList: TListBox
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = Label1 AnchorSideTop.Control = Label1
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = GrpInBtn AnchorSideRight.Control = GrpInBtn
AnchorSideBottom.Control = Bevel1 AnchorSideBottom.Control = ButtonBevel
Left = 8 Left = 0
Height = 191 Height = 138
Top = 101 Top = 17
Width = 181 Width = 126
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 8
BorderSpacing.Top = 2 BorderSpacing.Top = 2
BorderSpacing.Right = 8 BorderSpacing.Right = 6
ItemHeight = 0 ItemHeight = 0
OnDblClick = VarListDblClick
OnSelectionChange = VarListSelectionChange OnSelectionChange = VarListSelectionChange
TabOrder = 0 TabOrder = 4
end end
object GrpInBtn: TBitBtn object GrpInBtn: TBitBtn[7]
AnchorSideLeft.Control = PlotOptionsBox AnchorSideLeft.Control = ParamsPanel
AnchorSideLeft.Side = asrCenter
AnchorSideTop.Control = VarList AnchorSideTop.Control = VarList
Left = 197 Left = 132
Height = 28 Height = 26
Top = 101 Top = 17
Width = 28 Width = 26
Images = MainDataModule.ImageList Images = MainDataModule.ImageList
ImageIndex = 1 ImageIndex = 1
OnClick = GrpInBtnClick OnClick = GrpInBtnClick
Spacing = 0 Spacing = 0
TabOrder = 1 TabOrder = 5
end end
object GrpOutBtn: TBitBtn object GrpOutBtn: TBitBtn[8]
AnchorSideLeft.Control = GrpInBtn AnchorSideLeft.Control = ParamsPanel
AnchorSideLeft.Side = asrCenter
AnchorSideTop.Control = GrpInBtn AnchorSideTop.Control = GrpInBtn
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
Left = 197 Left = 132
Height = 28 Height = 26
Top = 133 Top = 47
Width = 28 Width = 26
BorderSpacing.Top = 4 BorderSpacing.Top = 4
Images = MainDataModule.ImageList Images = MainDataModule.ImageList
ImageIndex = 0 ImageIndex = 0
OnClick = GrpOutBtnClick OnClick = GrpOutBtnClick
Spacing = 0 Spacing = 0
TabOrder = 2 TabOrder = 6
end end
object GrpVarEdit: TEdit object Label2: TLabel[9]
AnchorSideLeft.Control = Label2 AnchorSideLeft.Control = GrpVarEdit
AnchorSideBottom.Control = GrpVarEdit
Left = 164
Height = 15
Top = 21
Width = 77
Anchors = [akLeft, akBottom]
BorderSpacing.Bottom = 2
Caption = 'Group Variable'
ParentColor = False
end
object GrpVarEdit: TEdit[10]
AnchorSideLeft.Control = GrpInBtn
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner AnchorSideRight.Control = ParamsPanel
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = GrpOutBtn AnchorSideBottom.Control = GrpOutBtn
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 237 Left = 164
Height = 23 Height = 23
Top = 126 Top = 38
Width = 199 Width = 127
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Left = 6
BorderSpacing.Top = 2 BorderSpacing.Top = 2
BorderSpacing.Right = 8
BorderSpacing.Bottom = 12 BorderSpacing.Bottom = 12
ReadOnly = True ReadOnly = True
TabOrder = 3 TabOrder = 7
Text = 'GrpVarEdit' Text = 'GrpVarEdit'
end end
object ResetBtn: TButton object PlotOptionsGroup: TGroupBox[11]
AnchorSideTop.Control = CloseBtn
AnchorSideRight.Control = ComputeBtn
Left = 235
Height = 25
Top = 308
Width = 54
Anchors = [akTop, akRight]
AutoSize = True
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Reset'
OnClick = ResetBtnClick
TabOrder = 5
end
object ComputeBtn: TButton
AnchorSideTop.Control = CloseBtn
AnchorSideRight.Control = CloseBtn
Left = 297
Height = 25
Top = 308
Width = 76
Anchors = [akTop, akRight]
AutoSize = True
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Compute'
OnClick = ComputeBtnClick
TabOrder = 6
end
object CloseBtn: TButton
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 381
Height = 25
Top = 308
Width = 55
Anchors = [akRight, akBottom]
AutoSize = True
BorderSpacing.Top = 8
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Close'
ModalResult = 11
OnClick = CloseBtnClick
TabOrder = 7
end
object PlotOptionsBox: TRadioGroup
AnchorSideLeft.Control = GrpInBtn AnchorSideLeft.Control = GrpInBtn
AnchorSideTop.Control = GrpOutBtn AnchorSideTop.Control = GrpOutBtn
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner Left = 132
AnchorSideRight.Side = asrBottom Height = 79
Left = 197 Top = 97
Height = 114 Width = 147
Top = 177
Width = 239
Anchors = [akTop, akRight]
AutoFill = True
AutoSize = True AutoSize = True
BorderSpacing.Top = 16 BorderSpacing.Top = 24
BorderSpacing.Right = 8 Caption = 'Plot Options'
Caption = 'Plot Options:' ClientHeight = 59
ChildSizing.LeftRightSpacing = 12 ClientWidth = 143
ChildSizing.TopBottomSpacing = 6 TabOrder = 8
ChildSizing.VerticalSpacing = 2 object VertBarsBtn: TSpeedButton
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize AnchorSideLeft.Control = PlotOptionsGroup
ChildSizing.EnlargeVertical = crsHomogenousChildResize AnchorSideTop.Control = PlotOptionsGroup
ChildSizing.ShrinkHorizontal = crsScaleChilds Left = 12
ChildSizing.ShrinkVertical = crsScaleChilds Height = 22
ChildSizing.Layout = cclLeftToRightThenTopToBottom Top = 4
ChildSizing.ControlsPerLine = 1 Width = 23
ClientHeight = 94 BorderSpacing.Left = 12
ClientWidth = 235 BorderSpacing.Top = 4
Items.Strings = ( BorderSpacing.Bottom = 6
'Plot means using 2D Horizontal Bars' Down = True
'Plot means using 3D Horizontal Bars' GroupIndex = 1
'Plot means using 2D Vertical Bars' Images = MainDataModule.ImageList
'Plot means using 3D Vertical Bars' ImageIndex = 8
)
TabOrder = 4
end end
object Bevel1: TBevel object HorBarsBtn: TSpeedButton
AnchorSideLeft.Control = Owner AnchorSideLeft.Control = VertBarsBtn
AnchorSideRight.Control = Owner AnchorSideLeft.Side = asrBottom
AnchorSideRight.Side = asrBottom AnchorSideTop.Control = PlotOptionsGroup
AnchorSideBottom.Control = CloseBtn Left = 39
Left = 0 Height = 22
Height = 8 Top = 4
Top = 292 Width = 23
Width = 444 BorderSpacing.Left = 4
Anchors = [akLeft, akRight, akBottom] BorderSpacing.Top = 4
Shape = bsBottomLine GroupIndex = 1
Images = MainDataModule.ImageList
ImageIndex = 9
end end
object Memo1: TLabel object ThreeDChk: TCheckBox
AnchorSideLeft.Control = Owner AnchorSideLeft.Control = HorBarsBtn
AnchorSideTop.Control = Owner AnchorSideLeft.Side = asrBottom
AnchorSideRight.Control = Owner AnchorSideTop.Control = VertBarsBtn
AnchorSideRight.Side = asrBottom AnchorSideTop.Side = asrCenter
Left = 8 Left = 94
Height = 60 Height = 19
Top = 8 Top = 6
Width = 428 Width = 34
Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 32
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 8 BorderSpacing.Right = 8
Caption = 'This procedure plots the frequency of cases in each of the groups in a group variable. The group variable should be defined as an integer variable.'#13#10#13#10'Select the variable and type of plot and click the Compute button for the results.' Caption = '3D'
ParentColor = False TabOrder = 0
WordWrap = True end
object ShowValuesChk: TCheckBox
AnchorSideLeft.Control = VertBarsBtn
AnchorSideTop.Control = VertBarsBtn
AnchorSideTop.Side = asrBottom
Left = 12
Height = 19
Top = 32
Width = 123
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Show values at bars'
TabOrder = 1
end
end
end
inherited ParamsSplitter: TSplitter
Height = 212
end end
end end

View File

@@ -5,41 +5,44 @@ unit GroupFreqUnit;
interface interface
uses uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons,
StdCtrls, Buttons, ExtCtrls, ExtCtrls, StdCtrls, LCLVersion,
MainUnit, GraphLib, Globals, DataProcs; TASources,
Globals, MainUnit, MainDM, BasicStatsChartFormUnit;
type type
{ TGroupFreqForm } { TGroupFreqForm }
TGroupFreqForm = class(TForm) TGroupFreqForm = class(TBasicStatsChartForm)
Bevel1: TBevel; ShowValuesChk: TCheckBox;
GrpInBtn: TBitBtn; GrpInBtn: TBitBtn;
GrpOutBtn: TBitBtn; GrpOutBtn: TBitBtn;
ComputeBtn: TButton;
GrpVarEdit: TEdit; GrpVarEdit: TEdit;
HorBarsBtn: TSpeedButton;
Label1: TLabel; Label1: TLabel;
Label2: TLabel; Label2: TLabel;
Memo1: TLabel; PlotOptionsGroup: TGroupBox;
PlotOptionsBox: TRadioGroup; ThreeDChk: TCheckBox;
ResetBtn: TButton;
CloseBtn: TButton;
VarList: TListBox; VarList: TListBox;
procedure CloseBtnClick(Sender: TObject); VertBarsBtn: TSpeedButton;
procedure ComputeBtnClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure GrpInBtnClick(Sender: TObject); procedure GrpInBtnClick(Sender: TObject);
procedure GrpOutBtnClick(Sender: TObject); procedure GrpOutBtnClick(Sender: TObject);
procedure ResetBtnClick(Sender: TObject); procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; User: boolean); procedure VarListSelectionChange(Sender: TObject; User: boolean);
private private
{ private declarations } FLabelsSource: TListChartSource;
FAutoSized: Boolean;
procedure UpdateBtnStates; procedure UpdateBtnStates;
protected
procedure AdjustConstraints; override;
procedure Compute; override;
procedure Plot(XLabels: StrDyneVec; FreqValues: DblDyneVec; XTitle: String);
public public
{ public declarations } constructor Create(AOwner: TComponent); override;
procedure Reset; override;
end; end;
var var
@@ -47,22 +50,90 @@ var
implementation implementation
{$R *.lfm}
uses uses
Math; Math,
TAChartUtils, TACustomSeries, TASeries,
Utils, DataProcs, ChartFrameUnit;
{ TGroupFreqForm } { TGroupFreqForm }
procedure TGroupFreqForm.ResetBtnClick(Sender: TObject); constructor TGroupFreqForm.Create(AOwner: TComponent);
var
i: integer;
begin begin
VarList.Clear; inherited;
for i := 1 to NoVariables do FLabelsSource := TListChartSource.Create(self);
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
GrpVarEdit.Text := '';
UpdateBtnStates;
end; end;
procedure TGroupFreqForm.AdjustConstraints;
begin
ParamsPanel.Constraints.MinWidth := MaxValue( [
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
(PlotOptionsGroup.Width - GrpInBtn.Width div 2 + GrpVarEdit.BorderSpacing.Left)*2,
(Max(Label1.Width, Label2.Width) + GrpvarEdit.BorderSpacing.Left) * 2
]);
ParamsPanel.Constraints.MinHeight := PlotOptionsGroup.Top + PlotOptionsGroup.Height +
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
Constraints.MinWidth := ParamsPanel.Constraints.MinWidth + 300;
Constraints.MinHeight := ParamsPanel.Constraints.MinHeight + ParamsPanel.BorderSpacing.Top * 2;
end;
procedure TGroupFreqForm.Compute;
VAR
nogroups, mingrp, maxgrp, grpcol, minfreq, maxfreq: integer;
cellStr: string;
i, numValues, valueIdx: integer;
freq: DblDyneVec = nil; // Could be IntDyneVec, but easier plotting with Dbl
values: StrDyneVec = nil;
begin
// get the variable to analyze
grpcol := 0;
for i := 1 to NoVariables do
if GrpVarEdit.Text = OS3MainFrm.DataGrid.Cells[i,0] then
begin
grpcol := i;
break;
end;
if grpcol = 0 then
begin
MessageDlg('No variable selected.', mtError, [mbOK], 0);
exit;
end;
SetLength(values, NoCases); // over-dimension values array; will be trimmed.
numvalues := 0;
for i := 1 to NoCases do
begin
cellStr := Trim(OS3MainFrm.DataGrid.Cells[grpcol,i]);
if IndexOfString(values, cellStr) = -1 then begin
values[numValues] := cellStr;
inc(numvalues);
end;
end;
SetLength(values, numValues); // Trim values array to correct length
// setup frequency array and count cases in each group
SetLength(freq, numvalues);
for i := 1 to NoCases do
begin
if not ValidValue(i, grpcol) then continue;
cellStr := Trim(OS3MainFrm.DataGrid.Cells[grpcol, i]);
valueIdx := IndexOfString(values, cellStr);
if valueIdx > -1 then
freq[valueIdx] := freq[valueIdx] + 1
else
raise Exception.Create('Value index not found.'); // this should not happen
end;
// Plot frequency data
Plot(values, freq, GrpVarEdit.Text);
end;
procedure TGroupFreqForm.GrpInBtnClick(Sender: TObject); procedure TGroupFreqForm.GrpInBtnClick(Sender: TObject);
var var
index: integer; index: integer;
@@ -76,141 +147,6 @@ begin
UpdateBtnStates; UpdateBtnStates;
end; end;
procedure TGroupFreqForm.ComputeBtnClick(Sender: TObject);
VAR
nogroups, mingrp, maxgrp, grpcol, value, minfreq, maxfreq: integer;
labelstr: string;
i: integer;
strvalue: string;
freq: IntDyneVec;
plottype: integer;
begin
// get the variable to analyze
grpcol := 0;
for i := 1 to NoVariables do
begin
strvalue := OS3MainFrm.DataGrid.Cells[i,0];
if GrpVarEdit.Text = strvalue then
begin
grpcol := i;
break;
end;
end;
if grpcol = 0 then
begin
MessageDlg('No variable selected.', mtError, [mbOK], 0);
exit;
end;
labelstr := GrpVarEdit.Text;
mingrp := 1000;
maxgrp := -1000;
for i := 1 to NoCases do
begin
if not ValidValue(i,grpcol) then continue;
value := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[grpcol,i])));
if value < mingrp then mingrp := value;
if value > maxgrp then maxgrp := value;
end;
nogroups := maxgrp - mingrp + 1;
if nogroups < 2 then
begin
MessageDlg('One or fewer groups found.', mtError, [mbOK], 0);
exit;
end;
// setup frequency array and count cases in each group
SetLength(freq,NoGroups+1);
for i := 0 to NoGroups do
freq[i] := 0;
for i := 1 to NoCases do
begin
if not ValidValue(i,grpcol) then continue;
value := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[grpcol,i])));
value := value - mingrp;
freq[value] := freq[value] + 1;
end;
// get min and max frequencies and check for existence of a range
minfreq := 10000;
maxfreq := -10000;
for i := 0 to NoGroups-1 do
begin
if freq[i] < minfreq then minfreq := freq[i];
if freq[i] > maxfreq then maxfreq := freq[i];
end;
if minfreq = maxfreq then
begin
MessageDlg('All groups have equal frequencies. Cannot plot.', mtInformation, [mbOK], 0);
freq := nil;
exit;
end;
case PlotOptionsBox.ItemIndex of
0: plottype := 9;
1: plottype := 10;
2: plottype := 1;
3: plottype := 2;
end;
// plot the frequencies
SetLength(GraphFrm.Xpoints,1,nogroups+1);
SetLength(GraphFrm.Ypoints,1,nogroups+1);
GraphFrm.nosets := 1;
GraphFrm.nbars := nogroups;
GraphFrm.Heading := 'Frequency Distribution';
GraphFrm.XTitle := 'Values of ' + labelstr;
GraphFrm.YTitle := 'Frequency';
GraphFrm.barwideprop := 0.5;
GraphFrm.AutoScaled := false;
GraphFrm.miny := 0.0;
GraphFrm.maxy := maxfreq;
GraphFrm.GraphType := plottype;
GraphFrm.BackColor := clCream; // clYellow;
GraphFrm.WallColor := clDkGray; //Black;
GraphFrm.FloorColor := clLtGray;
GraphFrm.ShowBackWall := true;
for i := 0 to nogroups do
begin
GraphFrm.Ypoints[0,i] := freq[i];
GraphFrm.Xpoints[0,i] := mingrp + i;
end;
GraphFrm.ShowModal;
GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil;
end;
procedure TGroupFreqForm.CloseBtnClick(Sender: TObject);
begin
Close;
end;
procedure TGroupFreqForm.FormActivate(Sender: TObject);
var
w: Integer;
begin
if FAutoSized then
exit;
w := MaxValue([ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]);
ResetBtn.Constraints.MinWidth := w;
ComputeBtn.Constraints.MinWidth := w;
CloseBtn.Constraints.MinWidth := w;
VarList.Constraints.MinHeight := PlotOptionsBox.Top + PlotOptionsBox.Height - VarList.Top;
Varlist.Constraints.MinWidth := Label1.Width * 3 div 2;
Constraints.MinWidth := Width;
Constraints.MinHeight := Height;
FAutoSized := true;
end;
procedure TGroupFreqForm.FormCreate(Sender: TObject);
begin
Assert(OS3MainFrm <> nil);
if GraphFrm = nil then Application.CreateForm(TGraphFrm, GraphFrm);
end;
procedure TGroupFreqForm.GrpOutBtnClick(Sender: TObject); procedure TGroupFreqForm.GrpOutBtnClick(Sender: TObject);
begin begin
@@ -222,20 +158,128 @@ begin
UpdateBtnStates; UpdateBtnStates;
end; end;
procedure TGroupFreqForm.Plot(XLabels: StrDyneVec; FreqValues: DblDyneVec; XTitle: String);
const
MARGIN: array[boolean] of Integer = (4, 0);
var
ser: TBarSeries;
YTitle: String;
i: Integer;
begin
// Erase the chart, if it has already been used.
FChartFrame.Clear;
FLabelsSource.Clear;
// Copy XLabels to LabelsSource
for i := 0 to High(XLabels) do
FLabelsSource.Add(i+1, i+1, XLabels[i]);
// Define captions -- will be applied later
XTitle := 'Values of ' + XTitle;
YTitle := 'Frequency';
// Plot the frequencies
ser := TBarSeries(FChartFrame.PlotXY(ptBars, nil, FreqValues, XLabels, nil, '', DATA_COLORS[0]));
if ThreeDChk.Checked then
begin
ser.Depth := 20;
{$IF LCL_FullVersion >= 2010000}
ser.DepthBrightnessDelta := -30;
{$IFEND}
end;
// Show/Hide series labels
if ShowValuesChk.Checked then
begin
ser.Marks.Style := smsValue;
ser.Marks.Distance := 0;
ser.MarkPositionCentered := true;
end else
ser.Marks.Style := smsNone;
ser.Marks.LinkPen.Color := clGray;
// Hide legend
FChartFrame.Chart.Legend.Visible := false;
// Show XLabels along the x axis
if HorBarsBtn.Down then
begin
// Rotate bars to be horizontal
ser.AxisIndexX := 0;
ser.AxisIndexY := 1;
FChartFrame.SetXTitle(YTitle);
FChartFrame.SetYTitle(XTitle);
FChartFrame.Chart.Margins.Bottom := 4;
FChartFrame.Chart.BottomAxis.Marks.Source := nil;
FChartFrame.Chart.BottomAxis.Marks.Style := smsValue;
FChartFrame.Chart.BottomAxis.Marks.Alignment := taCenter;
FChartFrame.Chart.Margins.Left := MARGIN[HorBarsBtn.Down];
FChartFrame.Chart.LeftAxis.Marks.Source := FLabelsSource;
FChartFrame.Chart.LeftAxis.Marks.Style := smsLabel;
FChartFrame.Chart.LeftAxis.Marks.Alignment := taCenter;
end else
begin
ser.AxisIndexX := 1;
ser.AxisIndexY := 0;
FChartFrame.SetXTitle(XTitle);
FChartFrame.SetYTitle(YTitle);
FChartFrame.Chart.Margins.Bottom := MARGIN[HorBarsBtn.Down];
FChartFrame.Chart.BottomAxis.Marks.Source := FLabelsSource;
FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel;
FChartFrame.Chart.BottomAxis.Marks.Alignment := taCenter;
FChartFrame.Chart.Margins.Left := 4;
FChartFrame.Chart.LeftAxis.Marks.Source := nil;
FChartFrame.Chart.LeftAxis.Marks.Style := smsValue;
FChartFrame.Chart.LeftAxis.Marks.Alignment := taCenter;
end;
// Set Chart title
FChartFrame.SetTitle('Frequency Distribution');
end;
procedure TGroupFreqForm.Reset;
var
i: integer;
begin
VarList.Clear;
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
GrpVarEdit.Text := '';
UpdateBtnStates;
FChartFrame.Clear;
end;
procedure TGroupFreqForm.UpdateBtnStates; procedure TGroupFreqForm.UpdateBtnStates;
begin begin
GrpInBtn.Enabled := VarList.ItemIndex > -1; GrpInBtn.Enabled := VarList.ItemIndex > -1;
GrpOutBtn.Enabled := (GrpVarEdit.Text <> ''); GrpOutBtn.Enabled := (GrpVarEdit.Text <> '');
FChartFrame.UpdateBtnStates;
end; end;
procedure TGroupFreqForm.VarListDblClick(Sender: TObject);
var
index: Integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (GrpVarEdit.Text = '') then
begin
GrpVarEdit.Text := VarList.Items[index];
Varlist.Items.Delete(index);
UpdateBtnStates;
end;
end;
procedure TGroupFreqForm.VarListSelectionChange(Sender: TObject; User: boolean); procedure TGroupFreqForm.VarListSelectionChange(Sender: TObject; User: boolean);
begin begin
UpdateBtnStates; UpdateBtnStates;
end; end;
initialization
{$I groupfrequnit.lrs}
end. end.