YOUSEFUL / DELPHI / COMPONENTS

TAtlasBoxPlot

Box-and-whisker chart: one box per sample with quartiles, median, mean, 1.5 IQR whiskers and outliers.

Visual control Palette: Atlas Plot Unit Atlas.BoxPlot · Inherits TAtlasCustomChart · Product Atlas Plot Pro

Description

A box-and-whisker chart. Each category is one sample of numbers, summarised once by TAtlasStats.Box when you add it: the box spans the first to the third quartile with a thick median line in the category colour, a hollow diamond marks the mean (ShowMean), the whiskers reach the most extreme values within 1.5 interquartile ranges of the box, and values beyond are drawn as hollow circles (ShowOutliers). Quartiles interpolate linearly between closest ranks. The box fill is the category colour blended 60 % towards the background.

Boxes stand upright with the value axis on the left, or lie left to right when Rotated. The value axis is a TAtlasPlotAxis: automatic by default, fixed with ValueAxis.SetRange, and whatever falls outside a fixed range is clipped from both drawing and hit testing. An empty chart shows "No data".

The chart keeps only the statistics, not the raw values; Stats returns them. HitTest, ValueToPixel and PlotRect describe the most recent render. Title, footnote, batching and export come from TAtlasCustomChart. Use the control from the main thread. There are no notches, no groups of several boxes per category and no data binding; the control is VCL only (no FMX).

Members

MemberKindWhat it does
CreateconstructorCreates an empty box plot, 480 x 320 pixels, white, with ShowMean and ShowOutliers on, BoxWidthPercent 60 and an automatic ValueAxis.
DestroydestructorFrees the categories and the value axis.
AddCategorymethodAdds one box for the sample Values and returns its index.
ClearmethodRemoves every category and repaints.
CategoryNamemethodThe name given to AddCategory for the category at Index (0-based).
StatsmethodThe TAtlasBoxStats computed for the category at Index: count, quartiles, mean, whiskers and outliers.
HitTestmethodWhat lies at the pixel (X, Y) in the most recent render: an outlier, a box or a whisker (checked in that order, the order they are drawn).
ValueToPixelmethodWhere Value falls along the value axis in the most recent render: a Y coordinate for upright boxes, an X coordinate when Rotated.
CategoryCountpropertyNumber of categories (boxes).
PlotRectpropertyThe rectangle the boxes were drawn in during the most recent render, without axis labels and titles.
ValueAxispropertyThe TAtlasPlotAxis that scales the values.
RotatedpropertyFalse: boxes stand upright, categories along the bottom, values on the left.
ShowMeanpropertyDraws a hollow diamond at each category's mean.
ShowOutlierspropertyDraws values beyond the whiskers as hollow circles.
BoxWidthPercentpropertyBox width as a percentage of the space each category gets, clamped to 5..100.
BeginUpdatemethod from TAtlasCustomChartStarts a batch of changes: until the matching EndUpdate, property changes and added data do not repaint the control.
EndUpdatemethod from TAtlasCustomChartEnds a batch started by BeginUpdate.
Rendermethod from TAtlasCustomChartDraws the chart into any TAtlasPlotSurface (for example a TAtlasSvgSurface or a TAtlasCanvasSurface over your own canvas), filling Bounds.
RenderTomethod from TAtlasCustomChartDraws the chart onto a VCL canvas, for example a printer canvas or a bitmap you own, filling Bounds.
CreateBitmapmethod from TAtlasCustomChartReturns a new 24-bit bitmap of the given size with the chart drawn on it; the caller frees it.
ToSVGmethod from TAtlasCustomChartReturns the chart as an SVG document of the given size (1 to 16384 pixels).
SaveToFilemethod from TAtlasCustomChartWrites the chart to .png, .bmp, .emf or .svg, chosen by the extension (case does not matter); any other extension raises EAtlasPlotError before anything is written.
PaletteColormethod from TAtlasCustomChartOne of ten built-in series colours (blue, orange, green, red, purple, olive, dark blue, teal, salmon, grey).
Titleproperty from TAtlasCustomChartBold caption centred at the top.
Footnoteproperty from TAtlasCustomChartCaption centred at the bottom.
Colorproperty from TAtlasCustomChartBackground colour, clWhite by default.
Fontproperty from TAtlasCustomChartFont of every caption; the title uses it in bold.
OnMouseMoveevent from TAtlasCustomChartThe standard VCL mouse event, published by the base class.

