You've already forked lazarus-ccr
LazStats: Extract and add some general purpose grid-related routines to the new unit GridProcs.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7738 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -122,7 +122,7 @@
|
|||||||
<PackageName Value="LCL"/>
|
<PackageName Value="LCL"/>
|
||||||
</Item7>
|
</Item7>
|
||||||
</RequiredPackages>
|
</RequiredPackages>
|
||||||
<Units Count="180">
|
<Units Count="181">
|
||||||
<Unit0>
|
<Unit0>
|
||||||
<Filename Value="LazStats.lpr"/>
|
<Filename Value="LazStats.lpr"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
@ -1534,6 +1534,11 @@
|
|||||||
<ResourceBaseClass Value="Form"/>
|
<ResourceBaseClass Value="Form"/>
|
||||||
<UnitName Value="BasicStatsReportAndChartFormUnit"/>
|
<UnitName Value="BasicStatsReportAndChartFormUnit"/>
|
||||||
</Unit179>
|
</Unit179>
|
||||||
|
<Unit180>
|
||||||
|
<Filename Value="units\gridprocs.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="GridProcs"/>
|
||||||
|
</Unit180>
|
||||||
</Units>
|
</Units>
|
||||||
</ProjectOptions>
|
</ProjectOptions>
|
||||||
<CompilerOptions>
|
<CompilerOptions>
|
||||||
|
@ -8,7 +8,7 @@ uses
|
|||||||
{$ENDIF}{$ENDIF}
|
{$ENDIF}{$ENDIF}
|
||||||
Interfaces, // this includes the LCL widgetset
|
Interfaces, // this includes the LCL widgetset
|
||||||
Forms, tachartlazaruspkg, tachartprint, lhelpcontrolpkg, Globals, LicenseUnit,
|
Forms, tachartlazaruspkg, tachartprint, lhelpcontrolpkg, Globals, LicenseUnit,
|
||||||
OptionsUnit, MainDM, MainUnit;
|
OptionsUnit, MainDM, MainUnit, GridProcs;
|
||||||
|
|
||||||
{$R LazStats.res}
|
{$R LazStats.res}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ implementation
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Math, Grids,
|
Math, Grids,
|
||||||
Utils, DictionaryUnit;
|
Utils, DictionaryUnit, GridProcs;
|
||||||
|
|
||||||
|
|
||||||
{ TCrossTabCalculator }
|
{ TCrossTabCalculator }
|
||||||
@ -232,13 +232,13 @@ begin
|
|||||||
for i := 1 to no_in_list do
|
for i := 1 to no_in_list do
|
||||||
begin
|
begin
|
||||||
j := FVarList[i-1];
|
j := FVarList[i-1];
|
||||||
if not GoodRecord(FDataGrid, 1, NoSelected, FColNoSelected) then continue;
|
if not GoodRecord(FDataGrid, 1, FColNoSelected) then continue;
|
||||||
value := StrToFloat(FDataGrid.Cells[j, 1]);
|
value := StrToFloat(FDataGrid.Cells[j, 1]);
|
||||||
min_value[i-1] := round(value);
|
min_value[i-1] := round(value);
|
||||||
max_value[i-1] := round(value);
|
max_value[i-1] := round(value);
|
||||||
for k := 2 to NoCases do
|
for k := 2 to NoCases do
|
||||||
begin
|
begin
|
||||||
if not GoodRecord(FDataGrid, k, NoSelected, FColNoSelected) then continue;
|
if not GoodRecord(FDataGrid, k, FColNoSelected) then continue;
|
||||||
value := StrToFloat(FDataGrid.Cells[j, k]);
|
value := StrToFloat(FDataGrid.Cells[j, k]);
|
||||||
if value < min_value[i-1] then
|
if value < min_value[i-1] then
|
||||||
min_value[i-1] := round(value);
|
min_value[i-1] := round(value);
|
||||||
@ -292,11 +292,11 @@ begin
|
|||||||
freq[i] := 0;
|
freq[i] := 0;
|
||||||
for i := 1 to NoCases do
|
for i := 1 to NoCases do
|
||||||
begin
|
begin
|
||||||
if IsFiltered(i) then
|
if IsFiltered(FDataGrid, i) then
|
||||||
continue;
|
continue;
|
||||||
for j := 1 to no_in_list do
|
for j := 1 to no_in_list do
|
||||||
begin
|
begin
|
||||||
if not GoodRecord(i, NoSelected, FColNoSelected) then continue;
|
if not GoodRecord(FDataGrid, i, FColNoSelected) then continue;
|
||||||
k := FVarList[j-1];
|
k := FVarList[j-1];
|
||||||
value := StrToFloat(FDataGrid.Cells[k,i]);
|
value := StrToFloat(FDataGrid.Cells[k,i]);
|
||||||
x := round(value);
|
x := round(value);
|
||||||
@ -453,6 +453,9 @@ var
|
|||||||
noSelected: Integer;
|
noSelected: Integer;
|
||||||
cellValue: String;
|
cellValue: String;
|
||||||
begin
|
begin
|
||||||
|
AVarList := nil; // Silence the compiler
|
||||||
|
AColNoSelected := nil;
|
||||||
|
|
||||||
SetLength(AVarList, SelList.Count);
|
SetLength(AVarList, SelList.Count);
|
||||||
SetLength(AColNoSelected, SelList.Count);
|
SetLength(AColNoSelected, SelList.Count);
|
||||||
|
|
||||||
|
@ -7,10 +7,11 @@ interface
|
|||||||
uses
|
uses
|
||||||
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
|
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
|
||||||
StdCtrls, ExtCtrls, Clipbrd, Grids,
|
StdCtrls, ExtCtrls, Clipbrd, Grids,
|
||||||
Globals, OptionsUnit, DictionaryUnit;
|
Globals, OptionsUnit, DictionaryUnit, GridProcs;
|
||||||
|
|
||||||
Function GoodRecord(Row, NoVars: integer; const GridPos: IntDyneVec): boolean; overload;
|
function GoodRecord(Row, NoVars: integer; const GridPos: IntDyneVec): boolean;
|
||||||
Function GoodRecord(AGrid: TStringGrid; Row, NoVars: integer; const GridPos: IntDyneVec): boolean; overload;
|
function IsFiltered(GridRow: integer): boolean; overload;
|
||||||
|
function ValidValue(row, col: integer): boolean;
|
||||||
|
|
||||||
procedure FormatCell(Col, Row : integer);
|
procedure FormatCell(Col, Row : integer);
|
||||||
procedure FormatGrid;
|
procedure FormatGrid;
|
||||||
@ -29,10 +30,6 @@ procedure CopyRow;
|
|||||||
procedure PasteRow;
|
procedure PasteRow;
|
||||||
procedure PrintDict(AReport: TStrings);
|
procedure PrintDict(AReport: TStrings);
|
||||||
procedure PrintData(AReport: TStrings);
|
procedure PrintData(AReport: TStrings);
|
||||||
function ValidValue(row, col: integer): boolean; overload;
|
|
||||||
function ValidValue(AGrid: TStringGrid; row, col: integer): boolean; overload;
|
|
||||||
function IsFiltered(GridRow: integer): boolean; overload;
|
|
||||||
function IsFiltered(AGrid: TStringGrid; GridRow: integer): boolean; overload;
|
|
||||||
|
|
||||||
procedure MatRead(const a: DblDyneMat; out NoRows, NoCols: integer;
|
procedure MatRead(const a: DblDyneMat; out NoRows, NoCols: integer;
|
||||||
const Means, StdDevs: DblDyneVec; out NCases: integer;
|
const Means, StdDevs: DblDyneVec; out NCases: integer;
|
||||||
@ -66,25 +63,21 @@ implementation
|
|||||||
uses
|
uses
|
||||||
Utils, MainUnit;
|
Utils, MainUnit;
|
||||||
|
|
||||||
function GoodRecord(Row, NoVars: Integer; const GridPos: IntDyneVec): boolean;
|
|
||||||
begin
|
|
||||||
Result := GoodRecord(OS3MainFrm.DataGrid, Row, NoVars, GridPos);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function GoodRecord(AGrid: TStringGrid; Row, NoVars: integer;
|
// NOTE: Do not call GridProcs.GoodRecord here because this old function may
|
||||||
const GridPos: IntDyneVec): boolean;
|
// use an over-dimensioned GridPos array.
|
||||||
|
function GoodRecord(Row, NoVars: Integer; const GridPos: IntDyneVec): boolean;
|
||||||
var
|
var
|
||||||
i, j: integer;
|
i, j: integer;
|
||||||
begin
|
begin
|
||||||
Result := true;
|
Result := true;
|
||||||
for i := 0 to NoVars-1 do
|
for i := 0 to NoVars - 1 do
|
||||||
begin
|
begin
|
||||||
j := GridPos[i];
|
j := GridPos[i];
|
||||||
if not ValidValue(AGrid, Row, j) then
|
if not ValidValue(Row, j) then
|
||||||
Result := false;
|
Result := false;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
//-------------------------------------------------------------------
|
|
||||||
|
|
||||||
procedure FormatCell(Col, Row: integer);
|
procedure FormatCell(Col, Row: integer);
|
||||||
var
|
var
|
||||||
@ -802,33 +795,7 @@ end;
|
|||||||
|
|
||||||
function ValidValue(row, col: Integer): Boolean;
|
function ValidValue(row, col: Integer): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := ValidValue(OS3MainFrm.DataGrid, row, col);
|
Result := GridProcs.ValidValue(OS3MainFrm.DataGrid, row, col);
|
||||||
end;
|
|
||||||
|
|
||||||
function ValidValue(AGrid: TStringGrid; row, col: integer): boolean;
|
|
||||||
var
|
|
||||||
valid: boolean;
|
|
||||||
xvalue: string;
|
|
||||||
cellstring: string;
|
|
||||||
begin
|
|
||||||
valid := true;
|
|
||||||
if FilterOn then
|
|
||||||
begin
|
|
||||||
cellstring := Trim(AGrid.Cells[FilterCol, row]);
|
|
||||||
if cellstring = 'NO' then valid := false;
|
|
||||||
Result := valid;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
xvalue := Trim(AGrid.Cells[col,row]);
|
|
||||||
if (xvalue = '') and (DictionaryFrm.DictGrid.Cells[4, col] <> 'S') then
|
|
||||||
valid := false;
|
|
||||||
if valid then // check for user-defined missing value
|
|
||||||
begin
|
|
||||||
if Trim(DictionaryFrm.DictGrid.Cells[6, col]) = xvalue then
|
|
||||||
valid := false;
|
|
||||||
end;
|
|
||||||
Result := valid;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function IsFiltered(GridRow: Integer): Boolean;
|
function IsFiltered(GridRow: Integer): Boolean;
|
||||||
@ -836,12 +803,6 @@ begin
|
|||||||
Result := IsFiltered(OS3MainFrm.DataGrid, GridRow);
|
Result := IsFiltered(OS3MainFrm.DataGrid, GridRow);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function IsFiltered(AGrid: TStringGrid; GridRow: integer): boolean;
|
|
||||||
begin
|
|
||||||
Result := FilterOn and (Trim(AGrid.Cells[FilterCol,GridRow]) = 'NO');
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure MatRead(const a: DblDyneMat; out NoRows, NoCols: integer;
|
procedure MatRead(const a: DblDyneMat; out NoRows, NoCols: integer;
|
||||||
const means, stddevs: DblDyneVec; out NCases: integer;
|
const means, stddevs: DblDyneVec; out NCases: integer;
|
||||||
const RowLabels, ColLabels: StrDyneVec; const AFileName: string);
|
const RowLabels, ColLabels: StrDyneVec; const AFileName: string);
|
||||||
|
157
applications/lazstats/source/units/gridprocs.pas
Normal file
157
applications/lazstats/source/units/gridprocs.pas
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
unit GridProcs;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Grids,
|
||||||
|
Globals, DictionaryUnit;
|
||||||
|
|
||||||
|
function CollectValues(AGrid: TStringGrid; AColIndex: Integer;
|
||||||
|
AColCheck: IntDyneVec): DblDyneVec;
|
||||||
|
|
||||||
|
procedure GetMinMax(AGrid: TStringGrid; AColIndex: Integer;
|
||||||
|
const AColCheck: IntDyneVec; out AMin, AMax: Double);
|
||||||
|
|
||||||
|
function GoodRecord(AGrid: TStringGrid; ARow: integer;
|
||||||
|
const AColCheck: IntDyneVec): boolean;
|
||||||
|
|
||||||
|
function IsEmptyNumericValue(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||||||
|
|
||||||
|
function IsFiltered(AGrid: TStringGrid; ARow: integer): boolean;
|
||||||
|
|
||||||
|
function IsMissingValueCode(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||||||
|
|
||||||
|
function ValidValue(AGrid: TStringGrid; ARow, ACol: integer): boolean;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Math;
|
||||||
|
|
||||||
|
{ Extracts the values in the given column from the grid and returns them as an
|
||||||
|
array.
|
||||||
|
Cells which are filtered or empty are not considered. This check is extended
|
||||||
|
over all columns specified by the column indices in AColCheck; AColCheck
|
||||||
|
should be empty to consider only the current column.
|
||||||
|
Non-numeric values in the considered cell will raise an exception.
|
||||||
|
|
||||||
|
NOTE: AColCheck must not be overdimensioned! }
|
||||||
|
function CollectValues(AGrid: TStringGrid; AColIndex: Integer; AColCheck: IntDyneVec): DblDyneVec;
|
||||||
|
var
|
||||||
|
row, n: Integer;
|
||||||
|
begin
|
||||||
|
SetLength(Result, AGrid.RowCount);
|
||||||
|
n := 0;
|
||||||
|
for row := 1 to AGrid.RowCount-1 do
|
||||||
|
begin
|
||||||
|
if Length(AColCheck) = 0 then
|
||||||
|
begin
|
||||||
|
if not ValidValue(AGrid, row, AColIndex) then continue;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if not GoodRecord(AGrid, row, AColCheck) then continue;
|
||||||
|
end;
|
||||||
|
Result[n] := StrToFloat(trim(AGrid.Cells[AColIndex, row]));
|
||||||
|
inc(n);
|
||||||
|
end;
|
||||||
|
SetLength(Result, n);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Determines the minimum and maximum of the values in the specified column of
|
||||||
|
the grid. Rows with "invalid" data are ignored. If AColCheck contains other
|
||||||
|
column indices these cells must be "valid", too. }
|
||||||
|
procedure GetMinMax(AGrid: TStringGrid; AColIndex: Integer;
|
||||||
|
const AColCheck: IntDyneVec; out AMin, AMax: Double);
|
||||||
|
var
|
||||||
|
row: Integer;
|
||||||
|
value: Double;
|
||||||
|
begin
|
||||||
|
AMin := Infinity;
|
||||||
|
AMax := -Infinity;
|
||||||
|
for row := 1 to AGrid.RowCount-1 do
|
||||||
|
begin
|
||||||
|
if Length(AColCheck) = 0 then
|
||||||
|
begin
|
||||||
|
if not ValidValue(AGrid, row, AColIndex) then continue;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if not GoodRecord(AGrid, row, AColCheck) then continue;
|
||||||
|
end;
|
||||||
|
value := StrToFloat(trim(AGrid.Cells[AColIndex, row]));
|
||||||
|
if value < AMin then AMin := value;
|
||||||
|
if value > AMax then AMax := value;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Checks whether all cells specified for the given row in the columns listed in
|
||||||
|
the GridPos array are "valid": not filtered and not empty }
|
||||||
|
function GoodRecord(AGrid: TStringGrid; ARow: integer;
|
||||||
|
const AColCheck: IntDyneVec): boolean;
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
for i := 0 to High(AColCheck) do
|
||||||
|
begin
|
||||||
|
j := AColCheck[i];
|
||||||
|
if not ValidValue(AGrid, ARow, j) then
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Checks whether the cell in the given row in the given numeric column is empty. }
|
||||||
|
function IsEmptyNumericValue(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||||||
|
var
|
||||||
|
value: String;
|
||||||
|
isStringField: Boolean;
|
||||||
|
begin
|
||||||
|
value := Trim(AGrid.Cells[ACol, ARow]);
|
||||||
|
isStringField := DictionaryFrm.DictGrid.Cells[4, ACol] = 'S';
|
||||||
|
Result := not IsStringField and (value = '');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Checks whether the specified row is "filtered". Two criteria are needed for
|
||||||
|
a row to be filtered:
|
||||||
|
- The cell in column FilterCol (global value) must contain the text 'NO'.
|
||||||
|
- The global variable "FilterOn" must be TRUE. }
|
||||||
|
function IsFiltered(AGrid: TStringGrid; ARow: integer): boolean;
|
||||||
|
begin
|
||||||
|
Result := FilterOn and (Trim(AGrid.Cells[FilterCol, ARow]) = 'NO');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Checks whether specified cell contains the "missing value code" defined by
|
||||||
|
the Dictionary }
|
||||||
|
function IsMissingValueCode(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||||||
|
var
|
||||||
|
missingCode: String;
|
||||||
|
value: String;
|
||||||
|
begin
|
||||||
|
missingCode := Trim(DictionaryFrm.DictGrid.Cells[6, ACol]);
|
||||||
|
value := Trim(AGrid.Cells[ACol, ARow]);
|
||||||
|
Result := (value = missingCode);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ Checks wheter the value in cell at the given column and row is a not-filtered,
|
||||||
|
non-empty number.
|
||||||
|
NOTE: non-numeric characters in a numeric field are not taken into account! }
|
||||||
|
function ValidValue(AGrid: TStringGrid; ARow, ACol: integer): boolean;
|
||||||
|
begin
|
||||||
|
Result := not (
|
||||||
|
IsFiltered(AGrid, ARow) or // filtering is active and row is marked to be excluded
|
||||||
|
IsEmptyNumericValue(AGrid, ARow, aCol) or // column is numeric, but cell is empty
|
||||||
|
IsMissingValueCode(AGrid, ARow, ACol) // cell contains the "missing value code"
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
Reference in New Issue
Block a user