2x TeeChart speed in Firemonkey (FastLine, Direct2D)

The Firemonkey Canvas is fast but there is a performance problem when drawing lots of elements (“lots” being in the order of tens of thousands).

Using a TPath, adding all the elements to it and then drawing the TPath gives some speed gains but it is not enough. Time is lost filling the TPath anyway.

If the elements are simple lines, graphical apis like Direct2D or GDI+ have optimized shortcuts that run much quicker than drawing single lines many times.

Using simple rtti “hacks”, TeeChart “FastLine” series style is now twice as fast when there are a lot of points to display.

The gains are aprox 2x (twice the speed). It all depends on the combination of cpu + gpu + chart size + number of points.

This improvement will be included in the next coming update release.

There are some conditions to use this fast technique:

// All points in the series are painted as one big line, instead of multiple segments
Series1.DrawStyle := TFastLineDrawStyle.flAll;

// “null” (empty) values, if they exist, should be ignored (no gaps in the line)
Series1.TreatNulls := TTreatNullsStyle.tnIgnore;

// Tell canvas to use faster speed:
Series1.FastPen := True;


Performance gain, from 19 frames-per-second to 38:


The picture above shows 2 FastLine series, with 100.000 points each running on Windows.


GPU Canvas:

Unfortunately, there is no shortcut for a similar method in the TCanvasGpu (used on Android and iOS platforms).

Trying to simplify the StrokeBuild and FillTriangles methods for this case (lots of lines) gives only aprox a 10% speed improvement.


About reducing the number of points:

Its clear it is better not to add that quantity of points to the series, as there are not enough pixels to display them, but in some applications (specially when the data comes more or less in realtime) reducing the number of points can cost more time depending on the algorithm.

FastLine provides a basic point-reducer mechanism using a property:

Series1.DrawAllPoints := False;
Series1.DrawAllPointsStyle := TDrawAllPointsStyle.daFirst; // use first Y for all common X

And also :  “daMinMax” to draw vertical lines for points with repeated “X” coordinates.

TeeChart Pro version includes more advanced ways to do data-reducing at the TeeDownSampling.pas unit.

A TDownSamplingFunction can be used at design-time or run-time using several algorithms (including Douglas-Peucker Polygon Simplification) :

TDownSampleMethod=(dsDouglas, dsMax, dsMin, dsMinMax, dsAverage,dsMinMaxFirstLast, dsMinMaxFirstLastNull);

TeeFunction1.DownSampleMethod := TDownSampleMethod.dsDouglas;

Series2.FunctionType := TeeFunction1;  // <– Series2 will contain the “reduced” data
Series2.DataSource := Series1;  // <– Series1 has many points


RAD Studio 10.1 Berlin, add TeeChart to “FireUI Live Preview”

Studio 10.1 Berlin has just been released and includes the FireUI Live Preview tool to visualize forms at design-time in mobile devices and desktop (Windows / Mac OSX) machines.


The default application does not provide support for TeeChart control, but its very easy to add !

  • Open the LivePreview.dproj project in Studio 10.1 from:  c:\Program Files (x86)\Embarcadero\Studio\18.0\source\Tools\FireUIAppPreview
  • Edit the project’s Regs.pas unit to add the TeeChart related units (see code below)
  • Run the app (without debugging)
  • Create a new Firemonkey project, add a TChart control to see it at Live Preview (connect to your ide machine first)

There is only a minor caveat that should be easy to solve:

When adding series of data to TChart, they appear filled with random points at design-time.
However, Live Preview displays component contents without the “csDesigning” ComponentState property so the series appear empty.

Modifications to Regs.pas unit (displayed in bold font) :

unit Regs;


  System.Classes, FMX.Controls, FMX.ImgList,


  {$IF TeeMsg_TeeChartPalette='TeeChart'}

  FMXTee.Editor.Pro,  // <-- if you have the Pro version of TeeChart

  FMXTee.Chart, FMXTee.Series;



  // Register here any component that is not previously registered by the framework




Big files: XML or JSON ? TeeBI !!

TeeBI Dashboards



XML and JSON are very typical text formats used to store data, designed to be more comfortable than plain old “csv” text and allowing hierarchical (parent -> child) relationships.

However, even if there are many wonderful standard libraries to process them, there is still a speed problem when loading big quantities of data (say, hundreds or thousands of megabytes).

Content has to be parsed and stored into memory structures representing the “tree” nature of data nodes and attributes, which can be very fast (milliseconds) for small files, but terribly slow (minutes !) for big ones.

TeeBI core base class (TDataItem) is an “agnostic” memory structure providing parent -> child connections, using simple arrays to store data (one array per field or column).