Constructors

Create constructor

constructor Create(AOwner: TComponent); override;

Creates an empty box plot, 480 x 320 pixels, white, with ShowMean and ShowOutliers on, BoxWidthPercent 60 and an automatic ValueAxis. Set Parent to show it; without a parent it can still render to bitmaps and files.

Destructors

Destroy destructor

destructor Destroy; override;

Frees the categories and the value axis. Free the control yourself only when it has no owner.

Properties

CategoryCount property

property CategoryCount: Integer read GetCategoryCount;

Number of categories (boxes).

PlotRect property

property PlotRect: TRect read FPlot;

The rectangle the boxes were drawn in during the most recent render, without axis labels and titles. Empty before the first render and when there are no categories.

ValueAxis property

property ValueAxis: TAtlasPlotAxis read FValueAxis write SetValueAxis;

The TAtlasPlotAxis that scales the values. Automatic by default: the range covers every category's minimum and maximum (only the whiskers when outliers are hidden), rounded outward to whole ticks. ValueAxis.SetRange(Low, High) fixes it; anything outside is clipped. Title is drawn beside the axis, Grid switches the grid lines, LabelFormat formats the tick captions and Inverted reverses the direction. Assigning copies the settings of another axis.

pascal
Box.ValueAxis.Title := 'Milliseconds';
Box.ValueAxis.SetRange(0, 100);

Rotated property

property Rotated: Boolean read FRotated write SetRotated default False;

False: boxes stand upright, categories along the bottom, values on the left. True: boxes lie left to right, categories down the left side, values along the bottom.

ShowMean property

property ShowMean: Boolean read FShowMean write SetShowMean default True;

Draws a hollow diamond at each category's mean.

ShowOutliers property

property ShowOutliers: Boolean read FShowOutliers write SetShowOutliers default True;

Draws values beyond the whiskers as hollow circles. When False, outliers are neither drawn nor hit, and they no longer stretch an automatic value axis.

BoxWidthPercent property

property BoxWidthPercent: Integer read FBoxWidthPercent write SetBoxWidthPercent default 60;

Box width as a percentage of the space each category gets, clamped to 5..100. The half-width is also capped at three text lines, so boxes stay slim on wide charts.

Title propertyinherited from TAtlasCustomChart

property Title: string read FTitle write SetTitle;

Bold caption centred at the top. Empty (the default) leaves no room for it.

Footnote propertyinherited from TAtlasCustomChart

property Footnote: string read FFootnote write SetFootnote;

Caption centred at the bottom. Empty (the default) leaves no room for it.

Color propertyinherited from TAtlasCustomChart

property Color default clWhite;

Background colour, clWhite by default. Chart parts are blended towards it (box fills, radar fills), and heat map cells are outlined with it.

Font propertyinherited from TAtlasCustomChart

property Font;

Font of every caption; the title uses it in bold. The height of Ag in this font (at least 8 pixels) sets the chart's margins, label spacing and marker sizes. Changing it repaints the control.

Events

OnMouseMove eventinherited from TAtlasCustomChart

property OnMouseMove;

The standard VCL mouse event, published by the base class. Pass X and Y to HitTest to find what is under the pointer.

Methods

AddCategory method

function AddCategory(const Name: string; const Values: TArray<Double>; Color: TColor = clDefault): Integer;

