2020-03-30 18:01:44 +00:00
|
|
|
// Use file "bubbleplot2.laz" for testing.
|
|
|
|
|
|
|
|
unit BubblePlotUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
|
2020-09-22 09:40:36 +00:00
|
|
|
StdCtrls, Clipbrd, Buttons, ExtCtrls, ComCtrls, Math,
|
|
|
|
MainUnit, Globals, DataProcs, DictionaryUnit, ContextHelpUnit, ChartFrameUnit, ReportFrameUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
{ TBubbleForm }
|
|
|
|
|
|
|
|
TBubbleForm = class(TForm)
|
|
|
|
Bevel1: TBevel;
|
|
|
|
HelpBtn: TButton;
|
2020-09-22 09:40:36 +00:00
|
|
|
PageControl: TPageControl;
|
2020-03-30 18:01:44 +00:00
|
|
|
Panel1: TPanel;
|
2020-09-22 09:40:36 +00:00
|
|
|
ParamsPanel: TPanel;
|
|
|
|
ParamsSplitter: TSplitter;
|
|
|
|
ReportPage: TTabSheet;
|
|
|
|
ChartPage: TTabSheet;
|
2020-03-30 18:01:44 +00:00
|
|
|
TransformChk: TCheckBox;
|
|
|
|
YLabelEdit: TEdit;
|
|
|
|
Label8: TLabel;
|
|
|
|
XLabelEdit: TEdit;
|
|
|
|
Label7: TLabel;
|
|
|
|
TitleEdit: TEdit;
|
|
|
|
Label6: TLabel;
|
|
|
|
ResetBtn: TButton;
|
|
|
|
ComputeBtn: TButton;
|
2020-09-20 20:37:17 +00:00
|
|
|
CloseBtn: TButton;
|
2020-03-30 18:01:44 +00:00
|
|
|
IDInBtn: TBitBtn;
|
|
|
|
IDOutBtn: TBitBtn;
|
|
|
|
XInBtn: TBitBtn;
|
|
|
|
XOutBtn: TBitBtn;
|
|
|
|
YInBtn: TBitBtn;
|
|
|
|
YOutBtn: TBitBtn;
|
|
|
|
SizeInBtn: TBitBtn;
|
|
|
|
SizeOutBtn: TBitBtn;
|
|
|
|
BubbleEdit: TEdit;
|
|
|
|
SizeEdit: TEdit;
|
|
|
|
YEdit: TEdit;
|
|
|
|
XEdit: TEdit;
|
|
|
|
Label1: TLabel;
|
|
|
|
Label2: TLabel;
|
|
|
|
Label3: TLabel;
|
|
|
|
Label4: TLabel;
|
|
|
|
Label5: TLabel;
|
|
|
|
VarList: TListBox;
|
|
|
|
procedure ComputeBtnClick(Sender: TObject);
|
|
|
|
procedure FormActivate(Sender: TObject);
|
|
|
|
procedure FormCreate(Sender: TObject);
|
|
|
|
procedure HelpBtnClick(Sender: TObject);
|
|
|
|
procedure IDInBtnClick(Sender: TObject);
|
|
|
|
procedure IDOutBtnClick(Sender: TObject);
|
|
|
|
procedure ResetBtnClick(Sender: TObject);
|
2020-09-20 20:37:17 +00:00
|
|
|
procedure CloseBtnClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure SizeInBtnClick(Sender: TObject);
|
|
|
|
procedure SizeOutBtnClick(Sender: TObject);
|
2020-09-22 09:40:36 +00:00
|
|
|
procedure VarListDblClick(Sender: TObject);
|
2020-08-23 22:52:55 +00:00
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure XInBtnClick(Sender: TObject);
|
|
|
|
procedure XOutBtnClick(Sender: TObject);
|
|
|
|
procedure YInBtnClick(Sender: TObject);
|
|
|
|
procedure YOutBtnClick(Sender: TObject);
|
|
|
|
private
|
|
|
|
{ private declarations }
|
2020-08-23 22:52:55 +00:00
|
|
|
BubbleCol, XCol, YCol, SizeCol: Integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
FAutoSized: boolean;
|
2020-09-22 09:40:36 +00:00
|
|
|
FReportFrame: TReportFrame;
|
|
|
|
FChartFrame: TChartFrame;
|
|
|
|
procedure PlotBubbles(YMax, YMin, BubMax, BubMin: Double);
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure UpdateBtnStates;
|
|
|
|
public
|
|
|
|
{ public declarations }
|
2020-09-20 14:15:41 +00:00
|
|
|
procedure Reset;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
BubbleForm: TBubbleForm;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
uses
|
2020-09-22 09:40:36 +00:00
|
|
|
TAChartUtils, TALegend, TAMultiSeries,
|
|
|
|
Utils;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
{ TBubbleForm }
|
|
|
|
|
|
|
|
procedure TBubbleForm.ComputeBtnClick(Sender: TObject);
|
|
|
|
var
|
2020-08-23 22:52:55 +00:00
|
|
|
i, j, cell: integer;
|
|
|
|
Xmin, Xmax, intcell, noreplications, minrep, maxrep: integer;
|
|
|
|
nobubbles: integer;
|
|
|
|
varname: string;
|
|
|
|
Ymin, Ymax, xvalue, yvalue, sizeValue, cellValue: double;
|
|
|
|
BubMin, BubMax: double;
|
|
|
|
ncases, ncols, BubbleID, newcol: integer;
|
|
|
|
GrandYMean, GrandSizeMean: double;
|
|
|
|
Data: DblDyneMat = nil;
|
|
|
|
Ymeans: DblDyneVec = nil;
|
|
|
|
CaseYMeans: DblDyneVec = nil;
|
|
|
|
SizeMeans: DblDyneVec = nil;
|
|
|
|
CaseSizeMeans: DblDyneVec = nil;
|
2020-03-30 18:01:44 +00:00
|
|
|
outline: string;
|
2020-08-23 22:52:55 +00:00
|
|
|
labels: StrDyneVec = nil;
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport: TStrings;
|
|
|
|
begin
|
|
|
|
BubbleCol := 0;
|
|
|
|
XCol := 0;
|
|
|
|
YCol := 0;
|
|
|
|
SizeCol := 0;
|
|
|
|
for i := 1 to NoVariables do
|
|
|
|
begin
|
|
|
|
varname := OS3MainFrm.DataGrid.Cells[i,0];
|
|
|
|
if (varname = BubbleEdit.Text) then BubbleCol := i;
|
|
|
|
if (varname = XEdit.Text) then XCol := i;
|
|
|
|
if (varname = YEdit.Text) then YCol := i;
|
|
|
|
if (varname = SizeEdit.Text) then SizeCol := i;
|
|
|
|
end;
|
|
|
|
if ((BubbleCol = 0) or (XCol = 0) or (YCol = 0) or (SizeCol = 0)) then
|
|
|
|
begin
|
|
|
|
MessageDlg('One or more variables not found.', mtError, [mbOK], 0);
|
|
|
|
ModalResult := mrNone;
|
|
|
|
Exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get number of bubbles and replications per bubble (number of bubble id's)
|
|
|
|
minrep := 1000;
|
|
|
|
maxrep := -1;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
intcell := StrToInt(OS3MainFrm.DataGrid.Cells[BubbleCol,i]);
|
|
|
|
if (intcell > maxrep) then maxrep := intcell;
|
|
|
|
if (intcell < minrep) then minrep := intcell;
|
|
|
|
end;
|
|
|
|
nobubbles := maxrep - minrep + 1;
|
|
|
|
noreplications := 1;
|
|
|
|
intcell := StrToInt(OS3MainFrm.DataGrid.Cells[BubbleCol,1]);
|
|
|
|
for i := 2 to NoCases do
|
|
|
|
begin
|
|
|
|
cell := StrToInt(OS3MainFrm.DataGrid.Cells[BubbleCol,i]);
|
|
|
|
if (cell = intcell) then noreplications := noreplications + 1;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get min, max and range of Y
|
|
|
|
Ymin := 1.0e308;
|
|
|
|
Ymax := -1.0e308;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
cellvalue := StrToFloat(OS3MainFrm.DataGrid.Cells[YCol,i]);
|
|
|
|
if (cellvalue > Ymax) then Ymax := cellvalue;
|
|
|
|
if (cellvalue < Ymin) then Ymin := cellvalue;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get min, max and range of X
|
|
|
|
Xmin := 10000;
|
|
|
|
Xmax := -1;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
intcell := StrToInt(OS3MainFrm.DataGrid.Cells[XCol,i]);
|
|
|
|
if (intcell > Xmax) then Xmax := intcell;
|
|
|
|
if (intcell < Xmin) then Xmin := intcell;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get min, max, range, and increment of bubble sizes
|
2020-08-23 22:52:55 +00:00
|
|
|
BubMin := Infinity;
|
|
|
|
BubMax := -Infinity;
|
2020-03-30 18:01:44 +00:00
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
cellvalue := StrToFloat(OS3MainFrm.DataGrid.Cells[SizeCol,i]);
|
|
|
|
if (cellvalue > BubMax) then BubMax := cellvalue;
|
|
|
|
if (cellvalue < BubMin) then BubMin := cellvalue;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Display basic statistics
|
2020-08-23 22:52:55 +00:00
|
|
|
nCases := NoCases div NoReplications;
|
2020-03-30 18:01:44 +00:00
|
|
|
GrandYMean := 0.0;
|
|
|
|
GrandSizeMean := 0.0;
|
2020-08-23 22:52:55 +00:00
|
|
|
SetLength(CaseYMeans, nCases);
|
|
|
|
SetLength(CaseSizeMeans, nCases);
|
|
|
|
SetLength(YMeans, NoReplications);
|
|
|
|
SetLength(SizeMeans, NoReplications);
|
|
|
|
for i := 0 to nCases - 1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
CaseYMeans[i] := 0.0;
|
|
|
|
CaseSizeMeans[i] := 0.0;
|
|
|
|
end;
|
2020-08-23 22:52:55 +00:00
|
|
|
for i := 0 to NoReplications - 1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-08-23 22:52:55 +00:00
|
|
|
YMeans[i] := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
SizeMeans[i] := 0.0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
i := 1;
|
|
|
|
while (i <= NoCases) do
|
|
|
|
begin
|
2020-08-23 22:52:55 +00:00
|
|
|
for j := 0 to NoReplications - 1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
bubbleID := StrToInt(OS3MainFrm.DataGrid.Cells[BubbleCol,i]);
|
|
|
|
yvalue := StrToFloat(OS3MainFrm.DataGrid.Cells[YCol,i]);
|
|
|
|
sizevalue := StrToFloat(OS3MainFrm.DataGrid.Cells[SizeCol,i]);
|
|
|
|
GrandYMean := GrandYMean + yvalue;
|
|
|
|
GrandSizeMean := GrandSizeMean + sizevalue;
|
2020-08-23 22:52:55 +00:00
|
|
|
Ymeans[j] := Ymeans[j] + yvalue;
|
|
|
|
SizeMeans[j] := SizeMeans[j] + sizevalue;
|
2020-03-30 18:01:44 +00:00
|
|
|
CaseYMeans[bubbleID-1] := CaseYMeans[bubbleID-1] + yvalue;
|
|
|
|
CaseSizeMeans[bubbleID-1] := CaseSizeMeans[bubbleID-1] + sizevalue;
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
GrandYMean := GrandYMean / (ncases * noreplications);
|
|
|
|
GrandSizeMean := GrandSizeMean / (ncases * noreplications);
|
2020-08-23 22:52:55 +00:00
|
|
|
for j := 0 to NoReplications - 1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
Ymeans[j] := Ymeans[j] / ncases;
|
|
|
|
SizeMeans[j] := SizeMeans[j] / ncases;
|
|
|
|
end;
|
|
|
|
for i := 0 to ncases - 1 do
|
|
|
|
begin
|
|
|
|
CaseYMeans[i] := CaseYMeans[i] / noreplications;
|
|
|
|
CaseSizeMeans[i] := CaseSizeMeans[i] / noreplications;
|
|
|
|
end;
|
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('MEANS FOR Y AND SIZE VARIABLES');
|
|
|
|
lReport.Add('');
|
2020-08-23 22:52:55 +00:00
|
|
|
lReport.Add('Grand Mean for Y: %8.3f', [GrandYMean]);
|
|
|
|
lReport.Add('Grand Mean for Size: %8.3f', [GrandSizeMean]);
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('REPLICATION MEAN Y VALUES (ACROSS OBJECTS)');
|
2020-08-23 22:52:55 +00:00
|
|
|
for j := 0 to NoReplications - 1 do
|
|
|
|
lReport.Add('Replication %5d Mean: %8.3f', [j+1, Ymeans[j]]);
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('REPLICATION MEAN SIZE VALUES (ACROSS OBJECTS)');
|
2020-08-23 22:52:55 +00:00
|
|
|
for j := 0 to NoReplications - 1 do
|
|
|
|
lReport.Add('Replication %5d Mean: %8.3f', [j+1, SizeMeans[j]]);
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('MEAN Y VALUES FOR EACH BUBBLE (OBJECT)');
|
2020-08-23 22:52:55 +00:00
|
|
|
for i := 0 to NCases - 1 do
|
|
|
|
lReport.Add(' Object %5d Mean: %8.3f', [i+1, CaseYMeans[i]]);
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('MEAN SIZE VALUES FOR EACH BUBBLE (OBJECT)');
|
2020-08-23 22:52:55 +00:00
|
|
|
for i := 0 to NCases - 1 do
|
|
|
|
lReport.Add(' Object %5d Mean: %8.3f', [i+1, CaseSizeMeans[i]]);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
// Show the report
|
2020-09-22 09:40:36 +00:00
|
|
|
FReportFrame.DisplayReport(lReport);
|
|
|
|
|
|
|
|
// Plot the bubbles
|
|
|
|
PlotBubbles(YMax, YMin, BubMax, BubMin);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
SizeMeans := nil;
|
|
|
|
Ymeans := nil;
|
|
|
|
CaseSizeMeans := nil;
|
|
|
|
CaseYMeans := nil;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Transform data matrix if elected
|
2020-08-23 22:52:55 +00:00
|
|
|
if TransformChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
ncases := nobubbles;
|
|
|
|
ncols := noreplications * 3 + 1;
|
|
|
|
|
|
|
|
// Note - columns: 1:=object ID, 2 to noreplications := X,
|
|
|
|
// next noreplications := Y, next noreplications := size
|
2020-08-23 22:52:55 +00:00
|
|
|
SetLength(Data, ncases, ncols);
|
2020-03-30 18:01:44 +00:00
|
|
|
i := 1;
|
|
|
|
while (i <= NoCases) do
|
|
|
|
begin
|
|
|
|
for j := 1 to noreplications do
|
|
|
|
begin
|
|
|
|
bubbleID := StrToInt(OS3MainFrm.DataGrid.Cells[BubbleCol,i]);
|
|
|
|
xvalue := StrToFloat(OS3MainFrm.DataGrid.Cells[XCol,i]);
|
|
|
|
yvalue := StrToFloat(OS3MainFrm.DataGrid.Cells[YCol,i]);
|
|
|
|
sizevalue := StrToFloat(OS3MainFrm.DataGrid.Cells[SizeCol,i]);
|
|
|
|
Data[bubbleID-1,0] := bubbleID;
|
|
|
|
Data[bubbleID-1,j] := xvalue;
|
|
|
|
Data[bubbleID-1,noreplications+j] := yvalue;
|
|
|
|
Data[bubbleID-1,noreplications*2+j] := sizevalue;
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
SetLength(labels, NoVariables+1);
|
2020-03-30 18:01:44 +00:00
|
|
|
for i := 1 to NoVariables do labels[i] := OS3MainFrm.DataGrid.Cells[i,0];
|
|
|
|
ClearGrid;
|
|
|
|
OS3MainFrm.DataGrid.RowCount := ncases + 1;
|
|
|
|
OS3MainFrm.DataGrid.ColCount := ncols + 1;
|
|
|
|
|
|
|
|
for i := 1 to ncases do
|
|
|
|
begin
|
|
|
|
OS3MainFrm.DataGrid.Cells[0,i] := IntToStr(i);
|
|
|
|
for j := 1 to ncols do
|
|
|
|
OS3MainFrm.DataGrid.Cells[j,i] := FloatToStr(Data[i-1,j-1]);
|
|
|
|
end;
|
|
|
|
OS3MainFrm.DataGrid.Cells[1,0] := labels[1];
|
|
|
|
|
|
|
|
for j := 2 to NoVariables do // clear dictionary
|
|
|
|
begin
|
|
|
|
for i := 0 to 7 do DictionaryFrm.DictGrid.Cells[i,j] := '';
|
|
|
|
DictionaryFrm.DictGrid.RowCount := DictionaryFrm.DictGrid.RowCount - 1;
|
|
|
|
VarDefined[j] := false;
|
|
|
|
end;
|
|
|
|
DictionaryFrm.DictGrid.Cells[1,1] := labels[1];
|
|
|
|
|
|
|
|
for j := 1 to noreplications do
|
|
|
|
begin
|
|
|
|
outline := labels[2] + IntToStr(j);
|
|
|
|
newcol := j + 1;
|
|
|
|
if (newcol+1 > DictionaryFrm.DictGrid.RowCount) then
|
|
|
|
DictionaryFrm.DictGrid.RowCount := DictionaryFrm.DictGrid.RowCount + 1;
|
|
|
|
DictionaryFrm.Defaults(Self,newcol);
|
|
|
|
VarDefined[newcol] := true;
|
|
|
|
DictionaryFrm.DictGrid.Cells[1,newcol] := outline;
|
|
|
|
OS3MainFrm.DataGrid.Cells[newcol,0] := outline;
|
|
|
|
end;
|
|
|
|
|
|
|
|
for j := 1 to noreplications do
|
|
|
|
begin
|
|
|
|
outline := labels[3] + IntToStr(j);
|
|
|
|
newcol := j + 1 + noreplications;
|
|
|
|
OS3MainFrm.DataGrid.Cells[newcol,0] := outline;
|
|
|
|
if (newcol+1 > DictionaryFrm.DictGrid.RowCount) then
|
|
|
|
DictionaryFrm.DictGrid.RowCount := DictionaryFrm.DictGrid.RowCount + 1;
|
|
|
|
DictionaryFrm.Defaults(Self,newcol);
|
|
|
|
VarDefined[newcol] := true;
|
|
|
|
DictionaryFrm.DictGrid.Cells[1,newcol] := outline;
|
|
|
|
end;
|
|
|
|
|
|
|
|
for j := 1 to noreplications do
|
|
|
|
begin
|
|
|
|
outline := labels[4] + IntToStr(j);
|
|
|
|
newcol := j + 1 + noreplications * 2;
|
|
|
|
OS3MainFrm.DataGrid.Cells[newcol,0] := outline;
|
|
|
|
|
|
|
|
if (newcol+1 > DictionaryFrm.DictGrid.RowCount) then
|
|
|
|
DictionaryFrm.DictGrid.RowCount := DictionaryFrm.DictGrid.RowCount + 1;
|
|
|
|
DictionaryFrm.Defaults(Self,newcol);
|
|
|
|
VarDefined[newcol] := true;
|
|
|
|
|
|
|
|
DictionaryFrm.DictGrid.Cells[1,newcol] := outline;
|
|
|
|
end;
|
|
|
|
|
|
|
|
NoVariables := ncols;
|
|
|
|
NoCases := ncases;
|
|
|
|
OS3MainFrm.NoCasesEdit.Text := IntToStr(NoCases);
|
|
|
|
OS3MainFrm.NoVarsEdit.Text := IntToStr(NoVariables);
|
|
|
|
Data := nil;
|
|
|
|
labels := nil;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.FormActivate(Sender: TObject);
|
|
|
|
var
|
|
|
|
w: Integer;
|
|
|
|
begin
|
|
|
|
if FAutoSized then
|
|
|
|
exit;
|
|
|
|
|
2020-09-20 20:37:17 +00:00
|
|
|
w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]);
|
2020-03-30 18:01:44 +00:00
|
|
|
HelpBtn.Constraints.MinWidth := w;
|
|
|
|
ResetBtn.Constraints.MinWidth := w;
|
|
|
|
ComputeBtn.Constraints.MinWidth := w;
|
2020-09-20 20:37:17 +00:00
|
|
|
CloseBtn.Constraints.MinWidth := w;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
Panel1.Constraints.MinHeight := SizeOutBtn.Top + SizeOutBtn.Height;
|
2020-09-22 09:40:36 +00:00
|
|
|
ParamsPanel.Constraints.MinHeight := Panel1.Height + Panel1.BorderSpacing.Bottom +
|
|
|
|
3*TitleEdit.Height + 2*XLabelEdit.BorderSpacing.Top +
|
|
|
|
TransformChk.BorderSpacing.Top + TransformChk.Height + TransformChk.BorderSpacing.Bottom +
|
|
|
|
Bevel1.Height +
|
|
|
|
CloseBtn.Height + CloseBtn.BorderSpacing.Top;
|
|
|
|
ParamsPanel.Constraints.MinWidth := Max(TransformChk.Width, 4*w + 3*HelpBtn.BorderSpacing.Right);
|
|
|
|
|
|
|
|
Constraints.MinWidth := ParamsPanel.Constraints.MinWidth + 200;
|
|
|
|
Constraints.MinHeight := ParamsPanel.Constraints.MinHeight + 2*ParamsPanel.BorderSpacing.Top;
|
|
|
|
if Height < Constraints.MinHeight then Height := 1; // enforce auto-sizing
|
|
|
|
if Width < Constraints.MiNWidth then Width := 1;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-09-20 20:37:17 +00:00
|
|
|
Position := poDesigned;
|
2020-03-30 18:01:44 +00:00
|
|
|
FAutoSized := True;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.FormCreate(Sender: TObject);
|
|
|
|
begin
|
|
|
|
Assert(OS3MainFrm <> nil);
|
|
|
|
if DictionaryFrm = nil then Application.CreateForm(TDictionaryFrm, DictionaryFrm);
|
2020-09-22 09:40:36 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-09-20 14:15:41 +00:00
|
|
|
Reset;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
|
|
|
procedure TBubbleForm.IDInBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while (BubbleEdit.Text = '') and (i < VarList.Items.Count) do
|
|
|
|
begin
|
|
|
|
if (VarList.Selected[i]) then
|
|
|
|
begin
|
|
|
|
BubbleEdit.Text := VarList.Items[i];
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.IDOutBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if BubbleEdit.Text <> '' then
|
|
|
|
VarList.Items.Add(BubbleEdit.Text);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
|
|
|
procedure TBubbleForm.HelpBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if ContextHelpForm = nil then
|
|
|
|
Application.CreateForm(TContextHelpForm, ContextHelpForm);
|
|
|
|
ContextHelpForm.HelpMessage((Sender as TButton).Tag);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TBubbleForm.PlotBubbles(YMax, YMin, BubMax, BubMin: Double);
|
|
|
|
var
|
|
|
|
ser: TBubbleSeries;
|
|
|
|
bubbleIDs: TStringList;
|
|
|
|
i, j: Integer;
|
|
|
|
id: Integer;
|
|
|
|
xValue, yValue, sizeValue: Double;
|
|
|
|
s: String;
|
|
|
|
yRange, bubRange: Double;
|
|
|
|
begin
|
|
|
|
yRange := YMax - YMin;
|
|
|
|
BubRange := BubMax - BubMin;
|
|
|
|
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.Clear;
|
2020-08-23 22:52:55 +00:00
|
|
|
|
|
|
|
// Titles
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.Caption := 'Bubble Plot of ' + OS3MainFrm.FileNameEdit.Text + LineEnding + TitleEdit.Text;
|
|
|
|
FChartFrame.SetTitle(TitleEdit.Text);
|
2020-08-23 22:52:55 +00:00
|
|
|
if XLabelEdit.Text <> '' then
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.SetXTitle(XLabelEdit.Text)
|
2020-08-23 22:52:55 +00:00
|
|
|
else
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.SetXTitle(XEdit.Text);
|
2020-08-23 22:52:55 +00:00
|
|
|
if YLabelEdit.Text <> '' then
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.SetYTitle(YLabelEdit.Text)
|
2020-08-23 22:52:55 +00:00
|
|
|
else
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.SetYTitle(YEdit.Text);
|
2020-08-23 22:52:55 +00:00
|
|
|
|
|
|
|
// Collect bubble IDs and create a bubble series for each unique ID.
|
|
|
|
bubbleIDs := TStringList.Create;
|
|
|
|
try
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
s := OS3MainFrm.DataGrid.Cells[BubbleCol, i];
|
|
|
|
if bubbleIDs.IndexOf(s) = -1 then // Add each ID only once!
|
|
|
|
bubbleIDs.Add(s);
|
|
|
|
end;
|
|
|
|
for i := 0 to bubbleIDs.Count-1 do
|
|
|
|
begin
|
2020-09-22 09:40:36 +00:00
|
|
|
ser := TBubbleSeries.Create(FChartFrame.Chart);
|
2020-08-23 22:52:55 +00:00
|
|
|
ser.BubbleBrush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
|
|
|
|
ser.BubbleRadiusUnits := bruY;
|
|
|
|
ser.Title := bubbleIDs[i];
|
|
|
|
ser.Tag := StrToInt(bubbleIDs[i]);
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.Chart.AddSeries(ser);
|
2020-08-23 22:52:55 +00:00
|
|
|
end;
|
|
|
|
finally
|
|
|
|
bubbleIDs.Free;
|
|
|
|
end;
|
|
|
|
|
|
|
|
for i := 1 to NoCases do begin
|
|
|
|
id := StrToInt(OS3MainFrm.DataGrid.Cells[BubbleCol, i]);
|
|
|
|
// Find the series having this ID
|
2020-09-22 09:40:36 +00:00
|
|
|
for j := 0 to FChartFrame.Chart.SeriesCount-1 do
|
|
|
|
if (FChartFrame.Chart.Series[j] is TBubbleSeries) and
|
|
|
|
(TBubbleSeries(FChartFrame.Chart.Series[j]).Tag = id) then
|
2020-08-23 22:52:55 +00:00
|
|
|
begin
|
2020-09-22 09:40:36 +00:00
|
|
|
ser := TBubbleSeries(FChartFrame.Chart.Series[j]);
|
2020-08-23 22:52:55 +00:00
|
|
|
break;
|
|
|
|
end;
|
|
|
|
|
|
|
|
xValue := StrToFloat(OS3MainFrm.DataGrid.Cells[XCol, i]);
|
|
|
|
yValue := StrToFloat(OS3MainFrm.DataGrid.Cells[YCol, i]);
|
|
|
|
sizeValue := StrToFloat(OS3MainFrm.DataGrid.Cells[SizeCol, i]);
|
|
|
|
sizeValue := ((sizeValue - BubMin) / BubRange * 0.91 + 0.09) * YRange * 0.1;
|
|
|
|
// This scaling makes the larges bubble equal to 10% of the y range;
|
|
|
|
// the ratio of largest to smallest bubble is about 10:1.
|
|
|
|
|
|
|
|
ser.AddXY(xValue, yValue, sizeValue);
|
|
|
|
end;
|
|
|
|
|
2020-09-22 09:40:36 +00:00
|
|
|
FChartFrame.Chart.Legend.Visible := true;
|
2020-08-23 22:52:55 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-09-20 14:15:41 +00:00
|
|
|
procedure TBubbleForm.Reset;
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
BubbleEdit.Text := '';
|
|
|
|
XEdit.Text := '';
|
|
|
|
YEdit.Text := '';
|
|
|
|
SizeEdit.Text := '';
|
|
|
|
VarList.Clear;
|
|
|
|
for i := 1 to NoVariables do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-09-20 14:15:41 +00:00
|
|
|
procedure TBubbleForm.ResetBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
Reset;
|
|
|
|
end;
|
|
|
|
|
2020-09-20 20:37:17 +00:00
|
|
|
procedure TBubbleForm.CloseBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
Close;
|
|
|
|
end;
|
|
|
|
|
2020-09-20 14:15:41 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.SizeInBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while (SizeEdit.Text = '') and (i < VarList.Items.Count) do
|
|
|
|
begin
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
SizeEdit.Text := VarList.Items[i];
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.SizeOutBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if SizeEdit.Text <> '' then
|
|
|
|
VarList.Items.Add(SizeEdit.Text);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-09-22 09:40:36 +00:00
|
|
|
procedure TBubbleForm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
if BubbleEdit.Text = '' then
|
|
|
|
BubbleEdit.Text := VarList.Items[index]
|
|
|
|
else if XEdit.Text = '' then
|
|
|
|
XEdit.Text := VarList.Items[index]
|
|
|
|
else if YEdit.Text = '' then
|
|
|
|
YEdit.Text := VarList.Items[index]
|
|
|
|
else
|
|
|
|
SizeEdit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
|
|
|
procedure TBubbleForm.UpdateBtnStates;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
lSelected: Boolean;
|
|
|
|
begin
|
|
|
|
lSelected := false;
|
|
|
|
for i:=0 to VarList.Count-1 do
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
lSelected := true;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
|
|
|
|
IDInBtn.Enabled := lSelected and (BubbleEdit.Text = '');
|
|
|
|
XInBtn.Enabled := lSelected and (XEdit.Text = '');
|
|
|
|
YInBtn.Enabled := lSelected and (YEdit.Text = '');
|
|
|
|
SizeInBtn.Enabled := lSelected and (SizeEdit.Text = '');
|
|
|
|
IDOutBtn.Enabled := BubbleEdit.Text <> '';
|
|
|
|
XOutBtn.Enabled := XEdit.Text <> '';
|
|
|
|
YOutBtn.Enabled := YEdit.Text <> '';
|
|
|
|
SizeOutBtn.Enabled := SizeEdit.Text <> '';
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.XInBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while (XEdit.Text = '') and (i < VarList.Items.Count) do
|
|
|
|
begin
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
XEdit.Text := VarList.Items[i];
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.XOutBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if XEdit.Text <> '' then
|
|
|
|
VarList.Items.Add(XEdit.Text);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.YInBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while (YEdit.Text = '') and (i < VarList.Items.Count) do
|
|
|
|
begin
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
YEdit.Text := VarList.Items[i];
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-08-23 22:52:55 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TBubbleForm.YOutBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if YEdit.Text <> '' then
|
|
|
|
VarList.Items.Add(YEdit.Text);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|