Publication-ready editorial charts for Delphi, VCL and FireMonkey.
Chart4D draws charts the way a newsroom publishes them: a bold left-aligned title, a light horizontal grid, no chart junk, direct labelling, and a footer with the source. One consistent style out of the box, every part of it overridable.
Zero dependencies, RTL only in the core, in the style of the GDK 4D library family.
Most charting components give you every option and leave the design to you. The result is usually a chart that looks like a spreadsheet: a boxed plot area, a heavy grid in both directions, a legend in a corner, values you have to look up on an axis.
Chart4D starts from the other end. You supply the data and the words. The layout, the label placement and the colours are already decided. Override any of them when you disagree.
The core is plain Object Pascal on the RTL and does not know about VCL or FMX. The two controls are thin adapters over one shared renderer, so a chart renders pixel-for-pixel the same on both frameworks and exports to PNG the same way.
uses
Chart4D.Types,
Chart4D.Style,
Chart4D.VCL;
var Chart := TChart4D.Create(Self);
Chart.Parent := Self;
Chart.Align := alClient;
Chart.Plot.Kind := TChartKind.Bar;
Chart.Plot.Orientation := TChartOrientation.Horizontal;
Chart.Plot.Title := 'Almost everyone is online';
Chart.Plot.Subtitle := 'Share of the population using the internet, 2020';
Chart.Plot.Source := 'Source: World Bank';
Chart.Plot.Categories := ['Sweden', 'Spain', 'Belgium', 'Netherlands'];
Chart.Plot.AddSeries('2020', [94.5, 93.2, 91.5, 91.3]);
Chart.SaveToPng('online.png');The FireMonkey control has the same API. Use Chart4D.FMX instead of Chart4D.VCL and
nothing else changes.
| Kind | What it is for |
|---|---|
Line |
A measure over time, one or more series |
Area |
A total that accumulates, rather than a level you measure |
Bar |
Ranking and comparison, for values with a meaningful zero |
GroupedBar |
Two or three measures per category, side by side |
StackedBar |
Parts of a whole, absolute or normalised to 100% |
Histogram |
The shape of a distribution, binned for you |
DotPlot |
Comparison where zero is not informative, so bars would mislead |
Dumbbell |
Change between two moments, one row per category |
Range |
The span between a low and a high value |
Arrow |
Change between two moments, drawn as a direction rather than two points |
Scatter |
Two continuous measures against each other, with optional bubble sizing |
Pie |
Parts of one whole, for a handful of segments |
Donut |
A pie with room for a total in the middle |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Direct labelling is what makes this style readable, so it is built in rather than left to you.
Plot.ValueLabels := TValueLabelMode.Extremes; // None, All, FirstAndLast, ExtremesLabels are placed automatically, moved inside the plot when they would cover an axis label, and skipped when they would collide with a label already drawn. The result is deterministic, so a chart looks the same on every run.
To argue one point while still showing context, mute everything except one series:
Plot.HighlightedSeriesIndex := 4;A series with an explicitly set colour keeps it, so a deliberate choice always survives.
var YAxis := Plot.YAxis;
YAxis.MinValue := 0; // NaN for automatic
YAxis.Breaks := [0, 50, 100]; // empty for automatic
YAxis.BreakLabels := ['none', 'half', 'all']; // one label per break; empty to format the breaks
YAxis.UseThousandSeparator := True; // 40,000 instead of 40000
YAxis.LabelSuffix := '%';
YAxis.SuffixOnLastOnly := True; // the unit on the last label only
YAxis.LocaleName := 'nl-NL'; // 40.000 for a Dutch audience
YAxis.Scale := TAxisScaleKind.Logarithmic;
Plot.YAxis := YAxis;
var XAxis := Plot.XAxis;
XAxis.DateMode := TAxisDateMode.Auto; // days, months, quarters or years
Plot.XAxis := XAxis;Numbers use the invariant convention unless you set LocaleName, so test output is
reproducible.
For a horizontal chart the value axis is still YAxis. The orientation swaps where the axes
are drawn, not what they mean.
Plot.AddTextAnnotation(5, 72.5, '+17.3 years', ChartDarkRed, TTextAlignH.Center);
Plot.AddHorizontalLine(80, ChartLightGrey, True);
Plot.AddHorizontalRangeOverlay(78, 80, TAlphaColor($30990000));
Plot.AddArrow(1990, 60, 1995, 45);A range band takes its bounds from data instead of the axis, for confidence intervals, forecast ranges or a real spread:
const Band = Plot.AddRangeBandSeries('Male to female', Years, Men, Women);
Band.Color := TAlphaColor($3013A0C1);Both controls hit-test the chart on mouse move, highlight the nearest data point and draw a tooltip. Tooltips are on by default.
Chart.ShowTooltips := True;
Chart.OnDataPointHover := HandleHover;
procedure TFormMain.HandleHover(Sender: TObject; const Info: TChartHitInfo);
begin
if Info.HasHit then
Caption := Format('%s: %s', [Info.CategoryLabel,
TAxisScale.FormatValue(Info.Value, False)]);
end;SaveToPng never draws a tooltip, so an export is always clean.
Chart.SaveToPng('chart.png'); // 640x450 by default
Chart.SaveToPng('large.png', 1280, 900);The publication footer is part of the export: the source text on the left, an optional logo on the right, separated from the chart by a full-width rule.
Plot.Source := 'Source: World Bank';
Plot.LogoFilePath := 'logo.png';The logo is scaled to fit the footer height and aligned right. Both demos set it to
assets\chart4d-mark-64.png, so you can see what it looks like without wiring anything up.
TChartStyle.Default holds the editorial style: Helvetica, or Arial on Windows, a 28 pixel
bold title, a 22 pixel subtitle, 18 pixel legend and axis text in #222222, gridlines on the
value axis only in #CBCBCB, and no axis titles, ticks or axis lines. Sizes are pixels at the
640x450 reference size and scale with ScaleFactor.
var Style := Plot.Style;
Style.TitleFontSize := 32;
Style.ShowGridlines := False;
Style.ScaleFactor := 2.0;
Plot.Style := Style;The palette:
ChartBlue = TAlphaColor($FF1380A1);
ChartOrange = TAlphaColor($FFFAAB18);
ChartDarkRed = TAlphaColor($FF990000);
ChartGreen = TAlphaColor($FF588300);
ChartBaselineGrey = TAlphaColor($FF333333);
ChartLightGrey = TAlphaColor($FFDDDDDD);Open the runtime packages under packages\RAD Studio 13.0\ or packages\RAD Studio 12.0\,
whichever matches your IDE, and build Chart4D_R for the core, then Chart4D_VCL_R or
Chart4D_FMX_R for the framework you use.
Or add Source\ plus Source\VCL\ or Source\FMX\ to your project search path. Controls are
created at runtime; there is no design-time registration yet.
Examples\VCL and Examples\FMX both run every example in the catalogue, with the
explanation and the code that produces it beside the chart. They share
Examples\Common\Chart4DDemo.Catalog.pas, so the fragment on screen and the chart next to it
always come from the same source.
Build them with Build.bat in the repository root. The script picks the newest installed
Delphi; set CHART4D_STUDIO to 23.0 or 37.0 to force Delphi 12 or Delphi 13.
All demo data is published World Bank World Development Indicators data. Two exceptions: the electricity mix is Ember data via Our World in Data, and the temperature anomaly is HadCRUT5 from the Met Office Hadley Centre.
Build.bat builds the three packages, runs the DUnitX suite and builds both demos. Everything
compiles with zero warnings and zero hints.
Three console tools under Tools\ go further:
| Tool | What it checks |
|---|---|
CoreCheck |
Every core unit compiles and every scenario renders |
VclCheck |
The GDI+ adapter renders, exports and reports hover |
FmxCheck |
The same for FMX, plus every chart kind drawing real pixels |
FmxCheck and VclCheck drive the control's own mouse handling, so the chain from a mouse
move through the hit test to the repaint is covered, not just the geometry behind it.
Version 1.0.0. See SPEC.md for the design contract and CONTRIBUTING.md for how to build, test and submit a change.
Chart4D is released under the MIT License.
Copyright (c) 2026 GDK Software
For companies we offer a support and maintenance contract, including sponsored development of the features you need. Get in touch at gdksoftware.com/contact-us, or open an issue.
Chart4D is developed by GDK Software, a software company building Delphi developer tools, MCP integrations, and enterprise Delphi applications.











