YOUSEFUL / DELPHI / COMPONENTS
TAtlasBoxPlot
Box-and-whisker chart: one box per sample with quartiles, median, mean, 1.5 IQR whiskers and outliers.
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
| Member | Kind | What it does |
|---|---|---|
Create | constructor | Creates an empty box plot, 480 x 320 pixels, white, with ShowMean and ShowOutliers on, BoxWidthPercent 60 and an automatic ValueAxis. |
Destroy | destructor | Frees the categories and the value axis. |
AddCategory | method | Adds one box for the sample Values and returns its index. |
Clear | method | Removes every category and repaints. |
CategoryName | method | The name given to AddCategory for the category at Index (0-based). |
Stats | method | The TAtlasBoxStats computed for the category at Index: count, quartiles, mean, whiskers and outliers. |
HitTest | method | 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). |
ValueToPixel | method | Where Value falls along the value axis in the most recent render: a Y coordinate for upright boxes, an X coordinate when Rotated. |
CategoryCount | property | Number of categories (boxes). |
PlotRect | property | The rectangle the boxes were drawn in during the most recent render, without axis labels and titles. |
ValueAxis | property | The TAtlasPlotAxis that scales the values. |
Rotated | property | False: boxes stand upright, categories along the bottom, values on the left. |
ShowMean | property | Draws a hollow diamond at each category's mean. |
ShowOutliers | property | Draws values beyond the whiskers as hollow circles. |
BoxWidthPercent | property | Box width as a percentage of the space each category gets, clamped to 5..100. |
BeginUpdate | method from TAtlasCustomChart | Starts a batch of changes: until the matching EndUpdate, property changes and added data do not repaint the control. |
EndUpdate | method from TAtlasCustomChart | Ends a batch started by BeginUpdate. |
Render | method from TAtlasCustomChart | Draws the chart into any TAtlasPlotSurface (for example a TAtlasSvgSurface or a TAtlasCanvasSurface over your own canvas), filling Bounds. |
RenderTo | method from TAtlasCustomChart | Draws the chart onto a VCL canvas, for example a printer canvas or a bitmap you own, filling Bounds. |
CreateBitmap | method from TAtlasCustomChart | Returns a new 24-bit bitmap of the given size with the chart drawn on it; the caller frees it. |
ToSVG | method from TAtlasCustomChart | Returns the chart as an SVG document of the given size (1 to 16384 pixels). |
SaveToFile | method from TAtlasCustomChart | 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. |
PaletteColor | method from TAtlasCustomChart | One of ten built-in series colours (blue, orange, green, red, purple, olive, dark blue, teal, salmon, grey). |
Title | property from TAtlasCustomChart | Bold caption centred at the top. |
Footnote | property from TAtlasCustomChart | Caption centred at the bottom. |
Color | property from TAtlasCustomChart | Background colour, clWhite by default. |
Font | property from TAtlasCustomChart | Font of every caption; the title uses it in bold. |
OnMouseMove | event from TAtlasCustomChart | The 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Box.SaveToFile('chart.png', 800, 500);
Box.SaveToFile('chart.svg'); // the control's own sizePaletteColor 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.
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.
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.
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;Related
TAtlasBoxStats · TAtlasBoxHit · TAtlasBoxPart · TAtlasStats · TAtlasCustomChart · TAtlasPlotAxis