LazStats: Inherit AvgLinkUnit from BasicStatsReportFormUnit.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7932 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-12-16 23:08:59 +00:00
parent ac7ba200e2
commit b6459daccb
4 changed files with 202 additions and 241 deletions

View File

@ -862,7 +862,7 @@
<Unit94> <Unit94>
<Filename Value="forms\analysis\multivariate\avglinkunit.pas"/> <Filename Value="forms\analysis\multivariate\avglinkunit.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<ComponentName Value="AvgLinkFrm"/> <ComponentName Value="AvgLinkForm"/>
<HasResources Value="True"/> <HasResources Value="True"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
<UnitName Value="AvgLinkUnit"/> <UnitName Value="AvgLinkUnit"/>

View File

@ -1,123 +1,87 @@
object AvgLinkFrm: TAvgLinkFrm inherited AvgLinkForm: TAvgLinkForm
Left = 589 Left = 589
Height = 132 Height = 132
Top = 409 Top = 409
Width = 383 Width = 383
HelpType = htKeyword HelpType = htKeyword
HelpKeyword = 'html/AverageLinkClustering.htm' HelpKeyword = 'html/AverageLinkClustering.htm'
AutoSize = True
BorderStyle = bsDialog
Caption = 'Average Linkage Hierarchical Clustering' Caption = 'Average Linkage Hierarchical Clustering'
ClientHeight = 132 ClientHeight = 132
ClientWidth = 383 ClientWidth = 383
OnActivate = FormActivate inherited ParamsPanel: TPanel
OnCreate = FormCreate Height = 116
OnShow = FormShow Width = 259
Position = poMainFormCenter ClientHeight = 116
LCLVersion = '2.1.0.0' ClientWidth = 259
object MatrixTypeGroup: TRadioGroup inherited CloseBtn: TButton
AnchorSideLeft.Control = Owner Left = 204
AnchorSideLeft.Side = asrCenter Top = 91
AnchorSideTop.Control = Owner TabOrder = 4
Left = 131 end
Height = 72 inherited ComputeBtn: TButton
Top = 8 Left = 120
Width = 120 Top = 91
AutoFill = True TabOrder = 3
AutoSize = True end
BorderSpacing.Left = 8 inherited ResetBtn: TButton
BorderSpacing.Top = 8 Left = 58
Caption = 'Matrix Type Is:' Top = 91
ChildSizing.LeftRightSpacing = 12 Visible = False
ChildSizing.TopBottomSpacing = 6 end
ChildSizing.VerticalSpacing = 2 inherited HelpBtn: TButton
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize Tag = 105
ChildSizing.EnlargeVertical = crsHomogenousChildResize Left = -1
ChildSizing.ShrinkHorizontal = crsScaleChilds Top = 91
ChildSizing.ShrinkVertical = crsScaleChilds TabOrder = 1
ChildSizing.Layout = cclLeftToRightThenTopToBottom end
ChildSizing.ControlsPerLine = 1 inherited ButtonBevel: TBevel
ClientHeight = 52 Top = 75
ClientWidth = 116 Width = 259
Items.Strings = ( end
'Similarities' object MatrixTypeGroup: TRadioGroup[5]
'Dissimilarities' AnchorSideLeft.Control = ParamsPanel
) AnchorSideLeft.Side = asrCenter
TabOrder = 0 AnchorSideTop.Control = Bevel1
AnchorSideTop.Side = asrCenter
Left = 69
Height = 72
Top = 1
Width = 120
AutoFill = True
AutoSize = True
BorderSpacing.Left = 8
Caption = 'Matrix Type Is:'
ChildSizing.LeftRightSpacing = 12
ChildSizing.TopBottomSpacing = 6
ChildSizing.VerticalSpacing = 2
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 52
ClientWidth = 116
Items.Strings = (
'Similarities'
'Dissimilarities'
)
TabOrder = 0
end
object Bevel1: TBevel[6]
AnchorSideLeft.Control = ParamsPanel
AnchorSideTop.Control = ParamsPanel
AnchorSideBottom.Control = ButtonBevel
Left = 0
Height = 75
Top = 0
Width = 18
Anchors = [akTop, akLeft, akBottom]
Shape = bsSpacer
end
end end
object ComputeBtn: TButton inherited ParamsSplitter: TSplitter
AnchorSideLeft.Side = asrBottom Left = 271
AnchorSideTop.Control = Bevel1 Height = 132
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = CloseBtn
AnchorSideBottom.Side = asrBottom
Left = 236
Height = 25
Top = 96
Width = 76
Anchors = [akTop, akRight]
AutoSize = True
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Compute'
OnClick = ComputeBtnClick
TabOrder = 2
end
object CloseBtn: TButton
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Bevel1
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Side = asrBottom
Left = 320
Height = 25
Top = 96
Width = 55
Anchors = [akTop, akRight]
AutoSize = True
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Close'
ModalResult = 11
TabOrder = 3
end
object HelpBtn: TButton
Tag = 105
AnchorSideTop.Control = Bevel1
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = ComputeBtn
AnchorSideBottom.Side = asrBottom
Left = 177
Height = 25
Top = 96
Width = 51
Anchors = [akTop, akRight]
AutoSize = True
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Help'
OnClick = HelpBtnClick
TabOrder = 1
end
object Bevel1: TBevel
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = MatrixTypeGroup
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = CloseBtn
Left = 0
Height = 8
Top = 80
Width = 383
Anchors = [akTop, akLeft, akRight]
Shape = bsBottomLine
end end
end end