TDataItem = class
Name : String;
Items : Array of TDataItem;   // <--- Children
Kind : TDataKind;  // <-- Integer, String, Float, DateTime, Boolean, or "List of TDataItem"
Data : Array of ...    //  <--  one array for each Kind: "Int32Data : Array of Int32"


With a TDataItem, loading and saving big quantities of data is insanely fast (0.2 seconds to load or save 1 million rows with 4 columns on a normal PC).

The arrays are saved / loaded to / from Streams directly in one Write / Read operation.

That means we can import data from XML or JSON (or any other format like database datasets, server connections, Excel, etc, etc) into a TDataItem and then save it to a binary TeeBI file for later reuse.

Data := TDataItemPersistence.Load( 'my data.bi ')


Once a TDataItem is created or loaded, we can use it in many ways:

  • Search and modify data, re-structure columns
  • Sort data by multiple fields, and by custom expressions
  • Run ultra-fast SQL-like queries and summaries against TDataItems
  • Set master -> detail relationships between different TDataItems
  • Filter rows by code or using expressions (as strings or as TExpression classes)
  • Create calculated columns (using code or expressions)
  • Merge several TDataItems
  • Compare the structure and / or full data of TDataItems to obtain difference sets
  • Present TDataItems using Grids, Charts, Dashboards and PDF output
  • Connect TDataItems to a super-fast TBIDataset (a normal memory TDataset class)
  • Export to any other format (for example XML to JSON and vice-versa)
  • Access remote TDataItems from web servers transparently
  • Apply machine-learning algorithms using R or Python Scikit-learn
  • Access basic statistics of any TDataItem or child item


Note to TeeChart developers:

TeeBI includes a new TBIChart control (derived from TChart) that is capable of automatically creating new chart series and fill them from any TDataItem.

BIChart1.Data := MyDataItem;

A planned new feature is to integrate the Data property editor dialog inside the normal TeeChart editor, for design-time support (zero code charting !)


TeeBI library is available for download at the following link:


Supported development environments:

  • Embarcadero Studio (Delphi, C++) from XE4 version and up
  • Lazarus FreePascal
  • …and soon for Microsoft Visual Studio .NET

Several 3rd party products can be optionally used with TeeBI:



For more information:

Please visit the TeeBI community at Google+ and the TeeBI home website for more information and technical details.



What’s New in TeeChart VCL/FMX v2015.16

Build 2015.16.150901

Release September 2015

This technical document describes all changes made to TeeChart component library (FireMonkey and VCL versions) since the release of April 2015.


New Supported IDEs

  • Embarcadero RAD Studio 10 Seattle.
    Full support for Delphi and C++ Builder 10 Seattle for all platform projects.


‘Detail’ property

Series ‘master-detail’ functionality, with a new ‘Detail’ property and ‘Add’ method overload in the Series class to enable the ‘drill-down’ of Series data.
Example demo available at http://www.teechart.net/files/public/support/SeriesDetailSample.zip


TChartLayout component

TChartLayout component, a scrollable panel which will automatically arrange multiple charts into a viewable state.


GDI+ canvas Scale property

Creates smoother looking charts. Default value is 1 and can be changed at design and runtime through the Chart editor 3D render dialog.


Third legend column support

Support for a third legend column accompanied by a new TextStyle value:
This shows each point X, Y, and Text label at legend.


New Firemonkey dashboard project showcasing TeeChart standard series types

Full sources also available at GitHub:

TeeBI Web Server returning a summary chart

TeeBI teaser

Small teaser of TeeBI.

This is the custom web server calculating a query and returning a chart. The only dependencies are TeeChart and Indy http web server component.

TeeBI Web Server returning a summary chart


Data is in column-oriented, memory-based custom format for speed reasons, no database or FireDac, etc are necessary. Data is imported from many sources (excel, text files, firedac or any other datasets, etc) to the custom format, which is then transparent to the user apps.

The web server is optional if data is not remote, and it can also return binary streams to normal desktop (vcl or fmx), or mobile apps (fmx).

A table of 2000×5 cells takes 180msec via web. For visual display, an fmx or vcl dbgrid easily handles 1 or more million rows with a custom “TBIDataset” linked to an in-memory data, allowing grouping, filtering and sorting using complex expressions involving columns from the same table or foreign-key(s) fields.

This speed is the basis for a next-coming set of machine-learning and data-mining algorithms, currently under development.


Generic Delphi Tree structure

A generic Tree structure made in Delphi is freely available at this GitHub repository:


See the readme at GitHub for details and updated documentation.

This small class allows creating hierarchical structures where each “node” is a small object (20 bytes plus your own data size), containing a property of your desired type.

For example, a Tree of string nodes:

