YOUSEFUL / DELPHI
Atlas Plot Pro: FAQ, examples and tutorial
Learning center · Component reference
Atlas Plot Pro adds statistics and three specialised chart controls to Atlas Plot: TAtlasBoxPlot (box-and-whisker), TAtlasHeatMap (a value matrix as coloured cells) and TAtlasPolarPlot (a radar chart), plus TAtlasPlotAnalysis, which adds a histogram, a polynomial fit or a smoothed copy as a new series of an Atlas Plot TAtlasPlot. Add Atlas.PlotStats for TAtlasStats, Atlas.BoxPlot, Atlas.HeatMap or Atlas.PolarPlot for a control, Atlas.PlotAnalysis for analysis series, and Atlas.PlotAxis when you catch EAtlasPlotError, which every unit raises on invalid input. The product requires Atlas Plot, which supplies the axis, the drawing surface and TAtlasPlot; the three controls are on the Atlas Plot palette page. It is VCL only and has been built for Win32 and Win64.
FAQ
What does Atlas Plot Pro add to Atlas Plot? Chart forms that TAtlasPlot cannot draw (box plots, heat maps, radar charts), statistics as plain functions that need no chart, and helpers that add computed series to a TAtlasPlot. It is a separate package on top of Atlas Plot and does not change TAtlasPlot itself. Line, bar, area, point and pie series, axes, zoom and export of general charts remain Atlas Plot's job; see its component reference.
Which packages do I need at run time? Either link the units into your program (the samples do this, and then no packages are needed), or build with runtime packages: AtlasPlotProRuntime370.bpl needs AtlasPlotRuntime370.bpl beside it or on PATH. The design package AtlasPlotProDesign registers TAtlasBoxPlot, TAtlasHeatMap and TAtlasPolarPlot on the Atlas Plot page. It compiles, but installing it in the IDE and using the controls in the form designer have not been tested; creating the controls in code is the verified path. See Getting started for building the packages.
How are quartiles, whiskers and outliers defined? Quantiles interpolate linearly between closest ranks: position (n - 1) * Fraction in the sorted values, the common "type 7" (spreadsheet QUARTILE.INC). Whiskers end at the most extreme values within 1.5 interquartile ranges of the box, and anything beyond is an outlier. TAtlasStats.Box computes all of it and TAtlasBoxPlot draws exactly those numbers. The standard deviation is the sample one (divides by n - 1).
How does the histogram choose its bins? Pass a bin count from 1 to 10000, or 0 for Sturges' rule, ceil(log2 n) + 1. Bins have equal width from the minimum to the maximum and are half open, [edge, next edge), except the last, which includes the maximum. When all values are equal there is one bin of width one centred on them. BinOf finds a value's bin by binary search, so values exactly on an edge land in the right bin.
Why does PolynomialFit raise, and can I fit dates? Degrees 1 to 6 are supported, and a fit needs at least Degree + 1 points with more distinct X values than the degree; otherwise it raises EAtlasPlotError with "A fit needs more distinct arguments than its degree". Arguments are scaled to -1..1 before fitting, so TDateTime values (around 46,000) and other large arguments give accurate fits. The coefficients are not exposed; use Evaluate, which also extrapolates.
How do I show missing values? In a heat map and a radar chart, use NaN: it is an empty cell (drawn in EmptyColor) or a gap in the radar outline. The statistics functions and TAtlasBoxPlot.AddCategory reject NaN, infinite values and magnitudes above 1E100 with EAtlasPlotError, so filter missing values out of a sample first. Nothing is ever changed by a rejected call.
Can I render charts without showing a window? Yes. Create a control with no owner and no parent and call SaveToFile (.png, .bmp, .emf or .svg), CreateBitmap, ToSVG, RenderTo or Render. This works in console programs and services; the Statistics console sample does it. A file is written beside the target and renamed, so a failed export keeps the old file.
Do hit tests still match the screen after an export? Yes. HitTest, ValueToPixel, CellRect, PlotRect, Centre and Radius describe the most recent render. After SaveToFile, CreateBitmap, ToSVG or RenderTo, a control with a window handle re-runs its on-screen layout, so an 800 x 500 export does not break mouse handling on a smaller control. Only Render into your own surface leaves the queries describing that render.
Can I write my own chart type? Yes: derive from TAtlasCustomChart and override DrawChart and ResetLayout. You get the title, footnote, legend helper, batching and all export formats. The custom chart type sample writes one with hit testing.
Is any of it thread-safe? The TAtlasStats functions keep no state and never modify their input, so they can be called from any thread. The controls are VCL controls with no locking; create, change and render them from the main thread.
What is not implemented? No FMX version and no Win64 ARM (ARM64EC) build: only Win32 and Win64 were compiled. Also missing: secondary or multiple value axes (they need changes inside TAtlasPlot); bubble, error bar, range/Gantt bar, waterfall, funnel, gauge, contour, surface and other 3D series; true angle/radius polar series and wind roses (the radar chart is category based); annotations, cursors, draggable points, animations, gradients and transparency (the drawing surface has no alpha, so radar fills are opaque); data-aware series; a chart editor dialog; print preview. High-DPI switching, VCL styles, printing and accessibility have not been tested.
Examples
Summarise a sample with TAtlasStats: quartiles, whiskers at 1.5 IQR, outliers and the sample standard deviation.
uses
System.SysUtils, Atlas.PlotStats;
function Summary(const Values: TArray<Double>): string;
var Box: TAtlasBoxStats;
begin
Box := TAtlasStats.Box(Values);
Result := Format('Q1 %.2f, median %.2f, Q3 %.2f, whiskers %.0f..%.0f, %d outlier(s), sd %.2f',
[Box.Q1, Box.Median, Box.Q3, Box.LowWhisker, Box.HighWhisker, Length(Box.Outliers),
TAtlasStats.StdDev(Values)]);
end;For Summary([1, 2, 3, 4, 5, 6, 7, 8, 9, 40]) the result is Q1 3.25, median 5.50, Q3 7.75, whiskers 1..9, 1 outlier(s), sd 11.37; 40 lies beyond Q3 + 1.5 * IQR = 14.5.
Count values in histogram bins and find the bin of a value. The last bin includes the maximum.
uses
System.SysUtils, System.Classes, Atlas.PlotStats;
procedure ListBins(Target: TStrings);
var Bars: TAtlasHistogram; I: Integer;
begin
Bars := TAtlasStats.Histogram([1, 2, 2, 3, 3, 3, 4, 4, 5], 4);
for I := 0 to High(Bars.Counts) do
Target.Add(Format('%g..%g: %d', [Bars.Edges[I], Bars.Edges[I + 1], Bars.Counts[I]]));
Target.Add(Format('4.5 is in bin %d', [Bars.BinOf(4.5)]));
end;Adds 1..2: 1, 2..3: 2, 3..4: 3, 4..5: 3 and 4.5 is in bin 3. With Bins 0 the same data gets five bins (Sturges' rule, ceil(log2 9) + 1).
Fit a quadratic and extrapolate. The fit is computed on arguments scaled to -1..1, so it also works for date values.
uses
System.SysUtils, Atlas.PlotStats;
function Extrapolate: string;
var Fit: TAtlasPolynomial;
begin
Fit := TAtlasStats.PolynomialFit([-2, -1, 0, 1, 2], [9, 3, 1, 3, 9], 2);
Result := Format('degree %d, R squared %.3f, f(3) = %.3f', [Fit.Degree, Fit.RSquared, Fit.Evaluate(3)]);
end;Returns degree 2, R squared 1.000, f(3) = 19.000: the points lie exactly on y = 2x² + 1.
Put a box plot on a form. Each call to AddCategory summarises its sample at once.
uses
Vcl.Controls, Vcl.Forms, Atlas.BoxPlot;
function AddBoxPlot(Form: TForm): 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]);
end;Two boxes on an automatic value axis from 10 to 60; the Gateway box spans 15.5 to 19.5 with its median at 18, and 60 is drawn as a hollow outlier circle.
Show a matrix as a heat map with a three-stop gradient, a fixed scale and an empty cell.
uses
System.Math, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Atlas.HeatMap;
function AddHeatMap(Form: TForm): TAtlasHeatMap;
begin
Result := TAtlasHeatMap.Create(Form);
Result.Parent := Form;
Result.Align := alClient;
Result.RowLabels.CommaText := 'Mon,Tue,Wed';
Result.ColumnLabels.CommaText := '00,06,12,18';
Result.LoadMatrix([[12, 35, 80, 44], [10, NaN, 85, 40], [15, 38, 91, 52]]);
Result.LowColor := clWhite;
Result.MidColor := clYellow;
Result.HighColor := clRed;
Result.SetScale(0, 100);
Result.ShowValues := True;
end;A 3 x 4 grid from white through yellow (50) to red (100), values printed in black or white where they fit, Tuesday 06 in light grey, and a 0..100 colour bar on the right.
Compare two series on a radar chart. Set the categories first; NaN leaves a gap.
uses
System.Math, Vcl.Controls, Vcl.Forms, Atlas.PolarPlot;
function AddRadar(Form: TForm): TAtlasPolarPlot;
begin
Result := TAtlasPolarPlot.Create(Form);
Result.Parent := Form;
Result.Align := alClient;
Result.RadialAxis.SetRange(0, 10);
Result.Categories.CommaText := 'Speed,Reliability,Price,Support,"Ease of use"';
Result.AddSeries('Release 4', [7, 8.5, 6, 5, 7.5]);
Result.AddSeries('Release 5', [8.5, 9, 6.5, NaN, 8]);
end;A pentagon grid with Speed at twelve o'clock, a filled blue shape for Release 4 and an open orange outline for Release 5 with a gap at Support (a series with a gap is not filled), and a legend on the right.
Add a polynomial fit and a smoothed line to measured points on a TAtlasPlot.
uses
System.SysUtils, Vcl.Controls, Vcl.Forms, Atlas.PlotSeries, Atlas.Plot, Atlas.PlotAnalysis;
function AddFittedPlot(Form: TForm): TAtlasPlot;
var Measured: TAtlasPlotSeries; I: Integer; RSquared: Double;
begin
Result := TAtlasPlot.Create(Form);
Result.Parent := Form;
Result.Align := alClient;
Measured := Result.AddSeries('Measured', pkPoint);
for I := 0 to 40 do
Measured.Add(I / 4, 3 + 0.9 * (I / 4) - 0.35 * Sqr(I / 4 - 5) + 1.5 * Sin(I * 2.3));
TAtlasPlotAnalysis.AddPolynomialFit(Result, Measured, 2, RSquared).LineWidth := 3;
TAtlasPlotAnalysis.AddExponentialSmoothing(Result, Measured, 0.3);
Result.Title := Format('Quadratic fit, R squared %.3f', [RSquared]);
end;Three series: the points, a 64-point curve titled Measured fit(2) and Measured smooth(0.3); the title reads Quadratic fit, R squared 0.928.
Export a chart from a console program or service; no window is needed.
uses
Atlas.BoxPlot;
procedure ExportBoxPlot;
var Box: TAtlasBoxPlot;
begin
Box := TAtlasBoxPlot.Create(nil);
try
Box.AddCategory('Gateway', [12, 15, 15, 17, 18, 18, 18, 20, 21, 60]);
Box.SaveToFile('box.png', 800, 500);
Box.SaveToFile('box.svg', 800, 500);
Box.SaveToFile('box.emf', 800, 500);
finally
Box.Free;
end;
end;Writes box.png, box.svg and box.emf. Any other extension raises EAtlasPlotError before a file is touched.
Tutorial
Sample project: Statistics console.
Goal: compute quantiles, box statistics, a histogram, a correlation, polynomial fits and a smoothed series on data whose answers you know, check every result, and save a heat map and a box plot to files without opening a window.
- Create a console application in Delphi 13 and save it as
StatisticsConsole.dpr. Add the Atlas Plot Prosrcfolder and the Atlas Plotsrcfolder to the project's search path. Replace the generated code with the program header, theusesclause and two helpers:Expectraises when a result is wrong and printsok:when it is right,Nearcompares doubles.
program StatisticsConsole;
// Atlas Plot Pro quick start: statistics on known data, then a heat map
// and a box plot written to image files without a window. Every result is
// checked against a value worked out by hand; a mismatch raises and the
// program exits with code 1.
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.StrUtils, System.Math, System.IOUtils, Winapi.Windows, Vcl.Graphics,
Atlas.PlotAxis, Atlas.PlotStats, Atlas.BoxPlot, Atlas.HeatMap;
procedure Expect(Condition: Boolean; const What: string);
begin
if not Condition then raise Exception.Create('Unexpected result: ' + What);
Writeln(' ok: ', What);
end;
function Near(const A, B: Double): Boolean;
begin
Result := Abs(A - B) < 1E-9;
end;- Add the quantiles.
Quantilesorts a copy of the values and interpolates between closest ranks, so 1..10 in any order has its first quartile at 3.25.
procedure Quantiles;
var Values: TArray<Double>;
begin
Writeln('Quantiles of 1..10 in shuffled order');
Values := [7, 2, 9, 4, 5, 3, 8, 6, 1, 10];
Writeln(Format(' Q1 %.2f median %.2f Q3 %.2f mean %.2f sd %.4f',
[TAtlasStats.Quantile(Values, 0.25), TAtlasStats.Quantile(Values, 0.5),
TAtlasStats.Quantile(Values, 0.75), TAtlasStats.Mean(Values), TAtlasStats.StdDev(Values)]));
Expect(Near(TAtlasStats.Quantile(Values, 0.25), 3.25), 'first quartile interpolates between ranks 3 and 4');
Expect(Near(TAtlasStats.Quantile(Values, 0.5), 5.5), 'median of an even count is the middle pair average');
Expect(Near(TAtlasStats.Mean(Values), 5.5) and Near(TAtlasStats.StdDev(Values), Sqrt(82.5 / 9)), 'mean and sample standard deviation');
end;- Add the box statistics.
TAtlasStats.Boxreturns quartiles, whiskers and outliers in one record; 40 lies beyondQ3 + 1.5 * IQR= 14.5, so the high whisker stops at 9.
procedure BoxStatistics;
var Box: TAtlasBoxStats;
begin
Writeln('Box statistics of 1..9 and one slow value, 40');
Box := TAtlasStats.Box([1, 2, 3, 4, 5, 6, 7, 8, 9, 40]);
Writeln(Format(' box %.2f..%.2f whiskers %.0f..%.0f %d outlier(s)',
[Box.Q1, Box.Q3, Box.LowWhisker, Box.HighWhisker, Length(Box.Outliers)]));
Expect(Near(Box.Q1, 3.25) and Near(Box.Median, 5.5) and Near(Box.Q3, 7.75), 'quartiles');
Expect(Near(Box.LowWhisker, 1) and Near(Box.HighWhisker, 9), 'whiskers stop at the last value within 1.5 IQR');
Expect((Length(Box.Outliers) = 1) and Near(Box.Outliers[0], 40), '40 is the only outlier');
end;- Add the histogram. Four bins over 1..5 are
[1, 2),[2, 3),[3, 4)and[4, 5];BinOfreturns -1 outside them, andBins0 applies Sturges' rule.
procedure Histogram;
var Bars: TAtlasHistogram; I: Integer;
begin
Writeln('Histogram of 1 2 2 3 3 3 4 4 5 in four bins');
Bars := TAtlasStats.Histogram([1, 2, 2, 3, 3, 3, 4, 4, 5], 4);
for I := 0 to High(Bars.Counts) do
Writeln(Format(' [%.0f, %.0f%s: %d', [Bars.Edges[I], Bars.Edges[I + 1], IfThen(I = High(Bars.Counts), ']', ')'), Bars.Counts[I]]));
Expect((Bars.Counts[0] = 1) and (Bars.Counts[1] = 2) and (Bars.Counts[2] = 3) and (Bars.Counts[3] = 3), 'bins are half open, the last one closed');
Expect((Bars.BinOf(2) = 1) and (Bars.BinOf(5) = 3) and (Bars.BinOf(6) = -1), 'BinOf finds the bin; outside the range is -1');
Expect(Length(TAtlasStats.Histogram([1, 2, 2, 3, 3, 3, 4, 4, 5]).Counts) = 5, 'Bins = 0 applies Sturges'' rule: ceil(log2 9) + 1 = 5');
end;- Add the correlation and the two polynomial fits. The quadratic goes exactly through a parabola, so it also predicts 171 at x = 10, well outside the data; a straight line through the same points has an R squared of about 0.30.
procedure CorrelationAndFit;
var X, Y: TArray<Double>; I: Integer; Fit: TAtlasPolynomial;
begin
Writeln('Correlation and least-squares fits');
Writeln(Format(' r = %.2f', [TAtlasStats.Correlation([1, 2, 3, 4, 5], [2, 1, 4, 3, 5])]));
Expect(Near(TAtlasStats.Correlation([1, 2, 3, 4, 5], [2, 1, 4, 3, 5]), 0.8), 'Pearson r of a partly ordered pair is 0.8');
SetLength(X, 9);
SetLength(Y, 9);
for I := 0 to 8 do
begin
X[I] := I - 4;
Y[I] := 2 * X[I] * X[I] - 3 * X[I] + 1; // an exact parabola
end;
Fit := TAtlasStats.PolynomialFit(X, Y, 2);
Writeln(Format(' quadratic: degree %d, R squared %.4f, value at 10 = %.4f', [Fit.Degree, Fit.RSquared, Fit.Evaluate(10)]));
Expect((Fit.Degree = 2) and Near(Fit.RSquared, 1) and (Abs(Fit.Evaluate(10) - 171) < 1E-6), 'the parabola is recovered, also outside the data');
Fit := TAtlasStats.PolynomialFit(X, Y, 1);
Writeln(Format(' straight line: R squared %.4f', [Fit.RSquared]));
Expect(Abs(Fit.RSquared - 0.30474) < 1E-4, 'a line explains less than a third of a parabola');
end;- Add the smoothing and a rejected call. Every function raises
EAtlasPlotErrorinstead of returning NaN; two points cannot fix a parabola.
procedure Smoothing;
var Smooth: TArray<Double>;
begin
Writeln('Exponential smoothing of 10 20 20 0 with alpha 0.5');
Smooth := TAtlasStats.ExponentialSmoothing([10, 20, 20, 0], 0.5);
Writeln(Format(' %.2f %.2f %.2f %.2f', [Smooth[0], Smooth[1], Smooth[2], Smooth[3]]));
Expect(Near(Smooth[0], 10) and Near(Smooth[1], 15) and Near(Smooth[2], 17.5) and Near(Smooth[3], 8.75), 'each value moves halfway towards the input');
end;
procedure Rejections;
var Rejected: Boolean;
begin
Writeln('Invalid input raises EAtlasPlotError');
Rejected := False;
try
TAtlasStats.PolynomialFit([1, 2], [3, 4], 2); // two points cannot fix a parabola
except
on EAtlasPlotError do Rejected := True;
end;
Expect(Rejected, 'a fit with too few distinct arguments is rejected');
end;- Draw two charts without a window. A control created with no owner and no parent renders straight into a file;
ColorOfshows where a value falls on the fixed 50..100 scale.
procedure ExportCharts;
var Map: TAtlasHeatMap; Box: TAtlasBoxPlot; Svg: string;
begin
Writeln('Charts rendered without a window');
Map := TAtlasHeatMap.Create(nil);
try
Map.Title := 'Cache hit rate (%) by node and hour';
Map.RowLabels.CommaText := 'node-a,node-b,node-c';
Map.ColumnLabels.CommaText := '00,06,12,18';
// Percentages, because FormatFloat prints a % sign as it is and does not multiply by 100.
Map.LoadMatrix([[91, 88, 72, 80], [93, NaN, 75, 83], [89, 86, 70, 79]]);
Map.LowColor := clWhite;
Map.HighColor := clBlack;
Map.SetScale(50, 100);
Map.ShowValues := True;
Map.ValueFormat := '0"%"';
Map.SaveToFile('heatmap.png', 480, 300);
Expect(TFile.GetSize('heatmap.png') > 1000, 'heatmap.png written');
Expect(Map.IsEmpty(1, 1) and (Map.ColorOf(75) = TColor(RGB(128, 128, 128))), 'NaN is an empty cell; 75 is halfway on the 50..100 scale');
finally
Map.Free;
end;
Box := TAtlasBoxPlot.Create(nil);
try
Box.Title := 'Response time by service';
Box.ValueAxis.Title := 'ms';
Box.AddCategory('Gateway', [12, 15, 15, 17, 18, 18, 18, 20, 21, 60]);
Box.AddCategory('Search', [30, 31, 35, 36, 38, 40, 41, 45]);
Box.SaveToFile('boxplot.svg', 480, 300);
Svg := TFile.ReadAllText('boxplot.svg', TEncoding.UTF8);
Expect((Pos('>Gateway<', Svg) > 0) and (Pos('>Search<', Svg) > 0), 'boxplot.svg names both categories');
Expect(Near(Box.Stats(0).Median, 18) and (Length(Box.Stats(0).Outliers) = 1), 'the chart keeps the statistics of each sample');
finally
Box.Free;
end;
end;- Finish with the main block, which runs every step and turns any exception into exit code 1.
begin
try
FormatSettings := TFormatSettings.Invariant;
Quantiles;
BoxStatistics;
Histogram;
CorrelationAndFit;
Smoothing;
Rejections;
ExportCharts;
Writeln('All results verified.');
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
ExitCode := 1;
end;
end;
end.- Build and run it. The program prints every result followed by its check and exits with code 0:
Quantiles of 1..10 in shuffled order
Q1 3.25 median 5.50 Q3 7.75 mean 5.50 sd 3.0277
ok: first quartile interpolates between ranks 3 and 4
ok: median of an even count is the middle pair average
ok: mean and sample standard deviation
Box statistics of 1..9 and one slow value, 40
box 3.25..7.75 whiskers 1..9 1 outlier(s)
ok: quartiles
ok: whiskers stop at the last value within 1.5 IQR
ok: 40 is the only outlier
Histogram of 1 2 2 3 3 3 4 4 5 in four bins
[1, 2): 1
[2, 3): 2
[3, 4): 3
[4, 5]: 3
ok: bins are half open, the last one closed
ok: BinOf finds the bin; outside the range is -1
ok: Bins = 0 applies Sturges' rule: ceil(log2 9) + 1 = 5
Correlation and least-squares fits
r = 0.80
ok: Pearson r of a partly ordered pair is 0.8
quadratic: degree 2, R squared 1.0000, value at 10 = 171.0000
ok: the parabola is recovered, also outside the data
straight line: R squared 0.3047
ok: a line explains less than a third of a parabola
Exponential smoothing of 10 20 20 0 with alpha 0.5
10.00 15.00 17.50 8.75
ok: each value moves halfway towards the input
Invalid input raises EAtlasPlotError
ok: a fit with too few distinct arguments is rejected
Charts rendered without a window
ok: heatmap.png written
ok: NaN is an empty cell; 75 is halfway on the 50..100 scale
ok: boxplot.svg names both categories
ok: the chart keeps the statistics of each sample
All results verified.heatmap.png and boxplot.svg are next to the executable. To adapt it, replace the arrays with your own measurements and turn the Expect calls into Writeln; then give the box plot a parent on a form, as the Pro charts in a window sample does, and move the mouse over it to read the statistics back through HitTest.
Troubleshooting
EAtlasPlotError: At least 2 value(s) are needed; 1 given. StdDev and Correlation need two values; Mean, Quantile, Box, Histogram and ExponentialSmoothing need one; PolynomialFit needs Degree + 1. Check the length first, or catch EAtlasPlotError (unit Atlas.PlotAxis) and show "not enough data".
EAtlasPlotError: Plot values must be finite from AddCategory or a statistics function. The sample contains NaN or an infinite value. Box plots and statistics do not accept gaps; remove missing values first. Only the heat map and the radar chart treat NaN as "no value". "Plot value exceeds the supported magnitude 1E100" is the same check for huge numbers.
A fit needs more distinct arguments than its degree. Too few different X values for the degree, for example a quadratic through two dates or through repeated measurements at one X. Lower the degree or collect more distinct points.
Every heat map caption shows 1% or 0%. ValueFormat is a FormatFloat mask, and FormatFloat prints % as it is instead of multiplying by 100. Store percentages as 0..100 and use 0"%", as the quick start does.
Setting ScaleMinimum and ScaleMaximum does not change the heat map colours. They only apply while AutoScale is False, and setting them does not turn it off. Call SetScale(Low, High), which sets both and turns AutoScale off, or set AutoScale := False yourself.
Set at least three categories before adding series, or radar series vanish. Series are sized to the spokes: set Categories first, with at least three entries. Adding or removing a category afterwards discards every series; renaming one keeps them.
A filled radar series is drawn only as an outline. It contains NaN. A series with a gap has no closed shape, so it is drawn as separate line runs without a fill.
HitTest finds nothing and ValueToPixel returns -1. The chart has not been rendered yet (a control is laid out when it paints or exports), or the last target was too small to draw into. Query after the form has painted, or after CreateBitmap. Values outside a fixed ValueAxis range are clipped and cannot be hit either.
An outlier is missing from the box plot. Either ShowOutliers is False (hidden outliers are neither drawn nor hit and do not stretch the scale) or a fixed ValueAxis.SetRange excludes it. Call ValueAxis.Automatic := True to return to the automatic range.
Unsupported export format ".jpg". SaveToFile writes .png, .bmp, .emf and .svg only. Use CreateBitmap and a VCL image class for other formats.
The program does not start because AtlasPlotRuntime370.bpl is missing. Built with runtime packages, AtlasPlotProRuntime370.bpl needs the Atlas Plot runtime package beside the executable or on PATH. Ship both, or link the units statically.
Hint H2443 about TFont.GetStyle in Atlas.PlotSurface.pas. It appears when the Atlas Plot sources are compiled into your program, because that unit does not list System.UITypes. The call is just not inlined; it is harmless and does not appear when you link against the runtime packages.