View File

@ -11,130 +11,110 @@ unit AvgLinkUnit;
interface interface
uses uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Classes, SysUtils, Forms, Controls, Graphics, StdCtrls, ExtCtrls,
Dialogs, StdCtrls, ExtCtrls, MainUnit, Globals, BasicStatsReportFormUnit;
MainUnit, Globals, OutputUnit, ContextHelpUnit;
type type
{ TAvgLinkFrm } { TAvgLinkForm }
TAvgLinkFrm = class(TForm) TAvgLinkForm = class(TBasicStatsReportForm)
Bevel1: TBevel; Bevel1: TBevel;
ComputeBtn: TButton;
HelpBtn: TButton;
CloseBtn: TButton;
MatrixTypeGroup: TRadioGroup; MatrixTypeGroup: TRadioGroup;
procedure ComputeBtnClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure HelpBtnClick(Sender: TObject);
private private
{ private declarations } { private declarations }
procedure PreTree(NN, CRIT: integer; LST: IntDyneVec; KLUS: IntDyneMat; AReport: TStrings); procedure PreTree(NN, CRIT: integer; LST: IntDyneVec; KLUS: IntDyneMat; AReport: TStrings);
procedure TreePlot(Clusters: IntDyneMat; Lst: IntDyneVec; NoPoints: integer; AReport: TStrings); procedure TreePlot(Clusters: IntDyneMat; Lst: IntDyneVec; NoPoints: integer; AReport: TStrings);
protected
procedure AdjustConstraints; override;
procedure Compute; override;
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
public public
{ public declarations } { public declarations }
end; end;
var var
AvgLinkFrm: TAvgLinkFrm; AvgLinkForm: TAvgLinkForm;
implementation implementation
{$R *.lfm}
uses uses
Math; Math;
{ TAvgLinkFrm } { TAvgLinkForm }
procedure TAvgLinkFrm.FormActivate(Sender: TObject); procedure TAvgLinkForm.AdjustConstraints;
var
w: Integer;
begin begin
w := MaxValue([HelpBtn.Width, ComputeBtn.Width, CloseBtn.Width]); inherited;
HelpBtn.Constraints.MinWidth := w;
ComputeBtn.Constraints.MinWidth := w; ParamsPanel.Constraints.MinWidth := Max(
CloseBtn.Constraints.MinWidth := w; 3*CloseBtn.Width + 2*CloseBtn.BorderSpacing.Left,
MatrixTypeGroup.Width
);
ParamsPanel.Constraints.MinHeight :=
MatrixTypeGroup.Height + ButtonBevel.Height + CloseBtn.BorderSpacing.Top +
CloseBtn.Height;
end; end;
procedure TAvgLinkFrm.FormCreate(Sender: TObject);
begin
Assert(OS3MainFrm <> nil);
end;
procedure TAvgLinkFrm.FormShow(Sender: TObject); { Reference: Anderberg, M. R. (1973). Cluster analysis for applications.
begin New York: Academic press.
MatrixTypeGroup.ItemIndex := 0;
end;
procedure TAvgLinkFrm.HelpBtnClick(Sender: TObject); Almost any text on cluster analysis should have a good description of the
begin average-linkage hierarchical clustering algorithm.
if ContextHelpForm = nil then The algorithm begins with an initial similarity or dissimilarity matrix
Application.CreateForm(TContextHelpForm, ContextHelpForm); between pairs of objects.
ContextHelpForm.HelpMessage((Sender as TButton).tag); The algorithm proceeds in an iterative way. At each iteration the two
end; most similar (we assume similarities for explanation) objects are combined
into one group.
At each successive iteration, the two most similar objects or groups of
objects are merged. Similarity between groups is defined as the average
similarity between objects in one group with objects in the other.
procedure TAvgLinkFrm.ComputeBtnClick(Sender: TObject); INPUT: A correlation matrix (or some other similarity or
dissimilarity matrix) in a file named MATRIX.DAT
This must contain all the elements of a full
(n x n), symmetrical matrix. Any format is
allowable, as long as numbers are separated by
blanks.
OUTPUT: Output consists of a cluster history and a tree
diagram (dendogram). The cluster history
indicates, for each iteration, the objects
or clusters merged, and the average pairwise
similarity or dissimilarity in the resulting
cluster.
Author: John Uebersax
}
procedure TAvgLinkForm.Compute;
const const
SIM_DIS: array[0..1] of String = ('Similarity', 'Dissimilarity'); SIM_DIS: array[0..1] of String = ('Similarity', 'Dissimilarity');
VAR var
X : DblDyneMat; // similarity or dissimilarity matrix X: DblDyneMat = nil; // similarity or dissimilarity matrix
KLUS : IntDyneMat; KLUS: IntDyneMat = nil;
LST : IntDyneVec; LST: IntDyneVec = nil;
RX, SAV, SAV2, RRRMIN : double; RX, SAV, SAV2, RRRMIN: double;
NIN, NVAR : IntDyneVec; NIN: IntDyneVec = nil;
I, J, K, L, M, MN, N, CRIT, ITR, LIMIT : integer; NVAR: IntDyneVec = nil;
// ROWS : StrDyneVec; I, J, K, L, M, MN, N, CRIT, ITR, LIMIT: integer;
nvalues : integer; nValues: integer;
lReport: TStrings; lReport: TStrings;
label label
label300, label60, label70; label300, label60, label70;
begin begin
// Reference: Anderberg, M. R. (1973). Cluster analysis for nValues := NoVariables;
// applications. New York: Academic press. SetLength(X, nValues+1, nvalues+1);
// SetLength(KLUS, nValues+1, 3);
// Almost any text on cluster analysis should have a good SetLength(LST, nValues+1);
// description of the average-linkage hierarchical clustering SetLength(NIN, nValues+1);
// algorithm. The algorithm begins with an initial similarity SetLength(NVAR, nValues+1);
// or dissimilarity matrix between pairs of objects. The
// algorithm proceeds in an iterative way. At each iteration
// the two most similar (we assume similarities for explanation)
// objects are combined into one group. At each successive
// iteration, the two most similar objects or groups of objects are
// merged. Similarity between groups is defined as the average
// similarity between objects in one group with objects in the other.
//
// INPUT: A correlation matrix (or some other similarity or
// dissimilarity matrix) in a file named MATRIX.DAT
// This must contain all the elements of a full
// (n x n), symmetrical matrix. Any format is
// allowable, as long as numbers are separated by
// blanks.
//
// OUTPUT: Output consists of a cluster history and a tree
// diagram (dendogram). The cluster history
// indicates, for each iteration, the objects
// or clusters merged, and the average pairwise
// similarity or dissimilarity in the resulting
// cluster.
//
// Author: John Uebersax
if (NoVariables <= 0) then
begin
MessageDlg('You must first load a matrix into the grid.', mtError, [mbOK], 0);
exit;
end;
nvalues := NoVariables;
SetLength(X,nvalues+1,nvalues+1);
SetLength(KLUS,nvalues+1,3);
SetLength(LST,nvalues+1);
SetLength(NIN,nvalues+1);
SetLength(NVAR,nvalues+1);
lReport := TStringList.Create; lReport := TStringList.Create;
try try
@ -252,9 +232,11 @@ label300:
NIN[K] := NIN[K] + NIN[L]; NIN[K] := NIN[K] + NIN[L];
for I := L to MN do NIN[I] := NIN[I+1]; for I := L to MN do NIN[I] := NIN[I+1];
goto label70; goto label70;
label60: label60:
// Update number of objects in each cluster // Update number of objects in each cluster
NIN[K] := NIN[K] + NIN[L]; NIN[K] := NIN[K] + NIN[L];
label70: // end of ARRANGE procedure label70: // end of ARRANGE procedure
// continuation of CLUSV1 procedure // continuation of CLUSV1 procedure
@ -269,59 +251,54 @@ label70: // end of ARRANGE procedure
KLUS[ITR,1] := NVAR[K]; // save in KLUS rather than write out to file as in KLUS[ITR,1] := NVAR[K]; // save in KLUS rather than write out to file as in
KLUS[ITR,2] := NVAR[L]; // original program KLUS[ITR,2] := NVAR[L]; // original program
if not(L = M) then if (L <> M) then
begin begin
MN := M - 1; MN := M - 1;
for i := L to MN do NVAR[i] := NVAR[i+1]; for i := L to MN do NVAR[i] := NVAR[i+1];
end; end;
M := M - 1; M := M - 1;
if (ITR < LIMIT) then goto label300; if (ITR < LIMIT) then goto label300;
lReport.Add(''); lReport.Add('');
// End of CLUSV1 procedure // End of CLUSV1 procedure
// do pre-tree processing // do pre-tree processing
PreTree(nvalues, CRIT, LST, KLUS, lReport); PreTree(nvalues, CRIT, LST, KLUS, lReport);
lReport.Add(''); lReport.Add('');
lReport.Add(DIVIDER); lReport.Add(DIVIDER_AUTO);
lReport.Add(''); lReport.Add('');
// do TREE procedure // do TREE procedure
TreePlot(KLUS, LST, nvalues, lReport); TreePlot(KLUS, LST, nvalues, lReport);
DisplayReport(lReport); FReportFrame.DisplayReport(lReport);
finally finally
lReport.Free; lReport.Free;
NVAR := nil;
NIN := nil;
LST := nil;
KLUS := nil;
X := nil;
end; end;
end; end;
procedure TAvgLinkFrm.TreePlot(Clusters: IntDyneMat; Lst: IntDyneVec;
procedure TAvgLinkForm.TreePlot(Clusters: IntDyneMat; Lst: IntDyneVec;
NoPoints: integer; AReport: TStrings); NoPoints: integer; AReport: TStrings);
VAR VAR
outline : array[0..501] of char; outline : array[0..501] of char;
aline : array[0..82] of char; aline : array[0..82] of char;
valstr : string;
tempstr : string; tempstr : string;
plotline : string; plotline : string;
star : char; star : char;
blank : char; blank : char;
col1, col2, colpos1, colpos2 : integer; col1, col2, colpos1, colpos2 : integer;
noparts, startcol, endcol : integer; noparts, startcol, endcol : integer;
Results : StrDyneVec; Results : StrDyneVec = nil;
ColPos : IntDyneVec; ColPos : IntDyneVec = nil;
i, j, k, L, linecount, newcol, howlong, count: integer; i, j, k, L, linecount, newcol, howlong, count: integer;
begin begin
linecount := 1; linecount := 1;
star := '*'; star := '*';
blank := ' '; blank := ' ';
SetLength(ColPos,NoPoints+2); SetLength(ColPos, NoPoints + 2);
SetLength(Results,NoPoints*2+3); SetLength(Results, NoPoints*2 + 3);
//AReport.Add('');
// store initial column positions of vertical linkages // store initial column positions of vertical linkages
for i := 1 to NoPoints do ColPos[Lst[i]] := 4 + (i * 5); for i := 1 to NoPoints do ColPos[Lst[i]] := 4 + (i * 5);
@ -329,10 +306,7 @@ begin
// create column heading indented 10 spaces // create column heading indented 10 spaces
tempstr := 'UNIT '; tempstr := 'UNIT ';
for i := 1 to NoPoints do for i := 1 to NoPoints do
begin tempstr := tempstr + Format('%5d', [Lst[i]]);
valstr := format('%5d',[Lst[i]]);
tempstr := tempstr + valstr;
end;
Results[linecount] := tempstr; Results[linecount] := tempstr;
linecount := linecount + 1; linecount := linecount + 1;
@ -345,38 +319,45 @@ begin
// start dendoplot // start dendoplot
for i := 1 to NoPoints - 1 do for i := 1 to NoPoints - 1 do
begin begin
outline := ''; // put step no. first
valstr := Format('%5d',[i]); // put step no. first outline := Format('%5d', [i]);
outline := valstr;
// clear remainder of outline // clear remainder of outline
for j := 5 to (5 + NoPoints * 5) do outline[j] := ' '; for j := 5 to (5 + NoPoints * 5) do outline[j] := ' ';
outline[6 + NoPoints * 5] := #0; outline[6 + NoPoints * 5] := #0;
col1 := Clusters[i,1]; col1 := Clusters[i,1];
col2 := Clusters[i,2]; col2 := Clusters[i,2];
// find column positions for each variable // find column positions for each variable
colpos1 := ColPos[col1]; colpos1 := ColPos[col1];
colpos2 := ColPos[col2]; colpos2 := ColPos[col2];
for k := colpos1 to colpos2 do outline[k] := star; for k := colpos1 to colpos2 do
outline[k] := star;
// change column positions 1/2 way between the matched ones // change column positions 1/2 way between the matched ones
newcol := colpos1 + ((colpos2 - colpos1) div 2); newcol := colpos1 + ((colpos2 - colpos1) div 2);
for k := 1 to NoPoints do for k := 1 to NoPoints do
if ((ColPos[k] = colpos1) or (ColPos[k] = colpos2)) then ColPos[k] := newcol; if ((ColPos[k] = colpos1) or (ColPos[k] = colpos2)) then
ColPos[k] := newcol;
for k := 1 to NoPoints do for k := 1 to NoPoints do
begin begin
L := ColPos[k]; L := ColPos[k];
if ((L <> colpos1) and (L <> colpos2)) then outline[L] := star; if ((L <> colpos1) and (L <> colpos2)) then
outline[L] := star;
end; end;
Results[linecount] := outline; Results[linecount] := outline;
linecount := linecount + 1; linecount := linecount + 1;
// add a line of connectors to next grouping // add a line of connectors to next grouping
outline := ' '; outline := ' ';
for j := 5 to (5 + NoPoints * 5) do outline[j] := blank; for j := 5 to (5 + NoPoints * 5) do
outline[j] := blank;
for j := 1 to NoPoints do for j := 1 to NoPoints do
begin begin
colpos1 := ColPos[j]; colpos1 := ColPos[j];
outline[colpos1] := star; outline[colpos1] := star;
end; end;
Results[linecount] := outline; Results[linecount] := outline;
linecount := linecount + 1; linecount := linecount + 1;
@ -384,10 +365,10 @@ begin
// output the Results in parts // output the Results in parts
// determine number of pages needed for whole plot // determine number of pages needed for whole plot
noparts := 0;
howlong := Length(Results[1]); howlong := Length(Results[1]);
noparts := round(howlong / 80.0); noparts := round(howlong / 80.0);
if (noparts <= 0) then noparts := 1; if (noparts <= 0) then
noparts := 1;
if (noparts = 1) then // simply print the list if (noparts = 1) then // simply print the list
for i := 0 to linecount - 1 do for i := 0 to linecount - 1 do
@ -420,23 +401,23 @@ begin
if (endcol > howlong) then endcol := howlong; if (endcol > howlong) then endcol := howlong;
end; end;
end; end;
Results := nil;
ColPos := nil;
end; end;
procedure TAvgLinkFrm.PreTree(NN, CRIT: integer; LST: IntDyneVec;
procedure TAvgLinkForm.PreTree(NN, CRIT: integer; LST: IntDyneVec;
KLUS: IntDyneMat; AReport: TStrings); KLUS: IntDyneMat; AReport: TStrings);
VAR VAR
I, II, J, NI, NJ, L, M, N, Ina, INEND, NHOLD, NLINES, INDX, ICOL, JCOL: integer; I, II, J, NI, NJ, L, M, N, Ina, INEND, NHOLD, NLINES, INDX, ICOL, JCOL: integer;
KSH, JEND, MSH: integer; KSH, JEND, MSH: integer;
JHOLD, NIN1: IntDyneVec; JHOLD: IntDyneVec = nil;
NIN1: IntDyneVec = nil;
outline: string; outline: string;
label label
label2015, label2020, label2030, label2040, label2055, label2060; label2015, label2020, label2030, label2040, label2055, label2060;
begin begin
// PRETRE procedure // PRETRE procedure
SetLength(JHOLD,NN+1); SetLength(JHOLD, NN+1);
SetLength(NIN1,NN+1); SetLength(NIN1, NN+1);
// int NN := nvalues; // int NN := nvalues;
N := NN - 1; N := NN - 1;
AReport.Add('No. of objects: %3d', [NN]); AReport.Add('No. of objects: %3d', [NN]);
@ -459,19 +440,23 @@ begin
NI := NIN1[I]; NI := NIN1[I];
NJ := NIN1[J]; NJ := NIN1[J];
L := 1; L := 1;
label2015: label2015:
if (LST[L] = I) then goto label2020; if (LST[L] = I) then goto label2020;
L := L + 1; L := L + 1;
if (L <= NN) then goto label2015; if (L <= NN) then goto label2015;
label2020: label2020:
ICOL := L; ICOL := L;
Ina := ICOL + NI; Ina := ICOL + NI;
INEND := Ina + NJ - 1; INEND := Ina + NJ - 1;
L := L + 1; L := L + 1;
label2030: label2030:
if (LST[L] = J) then goto label2040; if (LST[L] = J) then goto label2040;
L := L + 1; L := L + 1;
if (L <= NN) then goto label2030; if (L <= NN) then goto label2030;
label2040: label2040:
JCOL := L; JCOL := L;
JEND := JCOL + NJ - 1; JEND := JCOL + NJ - 1;
@ -523,8 +508,20 @@ label2060:
// End of PRETRE procedure // End of PRETRE procedure
end; end;
initialization
{$I avglinkunit.lrs} function TAvgLinkForm.Validate(out AMsg: String; out AControl: TWinControl): boolean;
begin
Result := false;
if (NoVariables <= 0) then
begin
AControl := MatrixTypeGroup;
AMsg := 'You must first load a matrix into the grid.';
exit;
end;
Result := true;
end;
end. end.

View File

@ -2162,9 +2162,9 @@ end;
// Menu" "Analysis" > "Multivariate" > "Average Link Clustering" // Menu" "Analysis" > "Multivariate" > "Average Link Clustering"
procedure TOS3MainFrm.mnuAnalysisMulti_AvgLinkClick(Sender: TObject); procedure TOS3MainFrm.mnuAnalysisMulti_AvgLinkClick(Sender: TObject);
begin begin
if AvgLinkFrm = nil then if AvgLinkForm = nil then
Application.CreateForm(TAvgLinkFrm, AvgLinkFrm); Application.CreateForm(TAvgLinkForm, AvgLinkForm);
AvgLinkFrm.ShowModal; AvgLinkForm.Show;
end; end;
// Menu "Analysis" > "Multivariate" > "K Means Clustering" // Menu "Analysis" > "Multivariate" > "K Means Clustering"