var MyTree : TNode<String>;

MyTree.Data :=’hello’;




Clustering visualization

TeeChart Pro includes classes and components to perform “clustering” on your data, and optionally visualize the results using a chart “Tool” component.

Clustering is the process of grouping data automatically, according to how well related are the individual items.

As an unsupervised algorithm, its widely used in data-mining / machine-learning / B.I. (Business Intelligence) applications.



For more information on clustering visit the following Wikipedia link: http://en.wikipedia.org/wiki/Cluster_analysis

An executable example:


The clustering algorithm can be processed on custom data, not necessarily on TeeChart “Series” data.


Classes and Units

The TeeClustering.pas unit, for both VCL and Firemonkey, contains abstract “engine” classes that perform the clustering algorithms.

Three different clustering methods are provided:

• TKMeansClustering

• THierarchicalClustering

• TQTClustering (Quality Threshold)

These classes derive from a common abstract class: TBaseClustering.

Each clustering method has its own properties that determine how will the clusters be calculated. After calculating, you can access the Clusters property, which is a TList of TCluster objects.

A TCluster contains child clusters (Items[ ]), so you can check which input data items belong to which cluster, or in the case of the Hierarchical type, access the tree structure (clusters and sub-clusters).

The input data (your data) is not contained by the above classes.

Data is passed to the clustering engine through a “provider” class. There is currently one kind of data provider (TSeriesProvider) to cluster XY or XYZ Series points.

This class is implemented in the TeeClusteringTool.pas unit, together with a charting Tool class (TClusteringTool) to make things easier and more automatic.


Basic Example

Example runtime code (it can be done at design-time too, without coding) :

uses TeeClusteringTool;

var tool : TClusteringTool;



tool.Series:=Series1; // your series





After execution, you can loop on the resulting output clusters, for example:

var t : Integer;

for t:=0 to tool.Clusters.Count-1 do
Memo1.Lines.Add( ‘Cluster: ‘+IntToStr(t)+’ contains:  ‘+
IntToStr(tool.Clusters[t].Count)+’ points’ );




This tool automatically performs clustering using the choosen method and parameters, and optionally paints each source series point with a different color indicating which cluster they belong to, and/or draws polygons around each group of cluster’s items, among other things.


ClusteringTool1.Method := cmHierarchical;

ClusteringTool1.ColorEach := True; // paint Series with one color per cluster

ClusteringTool1.ShowBounds := True; // draws convex polygons bounding each cluster points

ClusteringTool1.Centers.Visible := True; // shows cluster centers

ClusteringTool1.Centroids.Visible := True; // shows cluster centroids

Other properties include Brush, Pen and Transparency, used when drawing cluster polygon boundaries.


Several helper methods are provided:

// Obtain cluster’s center and centroid XY points in Series scales:

var P : TPointFloat;

P:=ClusteringTool1.GetClusterCenter( ClusteringTool1.Clusters[3] );

P:=ClusteringTool1.GetClusterCentroid( ClusteringTool1.Clusters[2] );

// Obtain an array of XY points (in screen pixel coordinates), that belong to cluster:

var PP : TPointArray;

ClusteringTool1.GetClusterPoints( ClusteringTool1.Clusters[4], PP);


// Get cluster statistics:

var S : TClusterStats;

S:=ClusteringTool1.GetStats( ClusteringTool1.Clusters[0] );


Calculation parameters

Each clustering algorithm needs different parameters:


ClusteringTool1.KMeans.NumClusters := 10; // Number of minimum clusters (“K”)

ClusteringTool1.KMeans.MaxIterations := 1000; // Maximum number of iterations before stopping


ClusteringTool1.Hierarchical.NumClusters := 8; // Number of tree root clusters


ClusteringTool1.QTClustering.MinCount := 30; // Minimum number of points to form a cluster

ClusteringTool1.QTClustering.MaxDiameter := 100; // Maximum “diameter” a cluster can grow


Common parameters:


Cluster calculation is based on the “distance” between a data item and the other data items. There are several ways to calculate the “distance” between items.

The algorithms are agnostic, they call the Provider (ie: Series provider) to obtain the distances.

For example, on a XY scatter plot, the distance between points can be for example the hypotenuse (Pythagoras’ theorem), that is, the simple Euclidean distance between a point XY and another XY.

Distance calculations implemented:




ClusteringTool1.Distance := dmMinkowski;

ClusteringTool1.MinkowskiLambda := 4;



There are several ways to calculate the “distance” between clusters when one or the two clusters have more than one item.

This is called “linkage”.

The most simple way is using each cluster “center” (this means no linkage occurs).

Other linkage styles implemented:


Also called “minimum”.

