Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Создание диаграммы распределения данных в виде кривой Bell в FastReport из Delphi

Delphi , Базы данных , Отчеты

Создание диаграммы распределения данных в виде кривой Bell в FastReport из Delphi

При портировании домашней отчетности Delphi в FastReport может возникнуть потребность в диаграмме, показывающей распределение значений поля в наборе данных в виде кривой Bell. В этом руководстве мы рассмотрим, как создать такую диаграмму с помощью FastReport и Object Pascal (Delphi).

Проблема

Разработчик портирует домашнюю отчетность Delphi в FastReport и нуждается в диаграмме, показывающей распределение значений поля в наборе данных в виде кривой Bell. Ранее разработчик писал код для сортировки значений поля в ячейки (например, 100) и создавал гистограмму TChart на основе подсчета ячеек (Y) против 1-100 (X). FastReport имеет хорошую интеграцию с TChart, и разработчик может легко выводить линии значений поля. Но существует ли встроенный способ создания диаграммы распределения в FastReport, или нужно создавать новый набор данных отсортированных ячеек и выводить его?

Решение

Разработчик создал класс, который может быть полезен для других пользователей. Этот класс принимает набор данных и выполняет всю сложную работу по созданию списка частотных ячеек для определенного имени поля, а затем кэширует эти данные, чтобы позволить вызов 'GetValue' из TfrxUserDataSet под названием 'Distributions'. Пользователь отчета может просто разместить диаграмму баров в отчете, указать 'Distributions' в качестве набора данных и выбрать требуемое поле для 'Y-значений'. 'X-значения' должны быть установлены на то же имя поля, но с '-X' в конце. Класс разработчика затем прозрачно возвращает X- и Y-значения для диаграммы, создавая частотные ячейки при первом вызове. В этом примере не используется никакой код FastReport.

Хотя этот код и работает, его можно улучшить, например, в настоящее время X-значения охватывают минимум и максимум. Более подходящим отображением было бы использование 3 или 6 сигм (стандартное отклонение), но это легко можно Modify.

Ниже приведен пример кода на Object Pascal (Delphi), реализующий описанное решение:

unit UartFastReportsDistribution;

interface

uses
  DB,
  Classes;

const
  CellCount = 101;

type
  TCellArray = array[0..CellCount-1] of integer;
  TXValues = array[0..CellCount-1] of double;

  TDistributionCells = class(TObject)
  private
    FDataSet: TDataSet;
    FFieldName: string;
    FCells: TCellArray;
    FLastRecNo: integer;
    FCellsMax: integer;
    FDataMin, FDataMax: double;
    procedure BuildCells;
    function XValue(AIndex: integer): double;
    function YValue(AIndex: integer): double;
    function DataMean: double;
    function DataDevPk: double;
  end;

  TArtFastReportsDistribution = class(TObject)
  private
    FDataSet: TDataSet;
    FDistributions: TStringList;
    function NameToDistribution(const AFieldName: string): TDistributionCells;
  public
    constructor Create(ADataSet: TDataSet);
    destructor Destroy; override;
    procedure DoGetData(const AFieldName: string; ARecNo: integer; var Value: Variant);
    function RecordCount: integer;
  end;

implementation

uses
  Math,
  SysUtils;

{ TArtFastReportsDistribution }

function TArtFastReportsDistribution.NameToDistribution(const AFieldName: string): TDistributionCells;
var
  I: integer;
begin
  I := FDistributions.IndexOf(AFieldName);
  if I = -1 then
    begin
    Result := TDistributionCells.Create(FDataSet, AFieldName);
    FDistributions.AddObject(AFieldName, Result);
    end
  else
    Result := FDistributions.Objects[I] as TDistributionCells;
end;

constructor TArtFastReportsDistribution.Create(ADataSet: TDataSet);
begin
  inherited Create;
  FDataSet := ADataSet;
  FDistributions := TStringList.Create;
  FDistributions.OwnsObjects := True;
end;