Adds one box for the sample Values and returns its index. The sample is summarised at once with TAtlasStats.Box; the raw values are not kept, so later changes to the array have no effect. Color clDefault uses PaletteColor(Index). An empty sample, NaN, infinite values or magnitudes above 1E100 raise EAtlasPlotError and add nothing.

pascal
Index := Box.AddCategory('Gateway', [12, 15, 15, 17, 18, 18, 18, 20, 21, 60], clNavy);

Clear method

procedure Clear;

Removes every category and repaints.

CategoryName method

function CategoryName(Index: Integer): string;

The name given to AddCategory for the category at Index (0-based). An index outside 0..CategoryCount - 1 raises the list's range error.

Stats method

function Stats(Index: Integer): TAtlasBoxStats;

The TAtlasBoxStats computed for the category at Index: count, quartiles, mean, whiskers and outliers. Available as soon as the category is added, before any render.

pascal
Summary := Box.Stats(0);
Text := Format('median %.1f, %d outlier(s)', [Summary.Median, Length(Summary.Outliers)]);

HitTest method

function HitTest(X, Y: Integer): TAtlasBoxHit;

What lies at the pixel (X, Y) in the most recent render: an outlier, a box or a whisker (checked in that order, the order they are drawn). The whisker region is the rectangle from the low to the high whisker, as wide as the whisker caps. Regions are clipped to the plot like the drawing, so a value outside a manual ValueAxis range cannot be hit. Returns Part = bpNone with Category and Outlier -1 when nothing is there or before the first render. Hidden outliers (ShowOutliers False) are not hit.

pascal
Hit := Box.HitTest(X, Y);
if Hit.Part = bpOutlier then
  Value := Box.Stats(Hit.Category).Outliers[Hit.Outlier];

ValueToPixel method

function ValueToPixel(const Value: Double): Integer;

Where Value falls along the value axis in the most recent render: a Y coordinate for upright boxes, an X coordinate when Rotated. Returns -1 before any render, without categories, or when the last target was too small to lay out. The result is not clipped to PlotRect.

BeginUpdate methodinherited from TAtlasCustomChart

procedure BeginUpdate;

Starts a batch of changes: until the matching EndUpdate, property changes and added data do not repaint the control. Calls nest.

pascal
Box.BeginUpdate;
try
  Box.Title := 'Updated';
  Box.Footnote := 'Source: monitoring';
finally
  Box.EndUpdate;
end;

EndUpdate methodinherited from TAtlasCustomChart

procedure EndUpdate;

Ends a batch started by BeginUpdate. When the outermost batch ends the control is invalidated once. A call without a matching BeginUpdate is ignored.

Render methodinherited from TAtlasCustomChart

procedure Render(ASurface: TAtlasPlotSurface; const Bounds: TRect);

Draws the chart into any TAtlasPlotSurface (for example a TAtlasSvgSurface or a TAtlasCanvasSurface over your own canvas), filling Bounds. Raises EAtlasPlotError when ASurface is nil. Pixel queries such as HitTest then describe this render; unlike the other output methods, Render does not restore the on-screen layout afterwards.

pascal
Svg := TAtlasSvgSurface.Create(600, 400);
try
  Box.Render(Svg, Rect(0, 0, 600, 400));
  Text := Svg.Document;
finally
  Svg.Free;
end;

RenderTo methodinherited from TAtlasCustomChart

procedure RenderTo(Target: TCanvas; const Bounds: TRect);

Draws the chart onto a VCL canvas, for example a printer canvas or a bitmap you own, filling Bounds. When the control has a window handle it then re-runs its on-screen layout, so hit tests keep matching the screen.

pascal
Box.RenderTo(Bitmap.Canvas, Rect(0, 0, Bitmap.Width, Bitmap.Height));

CreateBitmap methodinherited from TAtlasCustomChart

function CreateBitmap(AWidth, AHeight: Integer): Vcl.Graphics.TBitmap;