The distance between cluster A and B is the minimum distance between all items in cluster A and all items in cluster B.


Also called “maximum”.

The distance between cluster A and B is the maximum distance between all items in cluster A and all items in cluster B.


The distance between cluster A and B is the average distance between all items in cluster A and all items in cluster B.


The result is the increase on “error sum of squares” when adding cluster B items to cluster A.


Calculation speed

Clustering is a slow process by nature. Each clustering method has different performance bottlenecks, proportional to the number of input data items.

The TeeClustering.pas unit has been greatly fine-tuned to optimize the speed of each algorithm, although much work is needed to find more advanced techniques that require less CPU cycles.

The QT Threshold algorithm benefits of parallelism, when multiple CPUs can be used together.

Speed examples (revisited):

(Time in milliseconds, Windows 8.1 x64 on Intel i7 4770 @ 3.4Ghz)

IDE XE8 Delphi, Win32, 5000 data points

Algorithm      Single CPU   Multiple CPU

K-Means              47                     31
Hierarchical    4328                4156
QT                     2859                  703


x64 bit executables are a little bit faster than 32bit.

Speed is also very dependant on the “distance” calculation method that is used to compare data.  The default Euclidean calculation has a quite big CPU cost as it calculates the Hypotenuse between two data XY value pairs.



Small tool to create icons and png images for iOS and Android Firemonkey applications

Yet another tool to create the *.png images required by Firemonkey iOS and Android application splash images.

Download source code  (65KB, for Embarcadero RAD Studio XE4 up to XE7)

(Main *.pas unit is aprox 200 lines of code, easy to modify to suit your needs)

Currently this tool generates 42 images of different sizes:



The sample project uses an FMX 3D form containing a sample “logo”. This can be replaced to use a normal image instead. Using a 3D form might produce better output quality as texts and graphics are regenerated from vector data every time for each icon dimension, instead of stretching a single “big” bitmap.

The *.ico file for Windows projects is created containing a single image.
You can use Gimp or IcoFX to create a multiple ico file using the generated *.png images.

See this great article about creating multi-icon *.ico files for Windows applications from Simon Stuart’s OTAPI.com:



The *.icns file for Mac OSX applications is not created as it has several complex requeriments (a shell command line tool must be used in the Mac machine) explained here:



Using TeeChart Java with Android Studio

Minimal example using TeeChart Java in Google’s Android Studio.

Android Studio home page:



Download the example (9MB)

If you want to recreate this project, the steps are as follows:

1) TeeChart Java for Android

The above example download includes an evaluation version of TeeChart.Android.jar library. (The evaluation version draws a watermark)

If you wish to download the full version or the full evaluation with examples and tutorials, please follow this link:


2) Create a new project in Android Studio (blank activity)

3) Copy TeeChart library to the app\libs folder

In your example project folders, copy the TeeChart.Android.jar file (from the above download zip)


After some seconds, Android Studio will automatically recognize the new copied file and will appear under the libs tree node.

If it doesn’t, right click the libs node and click on “Synchronize libs” option.

4) At the main activity java, type this code:

The main java source file is at (for example):

C:\Android Studio\app\src\main\java\com\david\demo\MyActivity.java

import com.steema.teechart.TChart;
import com.steema.teechart.drawing.Color;
import com.steema.teechart.styles.*;
import com.steema.teechart.styles.Series;


protected void onCreate(Bundle savedInstanceState) {


  // Find the Layout:
  ViewGroup v;
  v = (ViewGroup) findViewById( id.mylayout );

  // Create a Chart and add it to Layout:
  TChart chart = new TChart( this );
  v.addView( chart );

  // Create a new series of data:
  Series series1 = new Pie( chart.getChart() ); // Bar,Area,Line etc

  // Add some sample data:
  series1.add( 123, "Apples", Color.green );
  series1.add( 456, "Oranges", Color.red );
  series1.add( 321, "Kiwis", Color.yellow );

  // Cosmetic options:
  chart.getAxes().getBottom().setIncrement( 1 );


5) Run or debug

Clicking the ide Run or Debug buttons (or menu options) will execute the application.

A Pie chart appears with 3 slices at your Android device (phone or tablet), or at the emulator:


TeeChart Java for Android





Animated Bar Series Transitions (VCL and FMX)

A new feature in the next coming TeeChart Pro update is a new TeeAnimation class to perform animated transitions between the different Bar series stacking styles.


Creating the animation:

var a : TSeriesTransition;


Optional animation settings:

a.Duration:=300; // milliseconds

Playing the animation:



Executable demos (VCL and Firemonkey) and source code.

Note: Demo sources require a new event in TCustomBarSeries class, to be provided in the next coming TeeChart Pro update (aprox Sep-2014).