destructor TArtFastReportsDistribution.Destroy;
begin
  FreeAndNil(FDistributions);
  inherited;
end;

procedure TArtFastReportsDistribution.DoGetData(const AFieldName: string; ARecNo: integer; var Value: Variant);
var
  sFieldName: string;
  bIsXValue: boolean;
  I: integer;
  Dist: TDistributionCells;
begin
  sFieldName := AFieldName;
  I := Pos('-X', sFieldName);
  bIsXValue := I > 0;
  if bIsXValue then
    Delete(sFieldName, I, MaxInt);

  Dist := NameToDistribution(sFieldName);

  If (ARecNo = 1) and (Dist.FLastRecNo <> 1) then
    Dist.BuildCells;

  Dist.FLastRecNo := ARecNo;

  if bIsXValue then
    Value := Dist.XValue(ARecNo - 1)
  else
    Value := Dist.YValue(ARecNo - 1);
end;

function TArtFastReportsDistribution.RecordCount: integer;
begin
  Result := CellCount;
end;

{ TDistributionCells }

procedure TDistributionCells.BuildCells;
procedure ClearCells;
var
  I: integer;
begin
  for I := 0 to CellCount - 1 do
    FCells[I] := 0;

  FCellsMax := 0;
  FDataMin := 0.0;
  FDataMax := 0.0;
end;

function GetDataSetFieldValues: TFloatArray;
var
  I: integer;
  Field: TField;
begin
  Field := FDataSet.FieldByName(FFieldName);
  if not Assigned(Field) then
    Raise Exception.CreateFmt('Missing distribution field "%s"', [FFieldName]);

  SetLength(Result, FDataSet.RecordCount);
  FDataSet.First;
  I := 0;
  While not FDataset.EOF do
  begin
    Result[I] := Field.AsFloat;
    Inc(I);
    FDataSet.Next;
  end;
end;

var
  I,
  iCellCount,
  iOffset: integer;
  F: double;
  Data: TFloatArray;
begin
  ClearCells;

  If FDataSet.RecordCount = 0 then
    Exit;

  Data := GetDataSetFieldValues;

  FDataMin := MinValue(Data);
  FDataMax := MaxValue(Data);

  FCellsMax := 0;
  iCellCount := Length(FCells);

  for I := 0 to Length(Data) - 1 do
  begin
    F := Data[I];

    F := (F - DataMean + DataDevPk) / (2 * DataDevPk);
    iOffset := Trunc(iCellCount * F);
    If iOffset < 0 then
      iOffset := 0
    else
      If iOffset > iCellCount - 1 then
        iOffset := CellCount - 1;
    FCells[iOffset] := FCells[iOffset] + 1;

    If I = 0 then
      FCellsMax := FCells[iOffset]
    else
      FCellsMax := Max(FCells[iOffset], FCellsMax);
  end;
end;

constructor TDistributionCells.Create(ADataSet: TDataSet; const AFieldName: string);
begin
  inherited Create;
  FDataSet := ADataSet;
  FFieldName := AFieldName;
end;

function TDistributionCells.DataDevPk: double;
begin
  Result := FDataMax - DataMean;
end;

function TDistributionCells.DataMean: double;
begin
  Result := (FDataMin + FDataMax) / 2;
end;

function TDistributionCells.XValue(AIndex: integer): double;
begin
  Result := AIndex;
  Result := (Result / CellCount) - 0.5;
  Result := DataMean + (Result * 2 * DataDevPk);
end;

function TDistributionCells.YValue(AIndex: integer): double;
begin
  Result := FCells[AIndex];
end;

end.

Используя этот код, вы можете создать диаграмму распределения данных в виде кривой Bell в FastReport из Delphi, не прибегая к созданию нового набора данных отсортированных ячеек.

Создано по материалам из источника по ссылке.

Краткое описание: "Создание диаграммы распределения данных в виде кривой Bell в FastReport из Delphi."


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Отчеты ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-11-21 11:32:51/0.0056390762329102/1