Returns a new 24-bit bitmap of the given size with the chart drawn on it; the caller frees it. Both sizes must be 1 to 16384 pixels, otherwise EAtlasPlotError is raised. Works without a window, for example in a console program or a service.

pascal
Bitmap := Box.CreateBitmap(800, 500);
try
  Bitmap.SaveToFile('chart.bmp');
finally
  Bitmap.Free;
end;

ToSVG methodinherited from TAtlasCustomChart

function ToSVG(AWidth, AHeight: Integer): string;

Returns the chart as an SVG document of the given size (1 to 16384 pixels). Text is XML-escaped. Works without a window.

pascal
Text := Box.ToSVG(640, 420);

SaveToFile methodinherited from TAtlasCustomChart

procedure SaveToFile(const FileName: string; AWidth: Integer = 0; AHeight: Integer = 0);

Writes the chart to .png, .bmp, .emf or .svg, chosen by the extension (case does not matter); any other extension raises EAtlasPlotError before anything is written. A size of 0 or less uses the control's Width and Height; sizes above 16384 raise. The image is written to FileName.part and then renamed over the target, so a failed export keeps an existing file. Works without a window.

pascal
Box.SaveToFile('chart.png', 800, 500);
Box.SaveToFile('chart.svg');   // the control's own size

PaletteColor methodinherited from TAtlasCustomChart

class function PaletteColor(Index: Integer): TColor; static;

One of ten built-in series colours (blue, orange, green, red, purple, olive, dark blue, teal, salmon, grey). The index wraps: PaletteColor(10) equals PaletteColor(0), and negative indexes use their absolute value. Categories and series with colour clDefault take PaletteColor of their index.

pascal
Box.Color := TAtlasCustomChart.PaletteColor(3);

Examples

Compare response times of two services

Creates a box plot on a form and reports the box under the mouse.

pascal
uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Atlas.BoxPlot;

type
  TBoxReport = class
    Box: TAtlasBoxPlot;
    Status: TLabel;
    procedure BoxMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  end;

procedure TBoxReport.BoxMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var Hit: TAtlasBoxHit;
begin
  Hit := Box.HitTest(X, Y);
  if Hit.Part <> bpNone then
    Status.Caption := Format('%s: median %.1f ms', [Box.CategoryName(Hit.Category), Box.Stats(Hit.Category).Median]);
end;

function AddResponseTimes(Form: TForm; Report: TBoxReport): TAtlasBoxPlot;
begin
  Result := TAtlasBoxPlot.Create(Form);
  Result.Parent := Form;
  Result.Align := alClient;
  Result.Title := 'Response time by service';
  Result.ValueAxis.Title := 'ms';
  Result.AddCategory('Gateway', [12, 15, 15, 17, 18, 18, 18, 20, 21, 60]);
  Result.AddCategory('Search', [30, 31, 35, 36, 38, 40, 41, 45]);
  Report.Box := Result;
  Result.OnMouseMove := Report.BoxMouseMove;
end;

Export a rotated box plot without a window

A box plot needs no parent to render; this writes a PNG from a console program or service.

pascal
uses
  Atlas.BoxPlot;

procedure SaveLatencyChart(const FileName: string);
var Box: TAtlasBoxPlot;
begin
  Box := TAtlasBoxPlot.Create(nil);
  try
    Box.Rotated := True;
    Box.ShowMean := False;
    Box.AddCategory('Monday', [110, 120, 125, 130, 180]);
    Box.AddCategory('Tuesday', [100, 105, 115, 118, 121]);
    Box.SaveToFile(FileName, 800, 400);   // .png, .bmp, .emf or .svg
  finally
    Box.Free;
  end;
end;

TAtlasBoxStats · TAtlasBoxHit · TAtlasBoxPart · TAtlasStats · TAtlasCustomChart · TAtlasPlotAxis

Also in Atlas Plot Pro

TAtlasHeatMap · TAtlasPolarPlot