Difference between revisions of "TAChart documentation"

From Lazarus wiki
Jump to navigationJump to search
(→‎Error bars: Clearer formulation)
(41 intermediate revisions by 2 users not shown)
Line 22: Line 22:
 
== Series ==
 
== Series ==
  
[[File:series_hierarchy.png|right]]Series are the central part of TAChart. Their hierarchy is illustrated in the figure. The series inheriting from TCustomChartSeries represent data taken from a [[#Sources|ChartSource]] in graphical ways, such as lines or bars; the other series get their data in another way.
+
[[File:series_hierarchy-1.png|right]]Series are the central part of TAChart. Their hierarchy is illustrated in the figure. The series inheriting from TCustomChartSeries represents data taken from a [[#Sources|ChartSource]] in graphical ways, such as lines or bars; the other series get their data in another way.
  
 
=== Constant line series ===
 
=== Constant line series ===
Line 29: Line 29:
 
It can be used as a "central axis" in function graphs, or as a draggable marker line.
 
It can be used as a "central axis" in function graphs, or as a draggable marker line.
  
Also, by setting <code>Active</code>=true, <code>Pen.Style=psClear</code> and
+
Also, by setting <tt>Active</tt>=true, <tt>Pen.Style=psClear</tt> and
<code>UseBounds=true</code> and an appropriate <code>AxisIndexX</code>, it becomes an "axis extender",
+
<tt>UseBounds=true</tt> and an appropriate <tt>AxisIndexX</tt>, it becomes an "axis extender",
making sure that a given <code>Position</code> will always be included in the axis range.
+
making sure that a given <tt>Position</tt> will always be included in the axis range.
  
 
=== Basic series ===
 
=== Basic series ===
Line 41: Line 41:
 
==== Line series ====
 
==== Line series ====
  
<code>TLineSeries</code> can be used to draw a given set of points,
+
<tt>TLineSeries</tt> can be used to draw a given set of points,
optionally marking each data point with a symbol and/or connecting the data points with a line. The color of the line series is defined by the <code>SeriesColor</code>.
+
optionally marking each data point with a symbol and/or connecting the data points with a line. The color of the line series is defined by the <tt>SeriesColor</tt>.
  
<code>ColorEach</code> gives control over coloring inidividual data points and the adjacent line segments (the data point color is provided by the chart source):
+
<tt>ColorEach</tt> gives control over coloring inidividual data points and the adjacent line segments (the data point color is provided by the chart source):
* <code>ceNone</code> -- no individual coloring, even if colors are assigend to the chart data item.
+
* <tt>ceNone</tt> -- no individual coloring, even if colors are assigend to the chart data item.
* <code>cePoint</code> -- colorize only the data point symbol, not the line segment.
+
* <tt>cePoint</tt> -- colorize only the data point symbol, not the line segment.
* <code>ceLineAfter</code> -- apply the data point color to the line segment following the data point
+
* <tt>ceLineAfter</tt> -- apply the data point color to the line segment following the data point
* <code>ceLineBefore</code> -- apply the data point color to the segment before the data point
+
* <tt>ceLineBefore</tt> -- apply the data point color to the segment before the data point
* <code>cePointAndLineAfter, cePointAndLineBefore</code> -- like before, but colorizes also the data point symbol.
+
* <tt>cePointAndLineAfter, cePointAndLineBefore</tt> -- like before, but colorizes also the data point symbol.
  
You can get a "stepped" look by setting <code>LineType</code> property to <code>ltStepXY</code> or <code>ltStepYX</code>.
+
You can get a "stepped" look by setting <tt>LineType</tt> property to <tt>ltStepXY</tt> or <tt>ltStepYX</tt>.
  
Using a [[#Multi-valued sources|multi-valued data source]] <code>TLineSeries</code> can handle several y values for each x value. If <code>Stacked</code> is set to <code>true</code> then the individual y values are plotted in a stacked way, i.e., the second y value is added to the first one, the third y value to the second value etc. Note, however, unlike stacked bar or area series it may not be clear that the data values are stacked, and therefore stacking is usually not recommended for a line series.
+
Using a [[#Multi-valued sources|multi-valued data source]] <tt>TLineSeries</tt> can handle several y values for each x value. If <tt>Stacked</tt> is set to <tt>true</tt> then the individual y values are plotted in a stacked way, i.e., the second y value is added to the first one, the third y value to the second value etc. Note, however, unlike stacked bar or area series it may not be clear that the data values are stacked, and therefore stacking is usually not recommended for a line series.
  
 
===== Fast lines =====
 
===== Fast lines =====
Line 63: Line 63:
 
* There are no marks.
 
* There are no marks.
 
* There are no pointers.
 
* There are no pointers.
* <code>LineType</code> is not <code>ltFromOrigin</code>.
+
* <tt>LineType</tt> is not <tt>ltFromOrigin</tt>.
  
 
Some operating systems/widgetsets may additionally require that
 
Some operating systems/widgetsets may additionally require that
<code>LinePen.Style=psSolid</code> and <code>LinePen.Width=1</code>.
+
<tt>LinePen.Style=psSolid</tt> and <tt>LinePen.Width=1</tt>.
  
Additional speedups will be available if <code>Source.Sorted=true</code>.
+
Additional speedups will be available if <tt>Source.Sorted=true</tt>.
  
 
You can measure line speed drawing on your platform with the "line" demo.
 
You can measure line speed drawing on your platform with the "line" demo.
  
 
===== Point series =====
 
===== Point series =====
<code>TLineSeries</code> can be drawn as a "point series" showing only symbols at the position of the data points and hiding the connecting lines by setting <code>ShowPoints</code> to <code>True</code> and <code>LineType</code> to <code>ltNone</code>. Note that the <code>SeriesColor</code> applies only to the connecting lines; to specify the color of the points change the <code>Pointer.Brush.Color</code> for the fill and/or <code>Pointer.Pen.Color</code> for the border line color. The <code>Pointer</code> property also gives access to the shape (circle, box, etc) of the symbols (<code>Style</code>).
+
<tt>TLineSeries</tt> can be drawn as a "point series" showing only symbols at the position of the data points and hiding the connecting lines by setting <tt>ShowPoints</tt> to <tt>True</tt> and <tt>LineType</tt> to <tt>ltNone</tt>. Note that the <tt>SeriesColor</tt> applies only to the connecting lines; to specify the color of the points change the <tt>Pointer.Brush.Color</tt> for the fill and/or <tt>Pointer.Pen.Color</tt> for the border line color. The <tt>Pointer</tt> property also gives access to the shape (circle, box, etc) of the symbols (<tt>Style</tt>).
  
 
==== Bar series ====
 
==== Bar series ====
  
<code>TBarSeries</code> represents data as a set or bars, extending from <code>ZeroLevel</code> to data points.
+
<tt>TBarSeries</tt> represents data as a set or bars, extending from <tt>ZeroLevel</tt> to data points.
  
You can control bar width with <code>BarWidthPercent</code> property. Note that the it is measured relative to the
+
You can control bar width with <tt>BarWidthPercent</tt> property. Note that the it is measured relative to the
 
neighboring bars. If the X values are not equidistant, bars will have varying width.
 
neighboring bars. If the X values are not equidistant, bars will have varying width.
To prevent that, set <code>BarWidthStyle=bwPercentMin</code>.
+
To prevent that, set <tt>BarWidthStyle=bwPercentMin</tt>.
  
You can draw multiple bar series side-by-side by using <code>BarOffsetPercent</code> property.  
+
You can draw multiple bar series side-by-side by using <tt>BarOffsetPercent</tt> property.  
  
Use multiple y values to create stacked bar series (<code>Stacked = true</code>). Beginning with Lazarus v2.0 multiple y values can also be drawn in a side-by-side arrangement (<code>Stacked = false</code>).
+
Use multiple y values to create stacked bar series (<tt>Stacked = true</tt>). Beginning with Lazarus v2.0 multiple y values can also be drawn in a side-by-side arrangement (<tt>Stacked = false</tt>).
 +
 
 +
In addition to rectangular bars the data can be represented by alternative shapes: cylinder, hexagonal prism, pyramid or cone - see property <tt>BarShape</tt> which supports these values: <tt>bsRectangular, bsCylindrical, bsHexPrism, bsPyramid, bsConical</tt>. Furthermore, the event <tt>OnCustomDrawBar</tt> allows to paint the bars in any user-defined manner.
  
 
==== Area series ====
 
==== Area series ====
  
<code>TAreaSeries</code> represents data as a polygon extending downwards from the data points either to a <code>ZeroLevel</code> line
+
<tt>TAreaSeries</tt> represents data as a polygon extending downwards from the data points either to a <tt>ZeroLevel</tt> line
or towards infinity (if <code>UseZeroLevel=false</code>).
+
or towards infinity (if <tt>UseZeroLevel=false</tt>).
 +
 
 +
You can get a "stepped" look by setting the <tt>ConnectType</tt> property.
  
You can get a "stepped" look by setting the <code>ConnectType</code> property.
+
Like <tt>TBarSeries</tt> and <tt>TLineSeries</tt>, an area series can accept several y values for the same x from a [[#Multi-valued sources|multi-valued data source]]. These y values are drawn in a stacked way if the property <tt>Stacked</tt> is set to <tt>True</tt> (its default value). Use a [[#ChartStyles|ChartStyles]] component to define the appearance of the individual layers. (Note that in Lazarus versions 1.8.x or older, ChartStyles do not colorize overlapping layers consistently).  
  
Like <code>TBarSeries</code> and <code>TLineSeries</code>, an area series can accept several y values for the same x from a [[#Multi-valued sources|multi-valued data source]]. These y values are drawn in a stacked way if the property <code>Stacked</code> is set to <code>True</code> (its default value). Use a [[#ChartStyles|ChartStyles]] component to define the appearance of the individual layers. (Note that in Lazarus versions 1.8.x or older, ChartStyles do not colorize overlapping layers consistently).  
+
The property <tt>Banded</tt> (available in Lazarus v2.0+), if set to true, suppresses painting of the lowest stack level. This way a band of data values can be highlighted: use a chartsource with two y values and set the first y value to the lower and the second y value to the upper band level. Alternatively, the width of the band can be specified in the second y value if both properties <tt>Banded</tt> and <tt>Stacked</tt> are set to true.
  
The property <code>Banded</code> (available in Lazarus v2.0+), if set to true, suppresses painting of the lowest stack level. This way a band of data values can be highlighted: use a chartsource with two y values and set the first y value to the lower and the second y value to the upper band level. Alternatively, the width of the band can be specified in the second y value if both properties <code>Banded</code> and <code>Stacked</code> are set to true.
+
Multiple-y value support should be applied with caution: Stacking non-positive values may produce plots which are difficult to understand, and unstacked area series (<tt>Stacked = false</tt>) may suffer from data being covered by other y values. Also, the <tt>ZeroLevel</tt> should be included only in the lowest stack level to avoid unusual results.  
  
Multiple-y value support should be applied with caution: Stacking non-positive values may produce plots which are difficult to understand, and unstacked area series (<code>Stacked = false</code>) may suffer from data being covered by other y values. Also, the <code>ZeroLevel</code> should be included only in the lowest stack level to avoid unusual results.  
+
A 3D-like presentation of the series can be obtained if <tt>Depth</tt> is set to a positive value, something like 10 or 20. Note that the drawing algorithm is very simple and likely produces incorrect displays when curves cross, or stacking and banding are turned off.
  
A 3D-like presentation of the series can be obtained if <code>Depth</code> is set to a positive value, something like 10 or 20. Note that the drawing algorithm is very simple and likely produces incorrect displays when curves cross, or stacking and banding are turned off.
+
==== Polygon series ====
 +
<tt>TPolygonSeries</tt> draws a filled polygon defined by the points of the series. It is intended to be the basis of contour plots or GIS plots (earth maps). The series supports both single and multiple polygons. Single polygons are closed automatically. Multiple Polygons are created by closing a first polygon and simply adding the points of one ore more subsequent polygon(s); each contributing polygon must be closed. Such polygonare are useful to display disconnected "islands" or to display "holes" in an outer shape; in the latter case the points of inner and outer polygons must have opposite orientations.
  
 
=== Multi-value series ===
 
=== Multi-value series ===
Line 109: Line 114:
 
==== Bubble series ====
 
==== Bubble series ====
  
<code>TBubbleSeries</code> represent data as circles of variable radius centered at data points.
+
<tt>TBubbleSeries</tt> represent data as circles of variable radius centered at data points.
This series requires a source with <code>YCount</code> of at least 2,
+
This series requires a source with <tt>YCount</tt> of at least 2,
 
and uses the first additional Y value as the bubble radius.
 
and uses the first additional Y value as the bubble radius.
  
The <code>OverrideColor</code> property allows you to set the color of either the interior or the edge of each bubble individually.
+
The <tt>OverrideColor</tt> property allows you to set the color of either the interior or the edge of each bubble individually.
  
 
==== Box-and-whiskers series ====
 
==== Box-and-whiskers series ====
  
<code>TBoxAndWhiskerSeries</code> represents data as rectangles with a central line and
+
<tt>TBoxAndWhiskerSeries</tt> represents data as rectangles with a central line and
 
two T-like shapes protruding in both directions.
 
two T-like shapes protruding in both directions.
 
Although in statistics a [[Wikipedia:Box_plot|box-and whiskers plot]] is supposed to be based on specific
 
Although in statistics a [[Wikipedia:Box_plot|box-and whiskers plot]] is supposed to be based on specific
Line 126: Line 131:
 
[[Wikipedia:Gantt_chart|Gantt diagrams]].
 
[[Wikipedia:Gantt_chart|Gantt diagrams]].
  
This series requires a source with <code>YCount</code> of at least 5, and uses Y values as follows:
+
This series requires a source with <tt>YCount</tt> of at least 5, and uses Y values as follows:
 
{|
 
{|
 
!Index!!Usage
 
!Index!!Usage
Line 144: Line 149:
 
==== Open-high-low-close series ====
 
==== Open-high-low-close series ====
  
<code>TOpenHighLowCloseSeries</code> represents data as vertical lines with two ticks,
+
<tt>TOpenHighLowCloseSeries</tt> represents data as vertical lines with two ticks,
 
as described [[Wikipedia:Open-high-low-close_chart|here]].
 
as described [[Wikipedia:Open-high-low-close_chart|here]].
  
It usually requires <code>YCount</code> of at least 4, and uses Y values as follows:
+
It usually requires <tt>YCount</tt> of at least 4, and uses Y values as follows:
 
{|
 
{|
 
!Property!!Default!!Usage
 
!Property!!Default!!Usage
Line 166: Line 171:
 
==== Field series ====
 
==== Field series ====
  
<code>TFieldSeries</code> displays a vector at each data point. The vector is drawn as a line segment with an optional arrow. The line is centered at the x,y coordinates stored in the chart source, its direction is given by additional values stored in the XList and YList of the chart source. Therefore, this series type requires a source with two x and y values:
+
<tt>TFieldSeries</tt> displays a vector at each data point. The vector is drawn as a line segment with an optional arrow. By default, the line is centered at the x,y coordinates stored in the chart source, its direction is given by additional values stored in the XList and YList of the chart source. When property <tt>VectorCoordKind</tt> is switched to <tt>vckStartend</tt> the line is defined by start and end points directly. In total, this series type requires a source with two x and y values:
 
{|
 
{|
 
!Source data item field !! Usage
 
!Source data item field !! Usage
 
|-
 
|-
|X || X coordinate of line center
+
|X || X coordinate of line center (or start point, if <tt>VectorCoordKind = vckStartEnd</tt>)
 
|-
 
|-
|Y || Y coordinate of line center
+
|Y || Y coordinate of line center (or start point)
 
|-
 
|-
|XList[0] || X coordinate of line direction
+
|XList[0] || X coordinate of line direction (or end point, if <tt>VectorCoordKind = vckStartEnd</tt>)
 
|-
 
|-
|YList[0] || Y coordinate of line direction
+
|YList[0] || Y coordinate of line direction (or end point)
 
|-
 
|-
 
|}  
 
|}  
  
The method <code>AddVector(x,y: Double; vectorx, vectory: Double; ALabel: String = &apos;&apos;; AColor: TColor = clTAColor)</code> helps to assign all values correctly to the internal list source.  
+
The method <tt>AddVector(x,y: Double; vectorx, vectory: Double; ALabel: String = &apos;&apos;; AColor: TColor = clTAColor)</tt> helps to assign all values correctly to the internal list source.  
  
In order to avoid overlapping of vectors call the method <code>NormalizeVectors(ALength: Double)</code> to normalize their lengths such that the longest vector has the specified length.  
+
In order to avoid overlapping of vectors call the method <tt>NormalizeVectors(ALength: Double)</tt> to normalize their lengths such that the longest vector has the specified length.  
  
 
The arrow parameters are understood to be percentages of the vector length, i.e. the arrow becomes smaller for shorter vectors.
 
The arrow parameters are understood to be percentages of the vector length, i.e. the arrow becomes smaller for shorter vectors.
Line 193: Line 198:
 
==== Pie series ====
 
==== Pie series ====
  
<code>TPieSeries</code> draws pie charts.
+
<tt>TPieSeries</tt> draws pie charts.
  
 
For each data point, pie series interprets Y value as a relative size of the slice,
 
For each data point, pie series interprets Y value as a relative size of the slice,
and X value as a distance of splice from the center of the pie (only if <code>Exploded</code> property is true).
+
and X value as a distance of slice from the center of the pie (only if <tt>Exploded</tt> property is true).
Slice colors can be set in data items, or taken from the hard-coded list.
+
 
 +
Beginning at <tt>StartAngle</tt>, the pies run in counter-clockwise direction around the circle. When <tt>AngleRange</tt> is at its default of 360 the pies cover the full circle; a smaller value allows to use the circle only partially.
  
Pie radius can be either set manually by <code>FixedRadius</code> property,
+
Pie radius can be either set manually by <tt>FixedRadius</tt> property,
 
or calculated automatically so that the whole series, including all labels, exactly fits the parent chart.
 
or calculated automatically so that the whole series, including all labels, exactly fits the parent chart.
  
Slice colors are determined by either data items' <code>Color</code> field or hard-coded palette.
+
A ring can be painted instead of a pie slice by giving the property <tt>InnerRadiusPercent</tt> a value greater than 0, but smaller than 100 - this determines the radius of the inner circle as percentage of the total radius.
Slices contours are drawn using <code>EdgePen</code> property.
+
 
 +
The slice colors are determined by either data items' <tt>Color</tt> field or hard-coded palette.
 +
Slices contours are drawn using <tt>EdgePen</tt> property.
  
There are several options for label positioning, controlled by <code>MarkPositions</code> property:
+
There are several options for label positioning, controlled by <tt>MarkPositions</tt> property:
* <code>pmpAround</code> -- marks are drawn outside the pie, on the continuation or radius vector for each slice
+
* <tt>pmpAround</tt> -- marks are drawn outside the pie, on the continuation or radius vector for each slice
* <code>pmpInside</code> -- marks are drawn inside each slice
+
* <tt>pmpInside</tt> -- marks are drawn inside each slice
* <code>pmpLeftRight</code> -- marks are drawn directly to the left or to the right of slice
+
* <tt>pmpLeftRight</tt> -- marks are drawn directly to the left or to the right of slice
  
<code>MarkDistancePercent</code>, if set to true, interprets Marks.Distance as percentage of the pie radius. Otherwise it is in image units.
+
<tt>MarkDistance</tt> defines the distance between the marks starting point and the label. The starting point is defined by <tt>MarkPositionCentered</tt> to be either the pie perimeter (<tt>false</tt>) or center (<tt>true</tt>). <tt>MarkDistancePercent</tt>, if set to <tt>true</tt>, interprets <tt>Marks.Distance</tt> as percentage of the pie radius. Otherwise it is in image units.
  
If <code>RotateLabels</code> is true, each label is additionally rotated so that
+
If <tt>RotateLabels</tt> is true, each label is additionally rotated so that
(if <code>LabelFont.Orientation=0</code>) it is parallel to the radius vector of its slice.
+
(if <tt>LabelFont.Orientation=0</tt>) it is parallel to the radius vector of its slice.
  
 
If the Y value of a data item is set to NaN, the item is [[#Skipping source items|skipped]].
 
If the Y value of a data item is set to NaN, the item is [[#Skipping source items|skipped]].
 
If the X value is set to NaN, the item is not drawn, but the space for it is still reserved. This allows drawing of "partial" pie diagrams.
 
If the X value is set to NaN, the item is not drawn, but the space for it is still reserved. This allows drawing of "partial" pie diagrams.
  
Pie charts have limited support for 3-d drawing.
+
Pie charts have limited support for 3-d drawing. The property <tt>Depth</tt> determines the thickness of the pie. <tt>Orientation</tt> supplements the normal view (<tt>poNormal</tt>) with an oblique view of the reclined (<tt>poHorizontal</tt>) and upright (<tt>poVertical</tt>) pie series, the latter two being controlled by property <tt>ViewAngle</tt> in degrees between 0 and 89. Since TAChart does not implement a true hidden line/hidden area algorithm there may be some chance of drawing artifacts for some combinations of parameters, in particular when <tt>AngleRange</tt> is not <tt>360</tt>. A slight change of <tt>StartAngle</tt> and/or <tt>AngleRange</tt> usually helps to fix this issue.
  
 
==== Polar series ====
 
==== Polar series ====
  
<code>TPolarSeries</code> represents data as points in [[Wikipedia:Polar_coordinate_system|polar coordinates]].
+
<tt>TPolarSeries</tt> represents data as points in [[Wikipedia:Polar_coordinate_system|polar coordinates]].
  
The origin of the polar coordinate system is defined in graph coordinates by <code>OriginX</code> and <code>OriginY</code>
+
The origin of the polar coordinate system is defined in graph coordinates by <tt>OriginX</tt> and <tt>OriginY</tt>
 
properties.
 
properties.
  
Line 232: Line 240:
  
 
Some additional properties:
 
Some additional properties:
* <code>CloseCircle</code>: If true the last point is connected with the first one.
+
* <tt>CloseCircle</tt>: If true the last point is connected with the first one.
* <code>Filled</code>: If true the polygon of the series points is filled using the current <code>Brush</code>. If <code>CloseCircle</code> is false the fill goes to the origin.
+
* <tt>Filled</tt>: If true the polygon of the series points is filled using the current <tt>Brush</tt>. If <tt>CloseCircle</tt> is false the fill goes to the origin.
* <code>ShowPoints</code>: If true then the series pointer is drawn at the position of each data point.
+
* <tt>ShowPoints</tt>: If true then the series pointer is drawn at the position of each data point.
  
 
=== User-drawn series ===
 
=== User-drawn series ===
  
Provides <code>OnDraw</code> and <code>OnGetBounds</code> events to allow arbitrary custom drawing on the TChart.
+
Provides <codtte>OnDraw</tt> and <tt>OnGetBounds</tt> events to allow arbitrary custom drawing on the TChart.
Note that using <code>TChart.Canvas</code> directly is highly discouraged and will often not work as expected.
+
Note that using <tt>TChart.Canvas</tt> directly is highly discouraged and will often not work as expected.
  
 
=== Functional series ===
 
=== Functional series ===
Line 251: Line 259:
 
==== Function series ====
 
==== Function series ====
  
<code>TFuncSeries</code> represents a one-dimensional function defined by <code>OnCalculate</code> event as a line.
+
<tt>TFuncSeries</tt> represents a one-dimensional function defined by the <tt>OnCalculate</tt> event. The function is calculated for each <tt>Step</tt> pixels of the image, so you can
 
 
The function is calculated for each <code>Step</code> pixels of the image, so you can
 
 
use this property to increase either "smoothness" or drawing speed.
 
use this property to increase either "smoothness" or drawing speed.
  
<code>Extent</code> property may be used to set both <i>x</i> and <i>y</i> extents for the purpose
+
The <tt>Extent</tt> property may be used to set both <i>x</i> and <i>y</i> extents for the purpose
 
of calculating [[#Extents|full extent]] of the chart.
 
of calculating [[#Extents|full extent]] of the chart.
 
While drawing, however, this property is ignored, and the function will be
 
While drawing, however, this property is ignored, and the function will be
 
displayed according to the current extent.
 
displayed according to the current extent.
  
<code>DomainExclusions</code> property allows to exclude some intervals from the function domain.
+
The <tt>DomainExclusions</tt> property allows to exclude some intervals from the function domain.
Function series correctly draws discontinuity points set by <code>DomainExclusions</code>.
+
The TFuncSeries correctly draws discontinuity points set by <tt>DomainExclusions</tt>.
Currently, <code>DomainExclusions</code> can only be set at run-time
+
Currently, <tt>DomainExclusions</tt> can only be set at run-time
by calling <code>AddRange</code> or <code>AddPoint</code> procedures.
+
by calling the <tt>AddRange</tt> or <tt>AddPoint</tt> procedures. Intervals defined by <tt>DomainExclusions</tt> are closed by default, i.e. contain the end points; this means that the function is not calculated at the end points. If the domain exclusion must contain endpoints (as needed for the funtion <tt>y = sqrt(x)</tt>) call <tt>AddRange</tt> with the corresponding element of the set <tt>TIntervalOptions = (ioOpenStart, ioOpenEnd)</tt> as optional third parameter.
  
To draw a function around the excluded interval, series must choose a point near the interval endpoint.
+
The <tt>DomainExclusions.Epsilon</tt> property controls the distance between endpoint and last drawn point (of course, in case of an open interval, the curve begins immediately at the end point).
<code>DomainExclusions.Epsilon</code> property controls the distance between endpoint and last drawn point.
+
<tt>Epsilon</tt> can be adjusted in the rare cases that the default value of 1E-6 does not produce correct results.
It may be increased for infinity-type discontinuities, and decreased to model open excluded intervals.
 
  
 
==== Expression series ====
 
==== Expression series ====
  
The <code>TExpressionSeries</code> is similar to the <code>TFuncSeries</code>, but the function is specified as a mathematical expression string such as <code>'sin(1.23456*x)'</code> (property <code>Expression</code>). The series creates an instance of the [[How_To_Use_TFPExpressionParser|FPExpressionParser]] to analyze the string and to calculate the function values. In this way functions can be plotted at designtime.
+
The <tt>TExpressionSeries</tt> is similar to the <tt>TFuncSeries</tt>, but the function is specified as a mathematical expression string such as <tt>'sin(1.23456*x)'</tt> (property <tt>Expression</tt>). The series creates an instance of the [[How_To_Use_TFPExpressionParser|FPExpressionParser]] to analyze the string and to calculate the function values. In this way functions can be plotted at designtime.
  
The property <code>Params</code> allows to define parameters for the function term; in the object inspector it opens a collection editor in which every parameter can be specified by its name (as used in the expression) and its value. If, for example, a parameter <code>f</code> is defined to have the value <code>1.23456</code> then above expression can also be written as <code>'sin(f*x)'</code>.
+
The property <tt>Params</tt> allows to define parameters for the function term; in the object inspector it opens a collection editor in which every parameter can be specified by its name (as used in the expression) and its value. If, for example, a parameter <tt>f</tt> is defined to have the value <tt>1.23456</tt> then above expression can also be written as <tt>'sin(f*x)'</tt>.
  
Similarly to <code>TFuncSeries</code>, domain exclusions are supported to define the regions at which the function cannot be calculated. But in agreement with mathematical conventions, <code>TExpressionSeries</code> requires in property <code>Domain</code> the region in which the function is '''defined''' (the complement of the domain exclusions). The region is specified by a string such as <code>'x >= 0'</code>. If several conditions exist they must be separated by a colon, e.g. <code>'x < -1; x > 1'</code>. The colon has function of a logical OR. An interval is defined like <code>'-1 < x < 1'</code>. The constant parts of the conditions can be mathematical expressions as well - the following example excludes the point &pi;/2 from calculation of the function values: <code>'x <> pi/2'</code>.
+
Similarly to <tt>TFuncSeries</tt>, domain exclusions are supported to define the regions at which the function cannot be calculated. But in agreement with mathematical conventions, <tt>TExpressionSeries</tt> requires in property <tt>Domain</tt> the region in which the function is '''defined''' (the complement of the domain exclusions). The region is specified by a string such as <tt>'x >= 0'</tt>. If several conditions exist they must be separated by a colon, e.g. <tt>'x < -1; x > 1'</tt>. The colon has function of a logical OR. An interval is defined like <tt>'-1 < x < 1'</tt>. The constant parts of the conditions can be mathematical expressions as well - the following example excludes the point &pi;/2 from calculation of the function values: <tt>'x <> pi/2'</tt>. Decimal numbers must be entered with a dot as decimal separator, no matter what is defined in the language settings of the operating system.
  
 
{{Note|Parameters and domains must be defined before the expression is entered, otherwise the parser will report an error}}
 
{{Note|Parameters and domains must be defined before the expression is entered, otherwise the parser will report an error}}
Line 282: Line 287:
 
==== B-spline series ====
 
==== B-spline series ====
  
<code>TBSplineSeries</code> draws [[Wikipedia:B-spline|B-spline]] of given <code>Degree</code> using [[Wikipedia:De_Boor's_algorithm|De Boor's algorithm]].
+
<tt>TBSplineSeries</tt> draws [[Wikipedia:B-spline|B-spline]] of given <tt>Degree</tt> using [[Wikipedia:De_Boor's_algorithm|De Boor's algorithm]].
  
Spline segments shorter then <code>Step</code> pixels are represented by straight lines.
+
Spline segments shorter then <tt>Step</tt> pixels are represented by straight lines.
  
 
==== Cubic spline series ====
 
==== Cubic spline series ====
  
<code>TCubicSplineSeries</code> draws the data curve as a [[Wikipedia:Spline_interpolation|cubic spline]] using the standard ''NumLib'' package of FPC.
+
<tt>TCubicSplineSeries</tt> draws the data curve as a [[Wikipedia:Spline_interpolation|cubic spline]] using the standard ''NumLib'' package of FPC.
  
In Lazarus v2.0+, a property <code>SplineType</code> allows to select between [[Wikipedia:Spline_interpolation|natural]] and [[Wikipedia:Monotone_cubic_interpolation|monotone Hermite]] splines, the latter avoiding overshoot of the interpolation.
+
In Lazarus v2.0+, a property <tt>SplineType</tt> allows to select between [[Wikipedia:Spline_interpolation|natural]] and [[Wikipedia:Monotone_cubic_interpolation|monotone Hermite]] splines, the latter avoiding overshoot of the interpolation.
  
The spline function is calculated for each <code>Step</code> pixels of the image, so you can use this property to increase "smoothness" or drawing speed.
+
The spline function is calculated for each <tt>Step</tt> pixels of the image, so you can use this property to increase "smoothness" or drawing speed.
  
The data source must contain at least two points and have strictly increasing X coordinates. (Older Lazarus versions before v2.0 require at least 4 data points; for less points a polygon is drawn instead of a spline using the <code>BadDataPen</code> if the <code>csoDrawFewPoints</code> option is set.)
+
The data source must contain at least two points and have strictly increasing X coordinates. (Older Lazarus versions before v2.0 require at least 4 data points; for less points a polygon is drawn instead of a spline using the <tt>BadDataPen</tt> if the <tt>csoDrawFewPoints</tt> option is set.)
  
If X values are unordered and the <code>csoDrawUnorderedX</code> option is set,
+
If X values are unordered and the <tt>csoDrawUnorderedX</tt> option is set,
the spline will be drawn ignoring offending points using <code>BadDataPen</code>.
+
the spline will be drawn ignoring offending points using <tt>BadDataPen</tt>.
  
The options <code>csoExtrapolateLeft</code> and <code>csoExtrapolateRight</code> enable natural extrapolation to the left and to the right correspondingly.
+
The options <tt>csoExtrapolateLeft</tt> and <tt>csoExtrapolateRight</tt> enable natural extrapolation to the left and to the right correspondingly.
  
 
==== Fit series ====
 
==== Fit series ====
  
<code>TFitSeries</code> performs [[Wikipedia:Least_squares|least squares fitting]] using calculation routines contained in the standard
+
<tt>TFitSeries</tt> performs [[Wikipedia:Least_squares|least squares fitting]] using calculation routines contained in the standard
[[numlib|Numlib]] package from the FPC. The main fitting unit is TAFitLib which is self-contained and can be applied also without TAChart.
+
[[numlib|Numlib]] package from the FPC. The main fitting unit is ''TAFitLib'' which is self-contained and can be applied also without TAChart.
 +
 
 +
The fitting function is selected via the <tt>FitEquation</tt> property:
 +
* <tt>fePolynomial</tt>: ''y'' = ''b''<sub>0</sub> + ''b''<sub>1</sub>''x'' + ''b''<sub>2</sub>''x''<sup>2</sup> + &hellip; + ''b''<sub>n</sub>''x''<sup>n</sup>, where the value of ''n'' is controlled by <code>ParamCount</code> property (<tt>ParamCount = n + 1</tt>).
 +
* <tt>feLinear</tt>: ''y'' = ''a'' + ''bx''
 +
* <tt>feExp</tt>: ''y'' = ''a'' * e''<sup>bx</sup>''
 +
* <tt>fePower</tt>: ''y'' = ''a'' * ''x''<sup>b</sup>
 +
* <tt>feCustom</tt>: ''y'' = ''b''<sub>0</sub>X<sub>0</sub>(''x'') + ''b''<sub>1</sub>X<sub>1</sub>(''x'') + ''b''<sub>2</sub>X<sub>2</sub>(''x'') + &hellip; + ''b''<sub>n</sub>X<sub>n</sub>(''x'') where the value of ''n'' is controlled by the <tt>ParamCount</tt> property (<tt>ParamCount = n + 1</tt>), and X<sub>i</sub>(''x''), ''i'' = 0..''n'', are "basis functions" which are defined by the method <tt>SetFitBasisFunc(AIndex: TFitFuncIndex; AFitFunc: TFitFunc; AFitFuncName: String)</tt>.
 +
** <tt>AIndex</tt> - index ''i'' of the basis function, <tt>1..MaxInt</tt>.
 +
** <tt>AFitFuncName</tt> is a text representation of the function to be used for the default legend.
 +
** <tt>AFitFunc</tt> - address of the basis function X<sub>i</sub>(''x'') which has the signature <tt>function(x: ArbFloat; Param: Integer): ArbFloat</tt> with <tt>ArbFloat</tt> being the general floating-point data type in FPC's [[numlib|Numlib]] (unit <i>typ</i>). Some basis functions are readily available in unit ''TAFitLib'':
  
The fitting function is selected via the <code>FitEquation</code> property:
+
<syntaxhighlight lang=pascal>
* <code>fePolynomial</code>: ''y'' = ''b''<sub>0</sub> + ''b''<sub>1</sub>''x'' + ''b''<sub>2</sub>''x''<sup>2</sup> + &hellip; + ''b''<sub>n</sub>''x''<sup>n</sup>, where the value of ''n'' is controlled by <code>ParamCount</code> property (<code>ParamCount = n + 1</code>).
+
function FitBaseFunc_Const(x: ArbFloat; Param: Integer): ArbFloat;  // constant term
* <code>feLinear</code>: ''y'' = ''a'' + ''bx''
+
function FitBaseFunc_Linear(x: ArbFloat; Param: Integer): ArbFloat; // linear term (x)
* <code>feExp</code>: ''y'' = ''a'' * e''<sup>bx</sup>''
+
function FitBaseFunc_Square(x: ArbFloat; Param: Integer): ArbFloat;  // square term (x^2)
* <code>fePower</code>: ''y'' = ''a'' * ''x''<sup>b</sup>
+
function FitBaseFunc_Cube(x: ArbFloat; Param: Integer): ArbFloat;   // cubic term (x^3)
* <code>feCustom</code>: ''y'' = ''b''<sub>0</sub> + ''b''<sub>1</sub>X<sub>1</sub>(''x'') + ''b''<sub>2</sub>X<sub>2</sub>(''x'') + &hellip; + ''b''<sub>n</sub>X<sub>n</sub>(''x'') where the value of ''n'' is controlled by the <code>ParamCount</code> property (<code>ParamCount = n + 1</code>), and X<sub>i</sub>(''x''), ''i'' = 1..''n'', are "basis functions" which are defined by the method <code>SetFitBasisFunc(AIndex: TFitFuncIndex; AFitFunc: TFitFunc; AFitFuncName: String)</code>.
+
function FitBaseFunc_Poly(x: ArbFloat; Param: Integer): ArbFloat;    // power term (x^Param)
** <code>AIndex</code> - index ''i'' of the basis function, <code>1..MaxInt</code>.
+
function FitBaseFunc_Sin(x: ArbFloat; Param: Integer): ArbFloat;     // sin(x*Param)  
** <code>AFitFunc</code> - address of the basis function X<sub>i</sub>(''x'') which has the signature <code>function(x: ArbFloat; Param: Integer): ArbFloat</code> with <code>ArbFloat</code> being the general floating-point data type in FPC's [[numlib|Numlib]] (unit <i>typ</i>).
+
function FitBaseFunc_Cos(x: ArbFloat; Param: Integer): ArbFloat;    // cos(x*Param)
** <code>AFitFuncName</code> is a text representation of the function to be used for the default legend.
+
</syntaxhighlight>
  
By default, the parameters, <code>b<sub>0</sub>, b<sub>1</sub>, ..., a, b</code> are varied by the fitting process such that the mean square deviation between data and fitted curves is minimized. However, it is also possible to hold one or more fitting parameters constant, e.g. in order to force a fitted straight line to run through the origin. For this purpose, the values of the constant parameters must be specified in the ';' or '|' delimited list of string values of property <code>FixedParams</code>. The order of values must match the order of the fitting parameters. Variable parameters can be left empty or replaced by a non-numerical string.  
+
By default, the parameters, <tt>b<sub>0</sub>, b<sub>1</sub>, ..., a, b</tt> are varied by the fitting process such that the mean square deviation between data and fitted curves is minimized. However, it is also possible to hold one or more fitting parameters constant, e.g. in order to force a fitted straight line to run through the origin. For this purpose, the values of the constant parameters must be specified in the ';' or '|' delimited list of string values of property <tt>FixedParams</tt>. The order of values must match the order of the fitting parameters. Variable parameters can be left empty or replaced by a non-numerical string.  
  
Example: <code>FixedParams='var;2'</code> (or shorter: <code>';2'</code>) means that the first fitting parameter is variable, but the second one is held constant a the value 2; if there are more than 2 parameters, the others are considered to be variable, too.  
+
Example: <tt>FixedParams='var;2'</tt> (or shorter: <tt>';2'</tt>) means that the first fitting parameter is variable, but the second one is held constant a the value 2; if there are more than 2 parameters, the others are considered to be variable, too.  
  
The fitting range is usually defined by the series extent, but can be manually set via the <code>FitRange</code> property.
+
The fitting range is usually defined by the series extent, but can be manually set via the <tt>FitRange</tt> property.
The fitting function is drawn over the entire axis unless <code>DrawFitRangeOnly = true</code>.
+
The fitting function is drawn over the entire axis unless <tt>DrawFitRangeOnly = true</tt>.
  
When fitting is complete the <code>ErrCode</code> of the series is set to indicate whether the calculation was successful or not:
+
When fitting is complete the <tt>ErrCode</tt> of the series is set to indicate whether the calculation was successful or not:
* <code>fitOK</code>: successful
+
* <tt>fitOK</tt>: successful
* <code>fitDimError</code>: calculation was aborted because the dimensions of the data arrays (x, y, y error bars) do not match.
+
* <tt>fitDimError</tt>: calculation was aborted because the dimensions of the data arrays (x, y, y error bars) do not match.
* <code>fitMoreParamsThanValues</code>: calculation failed because there are more fitting parameters than data values.
+
* <tt>fitMoreParamsThanValues</tt>: calculation failed because there are more fitting parameters than data values.
* <code>fitNoFitParams</code>:calculation aborted because no fit parameters are specified. This could happen incidentally if all fitting parameter are forced to be fixed in the <code>FixedParams</code> property.
+
* <tt>fitNoFitParams</tt>:calculation aborted because no fit parameters are specified. This could happen incidentally if all fitting parameter are forced to be fixed in the <tt>FixedParams</tt> property.
* <code>fitSingular</code>: the design matrix of the fit problem is found to be (nearly) singular.  
+
* <tt>fitSingular</tt>: the design matrix of the fit problem is found to be (nearly) singular.
 +
* <tt>fitNoBaseFunction</tt>: Not enough fit basis functions are specified for the case of <tt>FitEquation=feCustom</tt>.
 +
The method <tt>ErrorMsg</tt> creates a text for an error message from the current <tt>ErrCode</tt>.
  
The event <code>OnFitComplete</code> is called after the fitting equation is found, but before the drawing starts. This is a good place to query the results of the fitting procedure:  
+
The event <tt>OnFitComplete</tt> is called after the fitting equation is found, but before the drawing starts. This is a good place to query the results of the fitting procedure:  
* <code>Param[AIndex]</code> is the best-fit value for the parameter with the specified index, <code>AIndex = 0..ParamCount-1</code>.
+
* <tt>Param[AIndex]</tt> is the best-fit value for the parameter with the specified index, <tt>AIndex = 0..ParamCount-1</tt>.
* <code>ParamError[AIndex]</code> tells the uncertainty ("standard error" in statistical terms) of the corresponding fitting parameter.
+
* <tt>ParamError[AIndex]</tt> tells the uncertainty ("standard error" in statistical terms) of the corresponding fitting parameter.
* The procedure <code>GetConfidenceLimits(AIndex: Integer; out ALower, AUpper: Double)</code> returns the range between <code>ALower</code> and <code>AUpper</code> within which the corresponding best-fit parameter is expected to be found at the probability specified by <code>ConfidenceLevel</code> (default: <code>0.95</code>, i.e. 95%).
+
* The procedure <tt>GetConfidenceLimits(AIndex: Integer; out ALower, AUpper: Double)</tt> returns the range between <tt>ALower</tt> and <tt>AUpper</tt> within which the corresponding best-fit parameter is expected to be found at the probability specified by <tt>ConfidenceLevel</tt> (default: <tt>0.95</tt>, i.e. 95%).
* <code>Param_tValue[AIndex]</code> returns the value of the [[Wikipedia:T-statistic|t statistic]] for the corresponding fit parameter. This is the ratio of value divided by standard error. For an accurate parameter, the t value should be much larger than 1.
+
* <tt>Param_tValue[AIndex]</tt> returns the value of the [[Wikipedia:T-statistic|t statistic]] for the corresponding fit parameter. This is the ratio of value divided by standard error. For an accurate parameter, the t value should be much larger than 1.
* <code>Param_pValue[AIndex]</code> is the probability that any t value as high as <code>Param_tValue</code> occurs just by chance for the given degrees of freedom. In order to "trust" the fitted value with a certainty given by <code>ConfidenceLevel</code>, the p value should be smaller than <code>1 - ConfidenceLevel</code>, by default 0.05.
+
* <tt>Param_pValue[AIndex]</tt> is the probability that any t value as high as <tt>Param_tValue</tt> occurs just by chance for the given degrees of freedom. In order to "trust" the fitted value with a certainty given by <tt>ConfidenceLevel</tt>, the p value should be smaller than <tt>1 - ConfidenceLevel</tt>, by default 0.05.
* <code>FitStatistics</code> informs about other statistical parameters helpful to verify the validity of the fitted model or for further statistical calculations. These data are accessible as properties or functions of this class:
+
* <tt>FitStatistics</tt> informs about other statistical parameters helpful to verify the validity of the fitted model or for further statistical calculations. These data are accessible as properties or functions of this class:
** <code>N</code> (integer): the number of data points used for fitting. Note that this can be less than the data points provided by the chart source since it may contain NaN values which are skipped.
+
** <tt>N</tt> (integer): the number of data points used for fitting. Note that this can be less than the data points provided by the chart source since it may contain NaN values which are skipped.
** <code>M</code> (integer): the number of fitting parameters. Normally this is the value of <code>ParamCount</code>, but if certain parameters are forced to be constant (<code>FixedParams</code>) their count is subtracted.
+
** <tt>M</tt> (integer): the number of fitting parameters. Normally this is the value of <tt>ParamCount</tt>, but if certain parameters are forced to be constant (<tt>FixedParams</tt>) their count is subtracted.
** <code>DOF</code> (integer): "degrees of freedom" - is the difference <code>N - M</code>, an important parameter in the statistical analysis of the fit results.
+
** <tt>DOF</tt> (integer): "degrees of freedom" - is the difference <tt>N - M</tt>, an important parameter in the statistical analysis of the fit results.
** <code>SST</code>: "total sum of squares" - this is the sum of the squares of the term <code>(y[i] - ymean)/dy[i]</code> over all data points. Here, <code>y[i]</code> is the y value of a data point at index <code>i</code>, <code>dy[i]</code> the size of its error bar (standard deviation) - or 1 if not available -, and <code>ymean</code> is the average value of <code>y[i]/dy[i]</code>. The quantity identifies the total variation of data points around their mean value.
+
** <tt>SST</tt>: "total sum of squares" - this is the sum of the squares of the term <tt>(y[i] - ymean)/dy[i]</tt> over all data points. Here, <tt>y[i]</tt> is the y value of a data point at index <tt>i</tt>, <tt>dy[i]</tt> the size of its error bar (standard deviation) - or 1 if not available -, and <tt>ymean</tt> is the average value of <tt>y[i]/dy[i]</tt>. The quantity identifies the total variation of data points around their mean value.
** <code>SSE</code>: "error sum of squares" - the variation of the data points around the fitted curve, i.e. sum of <code>((y[i] - ycalc(x[i])/dy[i])^2)</code>; here <code>ycalc(x[i])</code> is the calculated value of the fitted curve at the point <code>x[i]</code>.
+
** <tt>SSE</tt>: "error sum of squares" - the variation of the data points around the fitted curve, i.e. sum of <tt>((y[i] - ycalc(x[i])/dy[i])^2)</tt>; here <tt>ycalc(x[i])</tt> is the calculated value of the fitted curve at the point <tt>x[i]</tt>.
** <code>SSR</code>: "regression sum of squares" - the variation of the fitted curve alone, i.e. sum of <code>((ycalc(x[i]) - ymean)/dy[i])^2</code>.
+
** <tt>SSR</tt>: "regression sum of squares" - the variation of the fitted curve alone, i.e. sum of <tt>((ycalc(x[i]) - ymean)/dy[i])^2</tt>.
** <code>xBar</code>: average value of the x coordinates of all used data points.
+
** <tt>xBar</tt>: average value of the x coordinates of all used data points.
** <code>SSx</code>: variation of the x coordinates of the data points, i.e. sum of <code>(x[i] - xbar)^2</code>.
+
** <tt>SSx</tt>: variation of the x coordinates of the data points, i.e. sum of <cottde>(x[i] - xbar)^2</tt>.
** <code>VarCovar[i, j: Integer]: Double</code>: is an element of the variance-covariance matrix for the fit parameters at the given indexes.
+
** <tt>VarCovar[i, j: Integer]: Double</tt>: is an element of the variance-covariance matrix for the fit parameters at the given indexes.
** <code>R2</code>: "coefficient of determination". This is the ratio <code>SSR/SSE</code> and describes how much of the variation in the data is explained by the fitted curve. The value is 1 for a perfect fit and 0 for absolutely no agreement.
+
** <tt>R2</tt>: "coefficient of determination". This is the ratio <tt>SSR/SSE</tt> and describes how much of the variation in the data is explained by the fitted curve. The value is 1 for a perfect fit and 0 for absolutely no agreement.
** <code>AdjR2</code>: was introduced to compensate for the effect that <code>R2</code> usually increases by adding more and more fit parameters.
+
** <tt>AdjR2</tt>: was introduced to compensate for the effect that <tt>R2</tt> usually increases by adding more and more fit parameters.
** <code>Chi2</code>: another word for <code>SSE</code>. In essence, this is the statistical quantity which is minimized during the fitting procedure. The value given is the minimum value found.
+
** <tt>Chi2</tt>: another word for <tt>SSE</tt>. In essence, this is the statistical quantity which is minimized during the fitting procedure. The value given is the minimum value found.
** <code>ReducedChi2</code>: is <code>Chi2</code> (or: <code>SSE</code>) normalized to the degrees of freedom, i.e. variation of the data around the fitted curve per degree of freedom. Should be "small" for a good fit.
+
** <tt>ReducedChi2</tt>: is <tt>Chi2</tt> (or: <tt>SSE</tt>) normalized to the degrees of freedom, i.e. variation of the data around the fitted curve per degree of freedom. Should be "small" for a good fit.
** <code>ResidualStdError</code>: is the overall standard error of the fit. Should be "small".
+
** <tt>ResidualStdError</tt>: is the overall standard error of the fit. Should be "small".
** <code>pValue</code>: (fractional) probability that the residual scatter of the data points around the fitted curve is by chance. Should be high, in practice a few thenths, although sometimes values as low as 0.001 are still accepted. If no error bars are included in the fit, sometimes p turns out to be either exactly 0 or 1 - such values should be ignored.
+
** <tt>pValue</tt>: (fractional) probability that the residual scatter of the data points around the fitted curve is by chance. Should be high, in practice a few thenths, although sometimes values as low as 0.001 are still accepted. If no error bars are included in the fit, sometimes p turns out to be either exactly 0 or 1 - such values should be ignored.
* The procedures <code>GetLowerConfidenceInterval(const Ax: Double; out AY: Double)</code>, <code>GetUpperConfidenceInterval</code>, <code>GetLowerPredictionInterval</code> and <code>GetUpperPredictionInterval</code> can be hooked into the <code>OnCalculate</code> event of a TFuncSeries in order to plot the limits of the lower and upper confidence and prediction intervals around the fitted curve. These limits define areas around the fitted curve within which the overall fitted curve (confidence interval) or individual data points (prediction interval) can be expected based on the probability given by <code>ConfidenceLevel</code>.
+
* The procedures <tt>GetLowerConfidenceInterval(const Ax: Double; out AY: Double)</tt>, <tt>GetUpperConfidenceInterval</tt>, <tt>GetLowerPredictionInterval</tt> and <tt>GetUpperPredictionInterval</tt> can be hooked into the <tt>OnCalculate</tt> event of a <tt>TFuncSeries</tt> in order to plot the limits of the lower and upper confidence and prediction intervals around the fitted curve. These limits define areas around the fitted curve within which the overall fitted curve (confidence interval) or individual data points (prediction interval) can be expected based on the probability given by <tt>ConfidenceLevel</tt>.
 
* Note: all these statistical data assume that the residual errors follow a normal distribution and that the error bars have been estimated appropriately.
 
* Note: all these statistical data assume that the residual errors follow a normal distribution and that the error bars have been estimated appropriately.
 
   
 
   
<code>EquationText</code> method returns an <code>IEquationText</code> interface, which allows to construct a string
+
The <tt>EquationText</tt> method returns an <tt>IEquationText</tt> interface, which allows to construct a string
 
representing the fit equation. You can override names of ''x'' and ''y'' variables, numeric format, and, finally, obtain a string
 
representing the fit equation. You can override names of ''x'' and ''y'' variables, numeric format, and, finally, obtain a string
from <code>Get</code> function.
+
from <tt>Get</tt> function.
Note that a transformation from IEquationText to String is defined, so usually there is no need to call <code>Get</code> explicitly.
+
Note that a transformation from IEquationText to String is defined, so usually there is no need to call <tt>Get</tt> explicitly.
  
[[#Legend item text|<code>Legend.Format</code>]] property of fit series supports additional format argument ('%2:s')
+
[[#Legend item text|<tt>Legend.Format</tt>]] property of fit series supports additional format argument ('%2:s')
 
pointing to the default equation text.
 
pointing to the default equation text.
  
After a change to <code>TFitSeries</code> parameters, the equation will be recalculated on the next drawing of the series.
+
After a change to <tt>TFitSeries</tt> parameters, the equation will be recalculated on the next drawing of the series.
To recalculate it immediately, call <code>ExecFit</code> procedure.
+
To recalculate it immediately, call <tt>ExecFit</tt> procedure.
Use <code>State</code> property to check the validity of current equation.
+
Use <tt>State</tt> property to check the validity of current equation.
  
 
==== Color map series ====
 
==== Color map series ====
  
<code>TColorMapSeries</code> represents a 2-dimensional function defined by the <code>OnCalculate</code> event
+
<tt>TColorMapSeries</tt> represents a 2-dimensional function defined by the <tt>OnCalculate</tt> event
 
as a field of pixels, with color depending on function value.
 
as a field of pixels, with color depending on function value.
  
The series is drawn as a set of rectangles of size <code>StepX</code> by <code>StepY</code> pixels.
+
The series is drawn as a set of rectangles of size <tt>StepX</tt> by <tt>StepY</tt> pixels.
 
The function is called once for each rectangle.
 
The function is called once for each rectangle.
  
Color values are defined by one of the built-in palettes (property <code>BuiltinPalette = cmpHot, cmpCold, cmpRainbow, cmpMonochrome</code>). The range of values mapped to the colors of the palette must be specified in <code>BuiltinPaletteMax</code> and <code>BuiltinPaletteMin</code>, otherwise the results are not predictable.
+
Color values are defined by one of the built-in palettes (property <tt>BuiltinPalette = cmpHot, cmpCold, cmpRainbow, cmpMonochrome</tt>). The range of values mapped to the colors of the palette must be specified in <tt>BuiltinPaletteMax</tt> and <tt>BuiltinPaletteMin</tt>, otherwise the results are not predictable.
  
Alternatively, an external ChartSource can be assigned to property <code>ColorSource</code>, which must be sorted.
+
Alternatively, an external ChartSource can be assigned to property <tt>ColorSource</tt>, which must be sorted.
 
Each data point of the chart source is interpreted as having its X value correspond to the Color value.
 
Each data point of the chart source is interpreted as having its X value correspond to the Color value.
 
If the actual value falls between color levels, it can be either linearly interpolated
 
If the actual value falls between color levels, it can be either linearly interpolated
(if <code>Interpolate</code> is <code>true</code>) or rounded down to the nearest level.
+
(if <tt>Interpolate</tt> is <tt>true</tt>) or rounded down to the nearest level.
  
When <code>Legend.Multiplicity=lmPoint</code>, the color map series will display the color levels in the [[#Legend|legend]].
+
When <tt>Legend.Multiplicity=lmPoint</tt>, the color map series will display the color levels in the [[#Legend|legend]].
  
 
==== Expression color map series ====
 
==== Expression color map series ====
  
is similar to the color map series with the main difference that the 2-dimensional function is not defined by an event, but by a mathematical expression, such as <code>x^2+y^2</code>, like in the TExpressionSeries, but now with two variables <code>x</code> and <code>y</code>. The variables can be renamed by means of the properties <code>VariableNameX</code> and <code>VariableNameY</code>. Similar to TExpressionSeries it is also possible to introduce parameters (property <code>Params</code>). Domains, however, are not supported, the function must be defined within the entire visible x/y range.
+
is similar to the color map series with the main difference that the 2-dimensional function is not defined by an event, but by a mathematical expression, such as <tt>x^2+y^2</tt>, like in the TExpressionSeries, but now with two variables <tt>x</tt> and <tt>y</tt>. The variables can be renamed by means of the properties <tt>VariableNameX</tt> and <tt>VariableNameY</tt>. Similar to <tt>TExpressionSeries</tt> it is also possible to introduce parameters (property <tt>Params</tt>). Domains, however, are not supported, the function must be defined within the entire visible x/y range.
  
 
== Sources ==
 
== Sources ==
  
Data can get into a chart from various sources.
+
[[File:chartsource_hierarchy.png|right]]Data can get into a chart from various sources.
They are implemented as a set of components derived from <code>TCustomChartSource</code>.
+
They are implemented as a set of components derived from <tt>TCustomChartSource</tt>.
  
To assign a source to a series, you can set the <code>Source</code> property.
+
To assign a source to a series, you can set the <tt>Source</tt> property.
 
If the property is left unassigned, the series will use its own built-in list source.
 
If the property is left unassigned, the series will use its own built-in list source.
Methods like <code>AddXY</code> are delegated to the current series source.
+
Methods like <tt>AddXY</tt> are delegated to the current series source.
 
Note that the list source is the only editable source, so after you assign,
 
Note that the list source is the only editable source, so after you assign,
for example, a random chart source to the series, a call to <code>AddXY</code> will raise an exception.
+
for example, a random chart source to the series, a call to <tt>AddXY</tt> will raise an exception.
  
Each data item has the following fields: <code>X</code>, <code>Y</code>, <code>XList</code>, <code>YList</code>, <code>Color</code>, <code>Text</code>.
+
Each data item has the following fields: <tt>X</tt>, <tt>Y</tt>, <tt>XList</tt>, <tt>YList</tt>, <tt>Color</tt>, <tt>Text</tt>.
  
 
=== Sorted sources ===
 
=== Sorted sources ===
Line 405: Line 422:
 
If it is known that X values of the source are ascending,
 
If it is known that X values of the source are ascending,
 
some additional optimizations like binary search become possible.
 
some additional optimizations like binary search become possible.
So all sources have <code>IsSorted</code> property which helps determine that.
+
So all sources have an <tt>IsSorted</tt> property which helps determine that.
 +
 
 +
In Lazarus 2.1+, the [[#List_source|<tt>TListChartSource</tt>]] can be sorted according to several criteria:
 +
* <tt>SortBy</tt> = <tt>sbX</tt>, <tt>sbY</tt>, <tt>sbText</tt>, <tt>sbColor</tt>, <tt>sbCustom</tt>: sorting by X or Y value, Text, Color or in a user-defined way, respectively. In the latter case a handler for the event <tt>OnCompare</tt> must be provided.
 +
* <tt>SortIndex</tt>: the index of the X or Y value used for sorting.
 +
* <tt>SortDir</tt> = <tt>sdAscending</tt>, <tt>sdDescending</tt>: sorting in ascending or descending order.
 +
 
 +
When a source is sorted by anything other than x only the drawing order of the related series is affected, and it may be possible that nothing changes in the chart. A visual effect is seen for
 +
* [[#Pie_series|<tt>TPieSeries</tt>]] because the data point order determines to order of the pies around the circle
 +
* [[#Bubble_series|<tt>TBubbleSeries</tt>]] when bubbles overlap. Use the combination <tt>SortBy=sbY</tt>, <tt>SortIndex=1</tt> and <tt>SortDir=sdDescending</tt> to avoid covered bubbles because large bubbles are drawn first and small bubbles last.
 +
* all series inherited from [[#Basic_series|<tt>TBasicPointSeries</tt>]] when the <tt>XCount</tt> of the associated chart source is 0: in this case, the X value of the source is ignored and replaced by the data point index. Since the data point index changes upon sorting the data points will be automatically rearranged in the sorted order - see example ''sort_demo'' in the ''demo'' folder.
  
 
=== Multi-valued sources ===
 
=== Multi-valued sources ===
  
 
Sources can contain multiple Y values for each X value.
 
Sources can contain multiple Y values for each X value.
These values are stored in the <code>YList</code> field of the source data item.
+
These values are stored in the <tt>YList</tt> field of the source data item.
The number of Y values is determined by the <code>YCount</code> property.
+
The number of Y values is determined by the <tt>YCount</tt> property.
Note that the first Y value is stored in Y field anyway, so <code>YCount=3</code>
+
Note that the first Y value is stored in Y field anyway, so <tt>YCount=3</tt>
means that values are stored in <code>Y</code>, <code>YList[0]</code> and <code>YList[1]</code>.
+
means that values are stored in <tt>Y</tt>, <tt>YList[0]</tt> and <tt>YList[1]</tt>.
  
 
Additional values may be used by various series -- for example, stacked bars or bubble charts.
 
Additional values may be used by various series -- for example, stacked bars or bubble charts.
  
Moreover, it is also possible to store several X values for the same data point. This is required by <code>TFieldSeries</code>. These additional X values are stored in the <code>XList</code> of the source data item. Like with the Y values, the total count of X values is given by the <code>XCount</code> property which contains the "ordinary" X value plus the length of the <code>XList</code> array.
+
Moreover, it is also possible to store several X values for the same data point. This is required by <tt>TFieldSeries</tt>. These additional X values are stored in the <tt>XList</tt> of the source data item. Like with the Y values, the total count of X values is given by the <tt>XCount</tt> property which contains the "ordinary" X value plus the length of the <tt>XList</tt> array.
  
 
=== Skipping source items ===
 
=== Skipping source items ===
Line 430: Line 457:
 
Also note that if you set only one coordinate to NaN, the other will still take part in extent calculation.
 
Also note that if you set only one coordinate to NaN, the other will still take part in extent calculation.
  
In case of stacked series it is not clear how the missing value should be handled when the following levels are added to it. In Lazarus v2.1+ there is a property <code>StackedNaN</code> which can be selected as
+
In case of stacked series it is not clear how the missing value should be handled when the following levels are added to it. In Lazarus v2.1+ there is a property <tt>StackedNaN</tt> which can be selected as
* <code>snReplaceByZero</code> -- the missing value is considered to be zero; this is the way how Excel handles this case.
+
* <tt>snReplaceByZero</tt> -- the missing value is considered to be zero; this is the way how Excel handles this case.
* <code>snDoNotDraw</code> -- skips the entire data point with all stack levels.
+
* <tt>snDoNotDraw</tt> -- skips the entire data point with all stack levels.
  
 
You can see examples of skipping items in the "nan" demo.
 
You can see examples of skipping items in the "nan" demo.
  
 
=== Error bars ===
 
=== Error bars ===
<code>TLineSeries</code>, <code>TBSplineSeries</code>, <code>TCubicSplineSeries</code> and <code>TFitSeries</code> can display error bars at each data point. The size of the error bars in both <code>x</code> and <code>y</code> direction is determined by the parameters in the <code>XErrorBarData</code> and <code>YErrorBarData</code> properties, respectively:
+
<tt>TLineSeries</tt>, <cottde>TBSplineSeries</tt>, <tt>TCubicSplineSeries</tt> and <tt>TFitSeries</tt> can display error bars at each data point. The size of the error bars in both <tt>x</tt> and <tt>y</tt> direction is determined by the parameters in the <tt>XErrorBarData</tt> and <tt>YErrorBarData</tt> properties, respectively:
* <code>Kind: TChartErrorBarKind</code>: defines how the following data are interpreted
+
* <tt>Kind: TChartErrorBarKind</tt>: defines how the following data are interpreted
** <code>ebkNone</code>: ignore - no error bars will be diplayed
+
** <tt>ebkNone</tt>: ignore - no error bars will be diplayed
** <code>ebkConst</code>: all data points have the same error bar given by <code>ValuePlus</code> and <code>ValueMinus</code>.  
+
** <tt>ebkConst</tt>: all data points have the same error bar given by <tt>ValuePlus</tt> and <tt>ValueMinus</tt>.  
** <code>ebkPercent</code>: the values <code>ValuePlus</code> and <code>ValueMinus</code> are understood as percentage of the data values.  
+
** <tt>ebkPercent</tt>: the values <code>ValuePlus</code> and <tt>ValueMinus</tt> are understood as percentage of the data values.  
** <code>ebkChartSource</code>: every data point can have an individual error bar. The error bar length is stored in the XList or YList of a multi-valued chart source. The index among all x and y values is specified by <code>IndexPlus</code> and <code>IndexMinus</code> for positive and negative error bar, respectively.  
+
** <tt>ebkChartSource</tt>: every data point can have an individual error bar. The error bar length is stored in the XList or YList of a multi-valued chart source. The index among all x and y values is specified by <tt>IndexPlus</tt> and <tt>IndexMinus</tt> for positive and negative error bar, respectively.  
* <code>ValuePlus</code> and <code>ValueMinus</code>: length of the positive and negative error bars, respectively. Depending on the setting of <code>Kind</code>, the value is assumed to be constant for all data points (<code>Kind = ebkConst</code>, axis units), or a percentage of the data point value (<code>Kind = ebkPercent</code>). Both values must be positive numbers with the exception of <code>ValueMinus = -1</code> which indicates that the negative error bar should be equal to the positive error bar.
+
* <tt>ValuePlus</tt> and <tt>ValueMinus</tt>: length of the positive and negative error bars, respectively. Depending on the setting of <tt>Kind</tt>, the value is assumed to be constant for all data points (<tt>Kind = tt</tt>, axis units), or a percentage of the data point value (<tt>Kind = ebkPercent</tt>). Both values must be positive numbers with the exception of <tt>ValueMinus = -1</tt> which indicates that the negative error bar should be equal to the positive error bar.
* <code>IndexPlus</code> and <code>IndexMinus</code> are used when <code>Kind</code> is <code>ebkChartSource</code> and indicate the x or y index in a multi-valued chartsource from which the error bar lengths for the individual data points can be obtained. Suppose a chart source contains two x values (<code>XCount = 2</code>) and XErrorBarData.ValuePlus is 1 then the second x value (stored in XList[0]) is used for the positive error bar length. If <code>IndexMinus</code> is -1 then the negative error bar length is assumed to be equal to that of the positive error bar without having to provide an explicit value in the chart source.
+
* <tt>IndexPlus</tt> and <tt>IndexMinus</tt> are used when <tt>Kind</tt> is <tt>ebkChartSource</tt> and indicate the x or y index in a multi-valued chartsource from which the error bar lengths for the individual data points can be obtained. Suppose a chart source contains two x values (<tt>XCount = 2</tt>) and <tt>XErrorBarData.ValuePlus</tt> is <tt>1</tt> then the second x value (stored in <tt>XList[0]</tt>) is used for the positive error bar length. If <tt>IndexMinus</tt> is -1 then the negative error bar length is assumed to be equal to that of the positive error bar without having to provide an explicit value in the chart source.
 
{{Note|Usage of multiple y values for other purposes than individual error bars is discouraged in this context because the present implementation can display error bars only for the y value with index 0.}}
 
{{Note|Usage of multiple y values for other purposes than individual error bars is discouraged in this context because the present implementation can display error bars only for the y value with index 0.}}
 
Each series type supporting error bars has additional properties <code>XErrorBars</code> and <code>YErrorBars</code> which determine how the error bars will be displayed:
 
Each series type supporting error bars has additional properties <code>XErrorBars</code> and <code>YErrorBars</code> which determine how the error bars will be displayed:
* <code>Visible</code> can be used to turn off error bars even if their size is specified in the chart source.
+
* <tt>Visible</tt> can be used to turn off error bars even if their size is specified in the chart source.
* <code>Width</code> is the length of the crossbar drawn at the end of the error bar. The default value -1 means that its length will be equal to the corresponding size of the series' <code>Pointer</code>.
+
* <tt>Width</tt> is the length of the crossbar drawn at the end of the error bar. The default value -1 means that its length will be equal to the corresponding size of the series' <tt>Pointer</tt>.
* <code>Pen</code> defines the pen parameter used for drawing the error bars. Usually set <code>Pen.Color</code> to the color of the series.
+
* <tt>Pen</tt> defines the pen parameter used for drawing the error bars. Usually set <tt>Pen.Color</tt> to the color of the series.
  
 
=== List source ===
 
=== List source ===
  
<code>TListChartSource</code> is a basic chart source, storing chart data inside itself.
+
<tt>TListChartSource</tt> is a basic chart source, storing chart data inside itself.
As such, you can use <code>Add</code> and <code>Delete</code> functions to change source data.
+
As such, you can use <tt>Add</tt> and <tt>Delete</tt> functions to change source data.
  
The <code>Item</code> property returns a pointer directly to the underlying storage,
+
The <tt>Item</tt> property returns a pointer directly to the underlying storage,
 
so you can modify item fields directly. However, doing this will not automatically update
 
so you can modify item fields directly. However, doing this will not automatically update
 
the chart and will also invalidate some internal state of list source.
 
the chart and will also invalidate some internal state of list source.
 
It is recommended:
 
It is recommended:
* To change a single item, use Set{Color|Text|XValue|YValue|YList} procedures.
+
* To change a single item, use <tt>Set{Color|Text|XValue|YValue|YList}</tt> procedures.
* To change many items in a time-sensitive code, call <code>BeginUpdate</code>, then modify items directly, then call <code>EndUpdate</code>.
+
* To change many items in a time-sensitive code, call <tt>BeginUpdate</tt>, then modify items directly, then call <tt>EndUpdate</tt>.
  
The source also has <code>DataPoints</code> property to allow setting data at design time.
+
The source also has <tt>DataPoints</tt> property to allow setting data at design time.
 
This property is a TStringList, with each line representing a data point.
 
This property is a TStringList, with each line representing a data point.
 
Line consists of X, Y, optional YList, Color and Text values separated by | (vertical bar) character.
 
Line consists of X, Y, optional YList, Color and Text values separated by | (vertical bar) character.
Note that <code>DataPoints</code> property is designed primarily for sample and demo code.
+
Note that <tt>DataPoints</tt> property is designed primarily for sample and demo code.
 
It is very inefficient, and you should not use it to add data points from the code.
 
It is very inefficient, and you should not use it to add data points from the code.
  
You can control X value sorting by setting the <code>Sorted</code> property.
+
You can control X value sorting by setting the <tt>Sorted</tt> property.
Note when <code>Sorted</code> is set to true, list source sorts the data and keeps it sorted
+
Note when <tt>Sorted</tt> is set to true, list source sorts the data and keeps it sorted
 
after insertion of new points. If inserted points are not sorted, this may result
 
after insertion of new points. If inserted points are not sorted, this may result
 
in quadratic running time.
 
in quadratic running time.
You should either set <code>Sorted</code> to true only after insertion,
+
You should either set <tt>Sorted</tt> to true only after insertion,
 
or pre-sort your data to avoid this.
 
or pre-sort your data to avoid this.
  
 
=== Random source ===
 
=== Random source ===
  
<code>TRandomChartSource</code> source generates random data in the given range and is intended mostly to use in demos.
+
<tt>TRandomChartSource</tt> source generates random data in the given range and is intended mostly to use in demos.
 
You can also use it as design-time replacement for your actual data source.
 
You can also use it as design-time replacement for your actual data source.
 
This will let you see and change the look of your chart without having to run the application.
 
This will let you see and change the look of your chart without having to run the application.
Line 492: Line 519:
 
You can of course also generate, filter or modify data with the user-defined source.
 
You can of course also generate, filter or modify data with the user-defined source.
  
The number of data items in the source is determined by <code>PointsNumber</code> property.
+
The number of data items in the source is determined by <tt>PointsNumber</tt> property.
Items themselves must be returned by the <code>OnGetChartDataItem</code> event handler.
+
Items themselves must be returned by the <tt>OnGetChartDataItem</tt> event handler.
You should call <code>Reset</code> method to notify the chart about changes in the data.
+
You should call <tt>Reset</tt> method to notify the chart about changes in the data.
 
(Other sources detect changes and perform notification automatically).
 
(Other sources detect changes and perform notification automatically).
  
Note that if the <code>Sorted</code> property is set to true, it is the responsibility
+
Note that if the <tt>Sorted</tt> property is set to true, it is the responsibility
 
of the event handler to provide actually sorted data.
 
of the event handler to provide actually sorted data.
  
 
=== Database source ===
 
=== Database source ===
  
<code>TDbChartSource</code> takes data directly from a database.
+
<tt>TDbChartSource</tt> takes data directly from a database.
 
It is contained in a separate unit to avoid introducing a db-aware component dependency
 
It is contained in a separate unit to avoid introducing a db-aware component dependency
 
into every project using TAChart.
 
into every project using TAChart.
Line 510: Line 537:
 
!Property!!Access method
 
!Property!!Access method
 
|-
 
|-
|<code>FieldX</code>||AsFloat (or AsDateTime, if option dcsoDateTimeX is set)
+
|<tt>FieldX</tt>||AsFloat (or AsDateTime, if option dcsoDateTimeX is set)
 
|-
 
|-
|<code>FieldY</code>||AsFloat (or AsDateTime, if option dcsoDateTimeY is set)
+
|<tt>FieldY</tt>||AsFloat (or AsDateTime, if option dcsoDateTimeY is set)
 
|-
 
|-
|<code>FieldColor</code>||AsInteger
+
|<tt>FieldColor</tt>||AsInteger
 
|-
 
|-
|<code>FieldText</code>||AsString
+
|<tt>FieldText</tt>||AsString
 
|-
 
|-
 
|}
 
|}
If <code>FieldX</code> property is empty, RecNo is used instead.
+
If <tt>FieldX</tt> property is empty, <tt>RecNo</tt> is used instead.
<code>NULL</code> values in coordinate fields are translated into [[#Skipping_source_items|NaNs]].
+
<tt>NULL</tt> values in coordinate fields are translated into [[#Skipping_source_items|NaNs]].
 +
 
 +
To get a multi-valued source, set the <tt>FieldY</tt> property to a comma-separated list of field names.
 +
Note that <tt>YCount</tt> will be set automatically -- trying to set it by hand will raise an exception.
 +
 
 +
When the dataset returns date/time fields as strings you should set the property <tt>DateTimeFormat</tt> accordingly (e.g. <tt>'yyyy-mm-dd'</tt>) so that the strings can be converted to a TDateTime variables.
  
To get multi-valued source, set <code>FieldY</code> property to a comma-separated list of field names.
+
Please note that iterating through the items of a <tt>TDBChartSource</tt> is very ineffective. Do not attach other DB-aware controls to the same dataset because they will mirror the process. Usually it is recommended to copy the <tt>DBChartSource</tt> to a <tt>ListChartSource</tt> for better performance. Note also that some dataset types do not read all records of a table or query.
Note that <code>YCount</code> will be set automatically -- trying to set it by hand will raise an exception.
 
  
 
=== Calculated source ===
 
=== Calculated source ===
  
<code>TCalculatedChartSource</code> is the source used for manipulating data taken from the
+
<tt>TCalculatedChartSource</tt> is the source used for manipulating data taken from the
<code>Origin</code> source.
+
<tt>Origin</tt> source.
 
This source performs transformations in the following order:
 
This source performs transformations in the following order:
* Y reordering -- Y values of multi-valued source can be duplicated, removed or exchanged according to <code>ReorderYList</code> property, which is a comma-separated list of original Y value indexes. Step skipped if <code>ReorderYList</code> is empty.
+
* Y reordering -- Y values of multi-valued source can be duplicated, removed or exchanged according to <tt>ReorderYList</tt> property, which is a comma-separated list of original Y value indexes. Step skipped if <tt>ReorderYList</tt> is empty.
 
* Accumulation -- replaces each item's Y values by a function of the neighboring values.
 
* Accumulation -- replaces each item's Y values by a function of the neighboring values.
 
* Percentage -- replace each Y value by the percentage of total of all Y values for that item. Useful for drawing "stacked percentage" bar and area charts. Step skipped if the <code>Percentage</code> property is false.
 
* Percentage -- replace each Y value by the percentage of total of all Y values for that item. Useful for drawing "stacked percentage" bar and area charts. Step skipped if the <code>Percentage</code> property is false.
Line 536: Line 567:
 
Accumulation is controlled by several properties:
 
Accumulation is controlled by several properties:
  
<code>AccumulationRange</code> controls number of items to accumulate, counting the current item,
+
<tt>AccumulationRange</tt> controls number of items to accumulate, counting the current item,
so <code>AccumulationRange = 1</code> disables accumulation.
+
so <tt>AccumulationRange = 1</tt> disables accumulation.
<code>AccumulationRange = 0</code> is interpreted as "infinite" range, i.e. request to accumulate over all
+
<tt>AccumulationRange = 0</tt> is interpreted as "infinite" range, i.e. request to accumulate over all
the available data. This is mostly useful in conjunction with <code>camSum</code> method to produce
+
the available data. This is mostly useful in conjunction with <tt>camSum</tt> method to produce
 
cumulative sums.
 
cumulative sums.
  
 
Note that the actual number of items may be lower for the points near the beginning or end of the source.
 
Note that the actual number of items may be lower for the points near the beginning or end of the source.
  
<code>AccumulationDirection</code>:
+
<tt>AccumulationDirection</tt>:
* cadBackward -- use previous values from the source,
+
* <tt>cadBackward</tt> -- use previous values from the source,
* cadForward -- use next values from the source,
+
* <tt>cadForward</tt> -- use next values from the source,
* cadCenter -- use both previous and next values for a total number of up to <code>2 * AccumulationRange - 1</code>.
+
* <tt>cadCenter</tt> -- use both previous and next values for a total number of up to <tt>2 * AccumulationRange - 1</tt>.
  
<code>AccumulationMethod</code>:
+
<tt>AccumulationMethod</tt>:
* camNone -- skip accumulation step,
+
* <tt>camNone</tt> -- skip accumulation step,
* camSum -- sum of the last <code>AccumulationRange</code> items,
+
* <tt>camSum</tt> -- sum of the last <tt>AccumulationRange</tt> items,
* camAverage -- average the last <code>AccumulationRange</code> items,
+
* <tt>camAverage</tt> -- average the last <tt>AccumulationRange</tt> items,
* camDerivative -- finite differences derivative, calculated using the last <code>AccumulationRange</code> items. Note that the calculation method assumes equidistant X values, and may loose accuracy if the X distance varies substantially.
+
* <tt>camDerivative</tt> -- finite differences derivative, calculated using the last <tt>AccumulationRange</tt> items. Note that the calculation method assumes equidistant X values, and may loose accuracy if the X distance varies substantially.
* camSmoothDerivative -- smoothed finite differences derivative, more robust against random measurement errors in the data.
+
* <tt>camSmoothDerivative</tt> -- smoothed finite differences derivative, more robust against random measurement errors in the data.
  
 
=== Interval source ===
 
=== Interval source ===
<code>TIntervalChartSource</code> can supply arbitrarily many points in a given interval, controlled by various properties of the source.
+
<tt>TIntervalChartSource</tt> can supply arbitrarily many points in a given interval, controlled by various properties of the source.
 
This source is the default built-in source for axis marks.
 
This source is the default built-in source for axis marks.
 
If you want to set the same [[#Axis intervals|axis interval parameters]] for several axes,
 
If you want to set the same [[#Axis intervals|axis interval parameters]] for several axes,
you can assign a single <code>TIntervalChartSource</code> component the <code>Marks.Source</code>
+
you can assign a single <tt>TIntervalChartSource</tt> component the <tt>Marks.Source</tt>
 
of each of those axes.
 
of each of those axes.
  
 
=== Date-time interval source ===
 
=== Date-time interval source ===
<code>TDateTimeIntervalChartSource</code> is similar to the [[#Interval source|<code>TIntervalChartSource</code>]],
+
<tt>TDateTimeIntervalChartSource</tt> is similar to the [[#Interval source|<tt>TIntervalChartSource</tt>]],
 
but provides marks formatted as [[#Date and time axises|date/time values]]. This source automatically selects appropriate calendar interval
 
but provides marks formatted as [[#Date and time axises|date/time values]]. This source automatically selects appropriate calendar interval
 
(such as week or hour) depending on the axis scale.
 
(such as week or hour) depending on the axis scale.
  
Note that X values of provided data items are <code>TDateTime</code> values, and <code>Label</code> values
+
Note that X values of provided data items are <tt>TDateTime</tt> values, and <tt>Label</tt> values
contain formatted date-time strings. If you want to use <code>TDateTimeIntervalChartSource</code> as the source of axis marks,
+
contain formatted date-time strings. If you want to use <tt>TDateTimeIntervalChartSource</tt> as the source of axis marks,
you should probably set <code>Marks.Format</code> or <code>Marks.Style</code> properties to make use of provided labels.
+
you should probably set <tt>Marks.Format</tt> or <tt>Marks.Style</tt> properties to make use of provided labels.
  
If the <code>DateTimeFormat</code> property is set, it is used to format all labels.
+
If the <tt>DateTimeFormat</tt> property is set, it is used to format all labels.
 
Formatting is performed with standard
 
Formatting is performed with standard
 
[http://www.freepascal.org/docs-html/rtl/sysutils/formatdatetime.html SysUtils.FormatDateTime] function.
 
[http://www.freepascal.org/docs-html/rtl/sysutils/formatdatetime.html SysUtils.FormatDateTime] function.
If <code>DateTimeFormat</code> is empty, format is chosen automatically based on scale.
+
If <tt>DateTimeFormat</tt> is empty, format is chosen automatically based on scale.
  
 
TDateTimeIntervalChartSource is defined in the [[TAIntervalSources]] unit.
 
TDateTimeIntervalChartSource is defined in the [[TAIntervalSources]] unit.
Line 588: Line 619:
  
 
A notable exception is the [[#List source|list source]], which is guaranteed to provide fast random access.
 
A notable exception is the [[#List source|list source]], which is guaranteed to provide fast random access.
It may be used to cache slow sources with the help of <code>CopyFrom</code> procedure.
+
It may be used to cache slow sources with the help of <tt>CopyFrom</tt> procedure.
  
Also note that the pointer returned by <code>GetItem</code> function may point to the internal buffer
+
Also note that the pointer returned by <tt>GetItem</tt> function may point to the internal buffer
which will be overwritten by the next call to <code>GetItem</code>. Again the list source does not have this limitation.
+
which will be overwritten by the next call to <tt>GetItem</tt>. Again the list source does not have this limitation.
  
 
== Coordinates and axes ==
 
== Coordinates and axes ==
Line 601: Line 632:
 
* ''Device coordinates'' are usually equal to screen coordinates, but may be adjusted to the drawing back-end to accommodate different physical resolutions (DPI values). See, for example, [[#Printer_drawer|printer drawer]].
 
* ''Device coordinates'' are usually equal to screen coordinates, but may be adjusted to the drawing back-end to accommodate different physical resolutions (DPI values). See, for example, [[#Printer_drawer|printer drawer]].
  
You can add or remove an arbitrary number of axes by editing <code>AxisList</code> property.
+
You can add or remove an arbitrary number of axes by editing <tt>AxisList</tt> property.
 
By default, chart have two axes: one horizontal and one vertical.
 
By default, chart have two axes: one horizontal and one vertical.
They are accessible via <code>BottomAxis</code> and <code>LeftAxis</code> properties.
+
They are accessible via <tt>BottomAxis</tt> and <tt>LeftAxis</tt> properties.
Note that those properties are aliases to <code>AxisList[0]</code> and <code>AxisList[1]</code>,
+
Note that those properties are aliases to <tt>AxisList[0]</tt> and <tt>AxisList[1]</tt>,
so if you remove those default axes, accessing <code>BottomAxis</code> and <code>LeftAxis</code> will return nil.
+
so if you remove those default axes, accessing <tt>BottomAxis</tt> and <tt>LeftAxis</tt> will return nil.
  
Visually, axis consists of the axis line (drawn by <code>AxisPen</code>), grid lines (drawn by <code>GridPen</code>),
+
Visually, axis consists of the axis line (drawn by <tt>AxisPen</tt>), grid lines (drawn by <tt>GridPen</tt>),
 
ticks, marks and arrow.
 
ticks, marks and arrow.
  
 
Each axis is drawn inside its own rectangle, determined by the size of mark labels and ticks.
 
Each axis is drawn inside its own rectangle, determined by the size of mark labels and ticks.
By assigning several axes the same positive <code>Group</code> number, you can have them share the same
+
By assigning several axes the same positive <tt>Group</tt> number, you can have them share the same
 
rectangular area. Grouped axes can be used to achieve a "panes" look,
 
rectangular area. Grouped axes can be used to achieve a "panes" look,
 
when several series are drawn on different portions of the same graph.
 
when several series are drawn on different portions of the same graph.
  
 
Axes with the same alignment, but different groups, are stacked alongside each other.
 
Axes with the same alignment, but different groups, are stacked alongside each other.
You can use the <code>Margin</code> property to control spacing between such axes.
+
You can use the <tt>Margin</tt> property to control spacing between such axes.
  
 
=== Axis transformations ===
 
=== Axis transformations ===
  
Axis transformations are grouped in the <code>TChartAxisTransformations</code> component.
+
Axis transformations are grouped in the <tt>TChartAxisTransformations</tt> component.
 
It contains a list of transformations which are applied in the order given.
 
It contains a list of transformations which are applied in the order given.
 
(For example, performing scale before and after logarithm will yield different results).
 
(For example, performing scale before and after logarithm will yield different results).
  
 
For transformations to have an effect, you should:
 
For transformations to have an effect, you should:
* Make sure <code>Enabled</code> property is true for all transformations.
+
* Make sure that the <tt>Enabled</tt> property is true for all transformations.
* Assign transformations component to <code>Transformations</code> property of at least one axis.
+
* Assign transformations component to <tt>Transformations</tt> property of at least one axis.
* Assign <code>AxisIndexX</code> and/or <code>AxisIndexY</code> properties of the series to the appropriate axis index.
+
* Assign <tt>AxisIndexX</tt> and/or <tt>AxisIndexY</tt> properties of the series to the appropriate axis index.
Note that by default, <code>AxisIndexX</code> and <code>AxisIndexY</code> have a special value of -1,
+
Note that by default, <tt>AxisIndexX</tt> and <tt>AxisIndexY</tt> have a special value of -1,
 
which means "ignore axis transformations". Also note that if you add or remove axes, the indexes may change.
 
which means "ignore axis transformations". Also note that if you add or remove axes, the indexes may change.
You can rotate the series by assigning ''both'' <code>AxisIndexX</code> to vertical axis and <code>AxisIndexY</code>
+
You can rotate the series by assigning ''both'' <tt>AxisIndexX</tt> to vertical axis and <tt>AxisIndexY</tt>
 
to the horizontal axis.
 
to the horizontal axis.
  
Line 640: Line 671:
  
 
To display several independently-scaled series, assign them to two or more axes
 
To display several independently-scaled series, assign them to two or more axes
and apply <code>TAutoScaleAxisTransform</code> to each axis.
+
and apply <tt>TAutoScaleAxisTransform</tt> to each axis.
 
See "axistransf" demo, page "Linear", checkbox "Auto scale".
 
See "axistransf" demo, page "Linear", checkbox "Auto scale".
  
By using the <code>MinValue</code> and <code>MaxValue</code> properties you can control the in graph coordinates
+
By using the <tt>MinValue</tt> and <tt>MaxValue</tt> properties you can control the in graph coordinates
 
of the auto-scaled series. For example, by setting one transformation to a range from 0 to 1, and another
 
of the auto-scaled series. For example, by setting one transformation to a range from 0 to 1, and another
 
to a range from 1 to 2, you will confine all the series using the first transformation to the upper half of the chart,
 
to a range from 1 to 2, you will confine all the series using the first transformation to the upper half of the chart,
Line 650: Line 681:
 
==== Cumulative normal distribution transformation ====
 
==== Cumulative normal distribution transformation ====
  
Use <code>TCumulNormDistrAxisTransform</code> to set [[Wikipedia:Cumulative_distribution_function|cumulative normal distribution]] as an axis transformation. This may be useful in statistical charting.
+
Use <tt>TCumulNormDistrAxisTransform</tt> to set [[Wikipedia:Cumulative_distribution_function|cumulative normal distribution]] as an axis transformation. This may be useful in statistical charting.
  
 
Note that this transformation result is in range from 0 to 1. It is recommended to restrict the axis range accordingly.
 
Note that this transformation result is in range from 0 to 1. It is recommended to restrict the axis range accordingly.
Line 658: Line 689:
 
==== User-defined transformation ====
 
==== User-defined transformation ====
  
You can create you own transformation either by inheriting from <code>TAxisTransform</code>,
+
You can create you own transformation either by inheriting from <tt>TAxisTransform</tt>,
or, if you prefer "visual" programming, by using <code>TUserDefinedAxisTransform</code>.
+
or, if you prefer "visual" programming, by using <tt>TUserDefinedAxisTransform</tt>.
 
In either case there are two basic requirements:
 
In either case there are two basic requirements:
* <code>AxisToGraph</code> and <code>GraphToAxis</code> functions should be defined everywhere in data range and inverse of each other (for example, avoid now only dividing, but also multiplying by zero).
+
* <tt>AxisToGraph</tt> and <tt>GraphToAxis</tt> functions should be defined everywhere in data range and inverse of each other (for example, avoid now only dividing, but also multiplying by zero).
 
* Functions should be monotonic.
 
* Functions should be monotonic.
  
Line 668: Line 699:
 
Using date/time values for axis marks is a common requirement.
 
Using date/time values for axis marks is a common requirement.
 
The correct way to do this depends on the exact nature of your date/time data:
 
The correct way to do this depends on the exact nature of your date/time data:
* If the data is actual <code>TDateTime</code> values, use it as an X coordinate in points, assign [[#Date-time interval source|<code>TDateTimeIntervalChartSource</code>]] to the <code>Marks.Source</code> of the corresponding axis, and change <code>Marks.Style</code> to <code>smsLabel</code>. <code>TDateTimeIntervalChartSource</code> provides automatic labeling depending on the scale in wide range -- from centuries to milliseconds.
+
* If the data is actual <tt>TDateTime</tt> values, use it as an X coordinate in points, assign [[#Date-time interval source|<tt>TDateTimeIntervalChartSource</tt>]] to the <tt>Marks.Source</tt> of the corresponding axis, and change <tt>Marks.Style</tt> to <tt>smsLabel</tt>. <tt>TDateTimeIntervalChartSource</tt> provides automatic labeling depending on the scale in wide range -- from centuries to milliseconds.
* If the data is in physical units, but outside <code>TDateTime</code> values range, such as astronomical or micro-electronics timings, use it as a normal X coordinate with custom <code>Marks.Format</code>.
+
* If the data is in physical units, but outside <tt>TDateTime</tt> values range, such as astronomical or micro-electronics timings, use it as a normal X coordinate with custom <tt>Marks.Format</tt>.
 
* If the data is in calendar units, such as months and years, which is common for financial data, you have several options:
 
* If the data is in calendar units, such as months and years, which is common for financial data, you have several options:
** If date units are "equidistant" when interpreted as numbers (for example, simple year numbers), assign the same data source to both series and axis marks, then use custom <code>Marks.Format</code>, <code>Axis.OnMarkToText</code> event or <code>Text</code> field of the data items to format dates per your requirements.
+
** If date units are "equidistant" when interpreted as numbers (for example, simple year numbers), assign the same data source to both series and axis marks, then use custom <tt>Marks.Format</tt>, <tt>Axis.OnMarkToText</tt> event or <code>Text</code> field of the data items to format dates per your requirements.
 
** If date units are not "equidistant" (for example, numbers in YYYYMM format or even date strings), use surrogate X coordinate (usually, simply a point index) instead and display dates using methods described above.
 
** If date units are not "equidistant" (for example, numbers in YYYYMM format or even date strings), use surrogate X coordinate (usually, simply a point index) instead and display dates using methods described above.
** Convert coordinates to <code>TDateTime</code> values beforehand, then use <code>TDateTimeIntervalChartSource</code> as described above.
+
** Convert coordinates to <tt>TDateTime</tt> values beforehand, then use <tt>tt</tt> as described above.
  
 
=== Axis ranges ===
 
=== Axis ranges ===
Line 679: Line 710:
 
Axis range is measured in axis units and determines the extent of series attached to this axis.
 
Axis range is measured in axis units and determines the extent of series attached to this axis.
 
Normally an axis range is equal to the union of all series extents,
 
Normally an axis range is equal to the union of all series extents,
but may be overridden with the <code>Range</code> property.
+
but may be overridden with the <tt>Range</tt> property.
  
 
Axis marks are displayed inside the axis marks range, which is determined as the intersection of:
 
Axis marks are displayed inside the axis marks range, which is determined as the intersection of:
 
* Logical extent (converted to axis coordinates)
 
* Logical extent (converted to axis coordinates)
* Combined extent of all data series of this axis, if <code>Marks.AtDataOnly = true</code>
+
* Combined extent of all data series of this axis, if <tt>Marks.AtDataOnly = true</tt>
* <code>Marks.Range</code> property.
+
* <tt>Marks.Range</tt> property.
  
 
=== Axis intervals ===
 
=== Axis intervals ===
  
 
Axis marks are located along the axis at equal intervals chosen by the chart.
 
Axis marks are located along the axis at equal intervals chosen by the chart.
The choice of intervals can be influenced via <code>Intervals</code> property. This property has a few subproperties, which are applied in the following order:
+
The choice of intervals can be influenced via <tt>Intervals</tt> property. This property has a few subproperties, which are applied in the following order:
* <code>Options</code> property contains a set of flags controlling usage of other parameters. If the flag is not in the set, the corresponding parameter is ignored.
+
* <tt>Options</tt> property contains a set of flags controlling usage of other parameters. If the flag is not in the set, the corresponding parameter is ignored.
* <code>NiceSteps</code> is a string containing a sequence of "step multipliers" -- floating point values in the range from 0 to 1, excluding 0. If this property is applied, the axis step will be a power of ten multiplied by one of the provided values. If several multipliers can be used, the leftmost one will be chosen. Multipliers are separated by the vertical bar (|) character.
+
* <tt>NiceSteps</tt> is a string containing a sequence of "step multipliers" -- floating point values in the range from 0 to 1, excluding 0. If this property is applied, the axis step will be a power of ten multiplied by one of the provided values. If several multipliers can be used, the leftmost one will be chosen. Multipliers are separated by the vertical bar (|) character.
* If <code>NiceSteps</code> is ignored or TAChart fails to find appropriate step, the axis range will be divided into equal intervals without regard to the number of decimal digits in the representation of mark values. In this case, it is recommended to reduce the number of visible digits in <code>Marks.Format</code>.
+
* If <tt>NiceSteps</tt> is ignored or TAChart fails to find appropriate step, the axis range will be divided into equal intervals without regard to the number of decimal digits in the representation of mark values. In this case, it is recommended to reduce the number of visible digits in <tt>Marks.Format</tt>.
* <code>MinLength</code> and <code>MaxLength</code> properties set the limits of interval length ''in image units'' (usually pixels).
+
* <tt>MinLength</tt> and <tt>MaxLength</tt> properties set the limits of interval length ''in image units'' (usually pixels).
* <code>Count</code> property is the desired number of axis marks. Among all mark steps passing the previous tests, TChart chooses the one which gives the number of marks nearest to the <code>Count</code>. If <code>Count</code> property is ignored, or there are several steps with equal number of marks, the longest step is chosen.
+
* <tt>Count</tt> property is the desired number of axis marks. Among all mark steps passing the previous tests, TChart chooses the one which gives the number of marks nearest to the <tt>Count</tt>. If <tt>Count</tt> property is ignored, or there are several steps with equal number of marks, the longest step is chosen.
* <code>Tolerance</code> property sets the maximum distance ''in image units'' by which the mark may be moved in order to reduce the length of its decimal representation. This helps to avoid a lot of meaningless digits in mark labels when previous steps have for some reason failed to generate "nice" marks. Note that this stage ignores all previous restrictions, so large <code>Tolerance</code> values may result in significant distortions. Setting <code>Tolerance = 1</code> is often sufficient.
+
* <tt>Tolerance</tt> property sets the maximum distance ''in image units'' by which the mark may be moved in order to reduce the length of its decimal representation. This helps to avoid a lot of meaningless digits in mark labels when previous steps have for some reason failed to generate "nice" marks. Note that this stage ignores all previous restrictions, so large <tt>Tolerance</tt> values may result in significant distortions. Setting <tt>Tolerance = 1</tt> is often sufficient.
  
Note that if you set chart source manually, <code>Intervals</code> property may apply only partially or not apply at all.
+
Note that if you set chart source manually, <tt>Intervals</tt> property may apply only partially or not apply at all.
 
For example, [[#List source| list source]] is unable to guarantee maximum interval length, since it has only a finite number of points. See also [[#Interval source|interval chart source]].
 
For example, [[#List source| list source]] is unable to guarantee maximum interval length, since it has only a finite number of points. See also [[#Interval source|interval chart source]].
  
 
=== Axis position ===
 
=== Axis position ===
  
By default, the axis is aligned to the side of the chart corresponding to the <code>Alignment</code> property.
+
By default, the axis is aligned to the side of the chart corresponding to the <tt>Alignment</tt> property.
You can position an axis differently by setting the <code>Position</code> and <code>PositionUnits</code> properties.
+
You can position an axis differently by setting the <tt>Position</tt> and <tt>PositionUnits</tt> properties.
  
 
The following values of the <code>PositionUnits</code> property are accepted:
 
The following values of the <code>PositionUnits</code> property are accepted:
* <code>cuPercent</code> -- percentage of the clipping rectangle.
+
* <tt>cuPercent</tt> -- percentage of the clipping rectangle.
* <code>cuGraph</code> -- absolute position in graph coordinates.
+
* <tt>cuGraph</tt> -- absolute position in graph coordinates.
* <code>cuPixels</code> -- position in screen units relative to the default coordinate.
+
* <tt>cuPixels</tt> -- position in screen units relative to the default coordinate.
  
'''Note 1:''' If the axis position is changed from default (<code>Position = 0</code> and <code>PositionUnits = cuPercent</code>),
+
'''Note 1:''' If the axis position is changed from default (<tt>Position = 0</tt> and <tt>PositionUnits = cuPercent</tt>),
 
it will be excluded from the margins calculation, so it will appear to overlap the series.
 
it will be excluded from the margins calculation, so it will appear to overlap the series.
  
'''Note 2:''' The <code>Alignment</code> affects not only the position of the axis itself,
+
'''Note 2:''' The <tt>Alignment</tt> affects not only the position of the axis itself,
but also of the corresponding labels. So, if two axes have both <code>Position = 50</code> and <code>PositionUnits = cuPercent</code>,
+
but also of the corresponding labels. So, if two axes have both <tt>Position = 50</tt> and <tt>PositionUnits = cuPercent</tt>,
but one has <code>Alignment = calLeft</code> and another <code>Alignment = calRight</code>, they will diaplay a common axis line
+
but one has <tt>Alignment = calLeft</tt> and another <tt>Alignment = calRight</tt>, they will diaplay a common axis line
 
with labels on different sides.
 
with labels on different sides.
  
Line 723: Line 754:
  
 
If the property <tt>TextFormat</tt> is switched to <tt>tfHTML</tt> then HTML entities and tags can be embedded for special formatting of axis titles, such as subscripts/superscripts or greek characters. See [[#HTML|HTML]] for details.
 
If the property <tt>TextFormat</tt> is switched to <tt>tfHTML</tt> then HTML entities and tags can be embedded for special formatting of axis titles, such as subscripts/superscripts or greek characters. See [[#HTML|HTML]] for details.
 +
 +
The property <tt>Wordwrap</tt>, if set to <tt>true</tt>, allows to wrap extra long axis titles into new lines. Note that this feature works only when the title is horizontal for the x axis and vertical for the y axis. Moreover, html-formatted text is not supported for word-wrapping.
  
 
=== Axis LabelSize ===
 
=== Axis LabelSize ===
  
Since Lazarus v1.4 the chart axes have a new property <code>LabelSize</code> which - if different from <code>0</code> - overrides the automatic calculation of the space needed by the axis marks. The <code>LabelSize</code>, approximately, defines the pixels between axis line and axis title, independently of the size of the axis labels. This feature can be used to align the axis lines of several charts that are stacked above each other or placed side by side.  
+
Since Lazarus v1.4 the chart axes have a new property <tt>LabelSize</tt> which - if different from <tt>0</tt> - overrides the automatic calculation of the space needed by the axis marks. The <tt>LabelSize</tt>, approximately, defines the pixels between axis line and axis title, independently of the size of the axis labels. This feature can be used to align the axis lines of several charts that are stacked above each other or placed side by side.  
  
 
See the "axisalign" demo and [[TAChart_documentation#Graphical_explanation|Graphical explanation]] for an example.
 
See the "axisalign" demo and [[TAChart_documentation#Graphical_explanation|Graphical explanation]] for an example.
Line 739: Line 772:
  
 
There are several extents defined by TChart:
 
There are several extents defined by TChart:
* ''Full extent'' -- usually determined automatically as the area encompassing all the data from series and axis ranges. Is returned by the <code>GetFullExtent</code> function.
+
* ''Full extent'' -- usually determined automatically as the area encompassing all the data from series and axis ranges. Is returned by the <tt>GetFullExtent</tt> function.
* ''Fixed extent'' -- determined by the <code>TChart.Extent</code> property. May override full extent calculation partially or fully.
+
* ''Fixed extent'' -- determined by the <tt>TChart.Extent</tt> property. May override full extent calculation partially or fully.
* <code>LogicalExtent</code> -- the extent requested by the user to be seen on the chart image. Writing to this property is the official way to change the chart extent by external code. For example, <code>LogicalExtent := GetFullExtent</code> is (almost) equivalent to calling the <code>ZoomFull</code> procedure.
+
* <tt>LogicalExtent</tt> -- the extent requested by the user to be seen on the chart image. Writing to this property is the official way to change the chart extent by external code. For example, <tt>LogicalExtent := GetFullExtent</tt> is (almost) equivalent to calling the <tt>ZoomFull</tt> procedure.
* <code>CurrentExtent</code> -- the extent actually displayed to the user. May differ from the <code>LogicalExtent</code> due to the need to reserve space for series [[#Marks|marks]], inner chart [[#Margins|margins]] etc.
+
* <tt>CurrentExtent</tt> -- the extent actually displayed to the user. May differ from the <tt>LogicalExtent</tt> due to the need to reserve space for series [[#Marks|marks]], inner chart [[#Margins|margins]] etc.
  
The value of the minimum extent cannot be greater than the value of the maximum extent. If an attempt is made to set such values an exception will be generated. To prevent exceptions, the procedure <code>.Extent.FixTo(aBounds: TDoubleRect)</code> can be used to set logical extents. The values in <code>TDoubleRect</code> are ordered in the following way: ''[xmin, ymin, xmax, ymax]''.
+
The value of the minimum extent cannot be greater than the value of the maximum extent. If an attempt is made to set such values an exception will be generated. To prevent exceptions, the procedure <tt>.Extent.FixTo(aBounds: TDoubleRect)</tt> can be used to set logical extents. The values in <tt>TDoubleRect</tt> are ordered in the following way: ''[xmin, ymin, xmax, ymax]''.
  
In order to invert the extents, the property <code>Inverted</code>' of the (left, bottom, etc) axis shall be set to <code>True</code>.
+
In order to invert the extents, the property <tt>Inverted</tt>' of the (left, bottom, etc) axis shall be set to <tt>True</tt>.
  
'''Important:''' Setting logical extents will work as required only if all the <code>Margins</code> of the chart are set to 0 (default value is 4) and <code>Series.Marks.AutoMargins</code> to all series in the chart is set to <code>False</code> (default is <code>True</code>). Otherwise, the requested extent will be enlarged to include also the chart's <code>Margins</code> as well as the series' <code>Marks</code>.
+
'''Important:''' Setting logical extents will work as required only if all the <tt>Margins</tt> of the chart are set to 0 (default value is 4) and <tt>Series.Marks.AutoMargins</tt> to all series in the chart is set to <tt>False</tt> (default is <tt>True</tt>). Otherwise, the requested extent will be enlarged to include also the chart's <tt>Margins</tt> as well as the series' <tt>Marks</tt>.
  
 
=== Extent limits ===
 
=== Extent limits ===
Line 756: Line 789:
 
while setting the upper bound may force the user to only see a part of the very long series at any given time.
 
while setting the upper bound may force the user to only see a part of the very long series at any given time.
  
The extent can be limited with the <code>ExtentSizeLimit</code> property.
+
The extent can be limited with the <tt>ExtentSizeLimit</tt> property.
Sub-properties <code>MinX</code>, <code>MinY</code>, <code>UseMinX</code> and <code>UseMinY</code> control
+
Sub-properties <tt>MinX</tt>, <tt>MinY</tt>, <tt>UseMinX</tt> and <tt>UseMinY</tt> control the lower bounds of the extent, while sub-properties <tt>MaxX</tt>, <tt>MaxY</tt>, <tt>UseMaxX</tt> and <tt>UseMaxY</tt> control
the lower bounds of the extent, while  
 
sub-properties <code>MaxX</code>, <code>MaxY</code>, <code>UseMaxX</code> and <code>UseMaxY</code> control
 
 
the upper bounds.
 
the upper bounds.
  
 
Extent limits are expressed in graph units.
 
Extent limits are expressed in graph units.
  
Setting <code>Proportional = true</code> will enforce the current extent to have the shape of the plot area.
+
Setting <tt>Proportional = true</tt> will enforce the current extent to have the shape of the plot area.
 
This may be useful for cartographic or some math plots which require the same scale on both axes.
 
This may be useful for cartographic or some math plots which require the same scale on both axes.
  
 
=== Linked extents ===
 
=== Linked extents ===
  
Using the <code>TChartExtentLink</code> component, you can ensure that the logical extents of several charts
+
Using the <tt>TChartExtentLink</tt> component, you can ensure that the logical extents of several charts
enumerated by the <code>LinkedCharts</code> property always stay the same.
+
enumerated by the <tt>LinkedCharts</tt> property always stay the same. In Laz 2.1+ the component is extended to provide an additional property <tt>AlignSides</tt> which adjusts the <tt>LabelSize</tt> properties of aligned charts such that the corresponding sides of the plot area are aligned, too. (When property <tt>AlignMissingAxes</tt> is <tt>true</tt> (default) dummy axes are created for those sides having no axes so that alignment works for these sides, too).
  
 
This is useful for simulating multi-pane chart layouts. See "panes" demo for an example.
 
This is useful for simulating multi-pane chart layouts. See "panes" demo for an example.
Line 778: Line 809:
 
''Margin'' is a distance reserved around the edges of rectangular region. Margins are measured in image units (usually pixels).
 
''Margin'' is a distance reserved around the edges of rectangular region. Margins are measured in image units (usually pixels).
 
The chart itself has two kinds of margins:
 
The chart itself has two kinds of margins:
* Internal (<code>Margins</code> property) -- applied after axis drawing. Are also influenced by series marks and series themselves.
+
* Internal (<tt>Margins</tt> property) -- applied after axis drawing. Are also influenced by series marks and series themselves.
* External (<code>MarginsExternal</code> property) -- applied before axis drawing. Are also influenced by axis marks and arrows.
+
* External (<tt>MarginsExternal</tt> property) -- applied before axis drawing. Are also influenced by axis marks and arrows.
  
 
Other chart elements, such as legend, title, footer and labels, have margins, too.
 
Other chart elements, such as legend, title, footer and labels, have margins, too.
Line 785: Line 816:
 
=== Optimization notes ===
 
=== Optimization notes ===
  
Calculation of <code>CurrentExtent</code> and actual margins is a non-trivial ''iterative'' process (see <code>TChart.PrepareAxis</code> code for details).
+
Calculation of <tt>CurrentExtent</tt> and actual margins is a non-trivial ''iterative'' process (see <tt>TChart.PrepareAxis</tt> code for details).
 
Although usually fast, in complex cases it can require multiple passes through chart sources.
 
Although usually fast, in complex cases it can require multiple passes through chart sources.
  
Line 796: Line 827:
 
You can see examples of tools usage in the "tools" or "barseriestools" demos.  
 
You can see examples of tools usage in the "tools" or "barseriestools" demos.  
  
Tools are grouped in a <code>TChartToolset</code> component,
+
Tools are grouped in a <tt>TChartToolset</tt> component,
which should be assigned to the chart's <code>Toolset</code> property.
+
which should be assigned to the chart's <tt>Toolset</tt> property.
 
The same toolset can be used in several charts.
 
The same toolset can be used in several charts.
  
If <code>Toolset</code> is unassigned, for compatibility reasons a built-in toolset consisting of
+
If <tt>Toolset</tt> is unassigned, for compatibility reasons a built-in toolset consisting of
[[#Zoom drag tool|zoom drag ]] and [[#Pan drag tool|pan drag]] tools is used; these builtin tools can be turned off individually by setting the chart properties <code>AllowZoom</code> and/or <code>AllowPanning</code> to <code>false</code>, respectively (the latter is available only after Lazarus v2.2+).
+
[[#Zoom drag tool|zoom drag ]] and [[#Pan drag tool|pan drag]] tools is used; these builtin tools can be turned off individually by setting the chart properties <tt>AllowZoom</tt> and/or <tt>AllowPanning</tt> to <tt>false</tt>, respectively (the latter is available only after Lazarus v2.2+).
  
 
In each user action, tools in the toolset are processed in order, and for each tool:
 
In each user action, tools in the toolset are processed in order, and for each tool:
* If <code>Enabled=false</code>, the tool is ignored.
+
* If <tt>Enabled=false</tt>, the tool is ignored.
* If <code>Shift</code> is not equal to the current shift state, the tool is ignored.
+
* If <tt>Shift</tt> is not equal to the current shift state, the tool is ignored.
 
* Tool is requested to process the action.
 
* Tool is requested to process the action.
* If the tool signals that the action is handled, processing is stopped, otherwise it continues to the next tool. This way, tools with the same <code>Shift</code> value may be differentiated based on special activation conditions. For example, some drag tools may be configured to not activate on a simple click, leaving the click event available for other actions.
+
* If the tool signals that the action is handled, processing is stopped, otherwise it continues to the next tool. This way, tools with the same <tt>Shift</tt> value may be differentiated based on special activation conditions. For example, some drag tools may be configured to not activate on a simple click, leaving the click event available for other actions.
 
* Finally, if no suitable tool is found, the chart's event handler is called. Note that this means that chart event handlers will only work with all tools disabled. Generally it is recommended to use tools for interactivity, chart events are left mostly for compatibility.
 
* Finally, if no suitable tool is found, the chart's event handler is called. Note that this means that chart event handlers will only work with all tools disabled. Generally it is recommended to use tools for interactivity, chart events are left mostly for compatibility.
  
 
In your application you can create, for example, a toolbar with each button enabling the corresponding tool in the toolset and disabling all others.
 
In your application you can create, for example, a toolbar with each button enabling the corresponding tool in the toolset and disabling all others.
Alternatively, by assigning different <code>Shift</code> values, you can enable several tools at once.
+
Alternatively, by assigning different <tt>Shift</tt> values, you can enable several tools at once.
  
Some tools publish the <code>EscapeCancels</code> property which, if set to <code>true</code>, cancels the tool operation if the user pressed the ESC key.
+
Some tools publish the <tt>EscapeCancels</tt> property which, if set to <tt>true</tt>, cancels the tool operation if the user pressed the ESC key.
  
 
=== Keyboard handling in tools ===
 
=== Keyboard handling in tools ===
  
 
Besides mouse events, some tools may react on key presses -- for example, [[#Data point crosshair tool|crosshair tool]] with
 
Besides mouse events, some tools may react on key presses -- for example, [[#Data point crosshair tool|crosshair tool]] with
<code>Shift = [ssCtrl]</code> will display crosshairs when the CTRL key is pressed, without mouse buttons.
+
<tt>Shift = [ssCtrl]</tt> will display crosshairs when the CTRL key is pressed, without mouse buttons.
 
Unfortunately, the chart must be focused to receive keyboard events.
 
Unfortunately, the chart must be focused to receive keyboard events.
 
This means that after the user interacted with other controls on the same form, the chart stops reacting on keyboard-only events.
 
This means that after the user interacted with other controls on the same form, the chart stops reacting on keyboard-only events.
  
To prevent this, you can either call the <code>Chart.SetFocus</code> method, or set <code>Chart.AutoFocus = true</code>,
+
To prevent this, you can either call the <tt>Chart.SetFocus</tt> method, or set <tt>Chart.AutoFocus = true</tt>,
 
which will make a chart grab the focus when the mouse moves over it.
 
which will make a chart grab the focus when the mouse moves over it.
  
Line 832: Line 863:
  
 
There are two ways to display those shapes: either simply draw them over the chart, fully redrawing the chart
 
There are two ways to display those shapes: either simply draw them over the chart, fully redrawing the chart
upon each mouse movement, or use <code>pmXor</code> pen mode to draw and erase the shape directly from
+
upon each mouse movement, or use <tt>pmXor</tt> pen mode to draw and erase the shape directly from
the <code>MouseMove</code> event handler.
+
the <tt>MouseMove</tt> event handler.
 
The former method allows to use arbitrary pen color and style, but the latter is much more efficient.
 
The former method allows to use arbitrary pen color and style, but the latter is much more efficient.
Additionally, some widgetsets ignore all drawing outside the <code>Paint</code> event, in such a case the latter method will not work at all.
+
Additionally, some widgetsets ignore all drawing outside the <tt>Paint</tt> event, in such a case the latter method will not work at all.
  
 
The display method is controlled by the <code>DrawingMode</code> property with the following values:
 
The display method is controlled by the <code>DrawingMode</code> property with the following values:
* <code>tdmXor</code> -- use XOR method;
+
* <tt>tdmXor</tt> -- use XOR method;
* <code>tdmNormal</code> -- use full chart redraw;
+
* <tt>tdmNormal</tt> -- use full chart redraw;
* <code>tdmDefault</code> -- use XOR method on widgetsets where it is known to work (Windows and Gtk) and full redraw on others.
+
* <tt>tdmDefault</tt> -- use XOR method on widgetsets where it is known to work (Windows and Gtk) and full redraw on others.
  
 
=== Extent tools ===
 
=== Extent tools ===
Line 846: Line 877:
 
Extent tools modify the chart's [[#Extents|logical extent]].
 
Extent tools modify the chart's [[#Extents|logical extent]].
  
Zooming tools can be animated by setting <code>AnimationSteps</code> to a value greater then 1
+
Zooming tools can be animated by setting <tt>AnimationSteps</tt> to a value greater then <tt>1</tt>
and specifying an appropriate <code>AnimationInterval</code> in milliseconds.
+
and specifying an appropriate <tt>AnimationInterval</tt> in milliseconds.  
  
Panning tools can be restricted to the chart extent on all or some directions
+
In the zooming tools, adapt the <tt>LimitToExtent</tt> property to restrict zooming to the chart's full extent on all or some directions. The same property is available also in the panning tools for the corresponding purpose when the viewport is panned.
by using the <code>LimitToExtent</code> property.
 
  
 
==== Zoom drag tool ====
 
==== Zoom drag tool ====
  
<code>TZoomDragTool</code> allows the user to zoom in by drawing a rectangle with the mouse.
+
<tt>TZoomDragTool</tt> allows the user to zoom in by drawing a rectangle with the mouse.
 
The rectangle then becomes the new [[#Extents|logical extent]].
 
The rectangle then becomes the new [[#Extents|logical extent]].
  
 
Restoration of the zooming to the full extent can be achieved by several actions,
 
Restoration of the zooming to the full extent can be achieved by several actions,
controlled by the <code>RestoreExtentOn</code> property:
+
controlled by the <tt>RestoreExtentOn</tt> property:
* <code>zreDragTopLeft</code>, <code>zreDragTopRight</code>, <code>zreDragBottomLeft</code>, <code>zreDragBottomRight</code> -- dragging in the specified direction,
+
* <tt>zreDragTopLeft</tt>, <tt>zreDragTopRight</tt>, <tt>zreDragBottomLeft</tt>, <tt>zreDragBottomRight</tt> -- dragging in the specified direction,
* <code>zreClick</code> -- clicking without dragging,
+
* <tt>zreClick</tt> -- clicking without dragging,
* <code>zreDifferentDrag</code> -- dragging in a direction different from the one used to zoom in.
+
* <tt>zreDifferentDrag</tt> -- dragging in a direction different from the one used to zoom in.
  
By default, <code>RestoreExtentOn = [zreClick, zreDragTopLeft, zreDragTopRight, zreDragBottomLeft]</code> which means
+
By default, <tt>RestoreExtentOn = [zreClick, zreDragTopLeft, zreDragTopRight, zreDragBottomLeft]</tt> which means
 
that the full extent is restored either by clicking or by drawing a rectangle in any direction except from top-left to bottom-right.
 
that the full extent is restored either by clicking or by drawing a rectangle in any direction except from top-left to bottom-right.
  
To get a behavior compatible with earlier versions of Delphi's TeeChart, specify <code>RestoreExtentOn = [zreDragTopLeft, zreDragTopRight, zreDragBottomLeft]</code>.
+
To get a behavior compatible with earlier versions of Delphi's TeeChart, specify <tt>RestoreExtentOn = [zreDragTopLeft, zreDragTopRight, zreDragBottomLeft]</tt>.
  
To get a behavior compatible with newer versions of TeeChart, specify <code>RestoreExtentOn = [zreDifferentDrag]</code>.
+
To get a behavior compatible with newer versions of TeeChart, specify <tt>RestoreExtentOn = [zreDifferentDrag]</tt>.
  
The enumerated property <code>RatioLimit</code> (<code>(zrlNone, zrlProportional, zrlFixedX, zrlFixedY</code>) lets you restrict zooming to one of the coordinates, or makes the zooming process keep the original proportions.
+
The enumerated property <tt>RatioLimit</tt> (<tt>(zrlNone, zrlProportional, zrlFixedX, zrlFixedY</tt>) lets you restrict zooming to one of the coordinates, or makes the zooming process keep the original proportions. In such a case of restricted zooming the zoom rectangle is drawn in the fixed direction across the entire chart when the property <tt>AdjustSelection</tt> is at its default value <tt>true</tt>; otherwise the zoom rectangle would be drawn between the mouse start and end points, like in the unrestricted case.
  
 
==== Zoom click tool ====
 
==== Zoom click tool ====
  
<code>TZoomClickTool</code> allows the user to zoom in or out by clicking on the chart with the mouse.
+
<tt>TZoomClickTool</tt> allows the user to zoom in or out by clicking on the chart with the mouse.
<code>ZoomFactor</code> is the scaling multiplier applied by the tool where factors below 1 represent "zoom out", and factors above represent "zoom in".
+
<tt>ZoomFactor</tt> is the scaling multiplier applied by the tool where factors below 1 represent "zoom out", and factors above represent "zoom in".
  
<code>ZoomRatio</code> allows to create a non-proportional zooming effect by specifiying the ratio of X to Y scale. In other words, the X zoom factor is given by the property <code>ZoomFactor</code>, the Y zoom factor is the product <code>ZoomFactor*ZoomRatio</code>.
+
<tt>ZoomRatio</tt> allows to create a non-proportional zooming effect by specifiying the ratio of X to Y scale. In other words, the X zoom factor is given by the property <tt>ZoomFactor</tt>, the Y zoom factor is the product <tt>ZoomFactor*ZoomRatio</tt>.
* In particular, to '''zoom only horizontally''', the Y zoom factor must be 1, i.e. <code>ZoomFactor*ZoomRatio = 1</code> or <code>ZoomRatio = 1/ZoomFactor</code>. For example, when your <code>ZoomFactor</code> for the X axis is 1.1, then <code>ZoomRatio</code> must be 1/1.1 = 0.909.
+
* In particular, to '''zoom only horizontally''', the Y zoom factor must be 1, i.e. <tt>ZoomFactor*ZoomRatio = 1</tt> or <tt>ZoomRatio = 1/ZoomFactor</tt>. For example, when your <tt>ZoomFactor</tt> for the X axis is 1.1, then <tt>ZoomRatio</tt> must be 1/1.1 = 0.909.
* Similarly, to '''zoom only vertically''', the X factor must be 1, i.e. <code>ZoomFactor = 1</code>, and you can use <code>ZoomRatio</code> alone to determine the Y zoom factor.
+
* Similarly, to '''zoom only vertically''', the X factor must be 1, i.e. <tt>ZoomFactor = 1</tt>, and you can use <tt>ZoomRatio</tt> alone to determine the Y zoom factor.
* And finally, in the normal case, when X and Y should zoom by the same ratio, keep <code>ZoomRatio</code> at 1 and determine the overall zoom factor by the <code>ZoomFactor</code> alone.
+
* And finally, in the normal case, when X and Y should zoom by the same ratio, keep <tt>ZoomRatio</tt> at 1 and determine the overall zoom factor by the <tt>ZoomFactor</tt> alone.
  
If <code>FixedPoint</code> is true, the location of the mouse click is used as a fixed point for zooming, otherwise the chart image center is used instead.
+
If <tt>FixedPoint</tt> is true, the location of the mouse click is used as a fixed point for zooming, otherwise the chart image center is used instead.
  
 
==== Zoom mouse-wheel tool ====
 
==== Zoom mouse-wheel tool ====
  
<code>TZoomMouseWheelTool</code> allows the user to zoom in and out with the mouse wheel.
+
<tt>TZoomMouseWheelTool</tt> allows the user to zoom in and out with the mouse wheel.
 
Its properties are identical to the [[#Zoom click tool|zoom click tool]].
 
Its properties are identical to the [[#Zoom click tool|zoom click tool]].
  
The chart is scaled by <code>ZoomFactor</code> when the user scrolls the mouse wheel up,
+
The chart is scaled by <tt>ZoomFactor</tt> when the user scrolls the mouse wheel up,
and by <code>1/ZoomFactor</code> when the user scrolls the mouse wheel down.
+
and by <tt>1/ZoomFactor</tt> when the user scrolls the mouse wheel down.
  
 
==== Pan drag tool ====
 
==== Pan drag tool ====
  
<code>TPanDragTool</code> allows the user to move the logical extent by dragging the mouse in the directions
+
<tt>TPanDragTool</tt> allows the user to move the logical extent by dragging the mouse in the directions
indicated by the <code>Directions</code> property.
+
indicated by the <tt>Directions</tt> property.
  
Use the <code>MinDragRadius</code> property to distinguish dragging from clicking.
+
Use the <tt>MinDragRadius</tt> property to distinguish dragging from clicking.
  
 
==== Pan click tool ====
 
==== Pan click tool ====
  
<code>TPanClickTool</code> allows the user to move the logical extent by clicking inside a range of  
+
<tt>TPanClickTool</tt> allows the user to move the logical extent by clicking inside a range of  
<code>Margins</code> pixels from the corresponding border of the chart image.
+
<tt>Margins</tt> pixels from the corresponding border of the chart image.
  
 
The panning offset is determined by the distance from the edge of the chart (the nearer to
 
The panning offset is determined by the distance from the edge of the chart (the nearer to
 
the edge, the greater).
 
the edge, the greater).
Setting <code>Interval</code> in milliseconds will allow to continue panning with the given
+
Setting <tt>Interval</tt> in milliseconds will allow to continue panning with the given
 
interval until the mouse button is up.
 
interval until the mouse button is up.
  
 
==== Pan mouse wheel tool ====
 
==== Pan mouse wheel tool ====
  
<code>TPanMouseWheelTool</code> allows the user to move the logical extent by scrolling the mouse wheel.
+
<tt>TPanMouseWheelTool</tt> allows the user to move the logical extent by scrolling the mouse wheel.
  
The extent is moved in <code>WheelUpDirection</code> when the wheel is scrolled up
+
The extent is moved in <tt>WheelUpDirection</tt> when the wheel is scrolled up
 
and in the opposite direction when the wheel is scrolled down.
 
and in the opposite direction when the wheel is scrolled down.
  
The movement speed is controlled by <code>Step</code> property.
+
The movement speed is controlled by <tt>Step</tt> property.
  
 
=== Data tools ===
 
=== Data tools ===
  
Data tools are linked to specific data series via the <code>AffectedSeries</code> property,
+
Data tools are linked to specific data series via the <tt>AffectedSeries</tt> property,
 
which is a string of comma-separated series indexes.
 
which is a string of comma-separated series indexes.
 
Note that indexes may change if you add or remove series.  
 
Note that indexes may change if you add or remove series.  
Having <code>AffectedSeries</code> empty means that the tools operate on every series in the chart.
+
Having <tt>AffectedSeries</tt> empty means that the tools operate on every series in the chart.
  
 
When a data tool is activated, it determines the nearest point of the affected series
 
When a data tool is activated, it determines the nearest point of the affected series
which is located inside of the <code>GrabRadius</code> (in pixels).  
+
which is located inside of the <tt>GrabRadius</tt> (in pixels).  
  
Using the set <code>Targets: TNearestPointTargets</code> it can be controlled which part of a complex series must be hit:
+
Using the set <tt>Targets: TNearestPointTargets</tt> it can be controlled which part of a complex series must be hit:
* <code>nptPoint</code>: The tool must hit the data point at (x, y).
+
* <tt>nptPoint</tt>: The tool must hit the data point at (x, y).
* <code>nptXList</code>: If the series' source has several x values the tool must hit any of the values in the XList.
+
* <tt>nptXList</tt>: If the series' source has several x values the tool must hit any of the values in the XList.
* <code>nptYList</code>: If the series' source has several y values the tool must hit any of the values in the YList.
+
* <tt>nptYList</tt>: If the series' source has several y values the tool must hit any of the values in the YList.
* <code>nptCustom</code>: Meant for special effects depending on the series. In case of a bar series, for example, the function GetNearestPoint is overridden to accept hits inside series bars if this option is set.
+
* <tt>nptCustom</tt>: Meant for special effects depending on the series. In case of a bar series, for example, the function <tt>GetNearestPoint</tt> is overridden to accept hits inside series bars if this option is set.
 
All options are on by default.
 
All options are on by default.
 
For further control, most series have the same set of Targets, named <tt>ToolTargets</tt>. An option must be included in the targets of both tool and series to be active. This way tools can be shared with series reacting differently on each option. See "barseriestools" demo as an example.
 
For further control, most series have the same set of Targets, named <tt>ToolTargets</tt>. An option must be included in the targets of both tool and series to be active. This way tools can be shared with series reacting differently on each option. See "barseriestools" demo as an example.
  
For large series, the efficiency can be improved by using a sorted source, a small <code>GrabRadius</code> and a <code>DistanceMode&lt;&gt;cdmOnlyY </code>.
+
For large series, the efficiency can be improved by using a sorted source, a small <tt>GrabRadius</tt> and a <tt>DistanceMode&lt;&gt;cdmOnlyY </tt>.
  
 
==== Data point drag tool ====
 
==== Data point drag tool ====
  
<code>TDataPointDragTool</code> allows the user to change data values by dragging the data point.
+
<tt>TDataPointDragTool</tt> allows the user to change data values by dragging the data point.
 
Requires the series' data source to be a [[#List sources|list source]].
 
Requires the series' data source to be a [[#List sources|list source]].
  
You can use the <code>OnDrag</code> and <code>OnDragStart</code> events to limit drag direction or grab area.
+
You can use the <tt>OnDrag</tt> and <tt>OnDragStart</tt> events to limit drag direction or grab area.
  
 
See "dragdrop" demo for an example.
 
See "dragdrop" demo for an example.
Line 949: Line 979:
 
==== Data point click tool ====
 
==== Data point click tool ====
  
<code>TDataPointClickTool</code> allows you to assign an <code>OnPointClick</code> event handler,
+
<tt>TDataPointClickTool</tt> allows you to assign an <tt>OnPointClick</tt> event handler,
 
which will be called when the user clicks on the data point.
 
which will be called when the user clicks on the data point.
  
 
==== Data point hint tool ====
 
==== Data point hint tool ====
  
<code>TDataPointHintTool</code> displays a hint when the user moves the mouse over the data point.
+
<tt>TDataPointHintTool</tt> displays a hint when the user moves the mouse over the data point.
The hint is either equal to the point label (if <code>UseDefaultHintText=true</code>) or
+
The hint is either equal to the point label (if <tt>UseDefaultHintText=true</tt>) or
determined by calling the <code>OnHint</code> event handler.
+
determined by calling the <tt>OnHint</tt> event handler.
  
 
By default, this tool displays a separate hint window, independent from the application hint.
 
By default, this tool displays a separate hint window, independent from the application hint.
To use a single hint window per application, you may set <code>UseApplicationHint=true</code>.
+
To use a single hint window per application, you may set <tt>UseApplicationHint=true</tt>.
  
 
Note that the application-level hint does not work in combination with modifier keys
 
Note that the application-level hint does not work in combination with modifier keys
 
and mouse buttons, so the hint is displayed only if no buttons are pressed
 
and mouse buttons, so the hint is displayed only if no buttons are pressed
(i.e. <code>Shift</code> property must be empty when <code>UseApplicationHint=true</code>).
+
(i.e. <tt>Shift</tt> property must be empty when <tt>UseApplicationHint=true</tt>).
  
 
==== Data point crosshair tool ====
 
==== Data point crosshair tool ====
  
<code>TDataPointCrosshairTool</code> displays a cross-hair centered on the data point. It replaces the "reticule" found in older versions of TAChart.
+
<tt>TDataPointCrosshairTool</tt> displays a cross-hair centered on the data point. It replaces the "reticule" found in older versions of TAChart.
  
 
==== Data point distance tool ====
 
==== Data point distance tool ====
  
<code>TDataPointDistanceTool</code> allows to measure and display a distance between two points on the chart.
+
<tt>TDataPointDistanceTool</tt> allows to measure and display a distance between two points on the chart.
 +
 
 +
=== Chart element tools ===
 +
 
 +
==== Axis click tool ====
 +
 
 +
This tool fires an event <tt>OnClick</tt> when the user clicks on an axis or its title. The event has the clicked axis and a set of <tt>TAxisHitTest</tt> elements as parameters:
 +
* <tt>ahtTitle</tt>: click on the axis title
 +
* <tt>ahtLine</tt>: click on the axis line (allowed tolerance defined by the tool's <tt>GrabRadius</tt> or the axis' <tt>TickLength</tt> and <tt>InnerTickLength</tt> whichever is greater).
 +
* <tt>ahtLabels</tt>: click into the label area of the axis. It is not distinguished whether a label is clicked or the empty space between the labels.
 +
* <tt>ahtAxisStart</tt>: the click on the line or label area occured in the first quarter of the axis length
 +
* <tt>ahtAxisCenter</tt>: the click on the line or label area occured in the center part (two quarters) of the axis length
 +
* <tt>ahtAxisEnd</tt>: the click on the line or label area occured in the last quarter of the axis length.
 +
 
 +
==== Title/footer click tool ====
 +
 
 +
An <tt>OnClick</tt> event is created when the user clicks on the title or footer of a chart. The event has the clicked title/footer as parameter.
 +
 
 +
==== Legend click tool ====
 +
Generates an <tt>OnClick</tt> event when a click on the chart's legend has occured. The event has the legend as a parameter.
  
 
=== User defined tool ===
 
=== User defined tool ===
  
To add your own tool, either inherit from <code>TUserDefinedTool</code> or use it directly,
+
To add your own tool, either inherit from <tt>TUserDefinedTool</tt> or use it directly,
 
assigning one or more On{After,Before}{KeyDown,KeyUp,MouseDown,MouseMove,MouseUp,MouseWheelDown,MouseWheelUp} event handlers.
 
assigning one or more On{After,Before}{KeyDown,KeyUp,MouseDown,MouseMove,MouseUp,MouseWheelDown,MouseWheelUp} event handlers.
  
Call the <code>Handled</code> method of the tool to indicate that no further processing of the event should be done.
+
Call the <tt>Handled</tt> method of the tool to indicate that no further processing of the event should be done.
  
 
== Decorative elements ==
 
== Decorative elements ==
Line 986: Line 1,035:
 
Chart title and footer are multi-line texts appearing above and below the chart
 
Chart title and footer are multi-line texts appearing above and below the chart
 
correspondingly.
 
correspondingly.
They support various rotations and alignments.
+
They support various rotations and alignments, as well as the boolean <tt>WordWrap</tt> property to wrap text wider than the chart into multiple lines.
  
 
==== HTML ====
 
==== HTML ====
Line 1,000: Line 1,049:
 
** The '''font size''' is controlled by the <tt>size</tt> attribute. It can take the values "x-small", "small", "medium", "large", "x-large", "xx-large" for font sizes 7, 10, 12, 14, 18, 24pt, respectively. Alternatively, the point or pixel size can be specified directly if "pt" or "px", respectively, is appended.
 
** The '''font size''' is controlled by the <tt>size</tt> attribute. It can take the values "x-small", "small", "medium", "large", "x-large", "xx-large" for font sizes 7, 10, 12, 14, 18, 24pt, respectively. Alternatively, the point or pixel size can be specified directly if "pt" or "px", respectively, is appended.
 
** ''Example:'' This code adds a two-line footer in which the 2nd line is in blue, 8-pt, underlined Times New Roman:  
 
** ''Example:'' This code adds a two-line footer in which the 2nd line is in blue, 8-pt, underlined Times New Roman:  
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang=pascal>
 
   Chart.Foot.Text.Clear;
 
   Chart.Foot.Text.Clear;
 
   Chart.Foot.Text.Add('Reference:');
 
   Chart.Foot.Text.Add('Reference:');
 
   Chart.Font.Text.Add('<font name="Times New Roman" size="8pt" color="blue"><u>www.freepascal.org/</u></font>');
 
   Chart.Font.Text.Add('<font name="Times New Roman" size="8pt" color="blue"><u>www.freepascal.org/</u></font>');
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
{{Warning|It is not recommended to switch font name and font size within the same line because TAChart drawers cannot exactly align the base line of characters in different fonts and font sizes}}
 
{{Warning|It is not recommended to switch font name and font size within the same line because TAChart drawers cannot exactly align the base line of characters in different fonts and font sizes}}
  
Line 1,012: Line 1,063:
  
 
Chart legend is a table with each item containing an icon and a text line.
 
Chart legend is a table with each item containing an icon and a text line.
Grid lines may be controlled by <code>GridHorizontal</code> and <code>GridVertical</code> properties.
+
Grid lines may be controlled by <tt>GridHorizontal</tt> and <tt>GridVertical</tt> properties.
  
 
Legend supports various alignments and can be located inside the chart or
 
Legend supports various alignments and can be located inside the chart or
 
on the sidebar. Legend can be displayed in two or more columns
 
on the sidebar. Legend can be displayed in two or more columns
by setting <code>ColumnCount</code> property.
+
by setting <tt>ColumnCount</tt> property.
Setting <code>ColumnCount</code> to a very large value effectively creates "horizontal" legend.
+
Setting <tt>ColumnCount</tt> to a very large value effectively creates "horizontal" legend.
  
 
Legend items are generated based on chart series which have both
 
Legend items are generated based on chart series which have both
<code>Active</code> and <code>ShowInLegend</code> set to true.
+
<tt>Active</tt> and <tt>ShowInLegend</tt> set to true.
Depending on <code>Legend.Multiplicity</code> series can produce a single
+
Depending on <tt>Legend.Multiplicity</tt> series can produce a single
 
item or one item per point.
 
item or one item per point.
  
 
Legend items can be grouped together under sub-headers.
 
Legend items can be grouped together under sub-headers.
Sub-headers are taken from <code>GroupNames</code> property,
+
Sub-headers are taken from <tt>GroupNames</tt> property,
and each series can use <code>Legend.GroupIndex</code> property
+
and each series can use <tt>Legend.GroupIndex</tt> property
 
to indicate its group.
 
to indicate its group.
  
 
Legend items are sorted as following:
 
Legend items are sorted as following:
* By group index, items without group (<code>GroupIndex=-1</code>) going first to avoid confusion with the last group.
+
 
* By <code>Order</code> property, items without explicit order (<code>Order=-1</code>) going last.
+
* By group index, items without group (<tt>GroupIndex=-1</tt>) going first to avoid confusion with the last group.
 +
* By <tt>Order</tt> property, items without explicit order (<tt>Order=-1</tt>) going last.
 
* By creation order of series.
 
* By creation order of series.
 
* For multiple items per series, by generation order (for standard series it is the order of points).
 
* For multiple items per series, by generation order (for standard series it is the order of points).
  
 
Sorted items are then added to the legend table in either by rows or by columns
 
Sorted items are then added to the legend table in either by rows or by columns
depending on the <code>ItemFillOrder</code> property.
+
depending on the <tt>ItemFillOrder</tt> property.
  
 
==== Legend item text ====
 
==== Legend item text ====
  
The text of a legend item is generated by the corresponding series based on the <code>Legend.Format</code> property.
+
The text of a legend item is generated by the corresponding series based on the <tt>Legend.Format</tt> property.
 
This property is used as a first argument for the
 
This property is used as a first argument for the
[http://www.freepascal.org/docs-html/rtl/sysutils/format.html <code>SysUtils.Format</code>] function,
+
[http://www.freepascal.org/docs-html/rtl/sysutils/format.html <tt>SysUtils.Format</tt>] function,
 
with the second argument containing following data items:
 
with the second argument containing following data items:
  
 
* For per-series multiplicity:
 
* For per-series multiplicity:
** 0: Series <code>Title</code>
+
** 0: Series <tt>Title</tt>
** 1: Series <code>Index</code>
+
** 1: Series <tt>Index</tt>
 
* For per-point multiplicity:
 
* For per-point multiplicity:
 
** Same as [[#Mark labels|mark labels]]
 
** Same as [[#Mark labels|mark labels]]
Line 1,055: Line 1,107:
 
==== User-defined legend items ====
 
==== User-defined legend items ====
  
Arbitrary legend items can be generated by overriding <code>OnCreate</code> and <code>OnDraw</code> events of series <code>Legend</code> property.
+
Arbitrary legend items can be generated by overriding <tt>OnCreate</tt> and <tt>OnDraw</tt> events of series <tt>Legend</tt> property.
  
 
Note that user-defined item count is controlled solely by
 
Note that user-defined item count is controlled solely by
<code>UserItemsCount</code> property and does not depend on <code>Multiplicity</code>. Also note that <code>GroupIndex</code> and <code>Order</code> properties are actually per-item, so you can totally override entire legend from a single (perhaps fictive) series.
+
<codettUserItemsCount</tt> property and does not depend on <tt>Multiplicity</tt>. Also note that <tt>GroupIndex</tt> and <tt>Order</tt> properties are actually per-item, so you can totally override entire legend from a single (perhaps fictive) series.
  
 
=== Arrows ===
 
=== Arrows ===
  
 
Arrowheads can be drawn at the end of axis lines, constant lines, mark links, etc.
 
Arrowheads can be drawn at the end of axis lines, constant lines, mark links, etc.
It is controlled by <code>TChartAxis.Arrow</code>, <code>TConstantLine.Arrow</code>, <code>TChartMarks.Arrow</code> correspondingly.
+
It is controlled by <tt>TChartAxis.Arrow</tt>, <tt>TConstantLine.Arrow</tt>, <tt>TChartMarks.Arrow</tt> correspondingly.
  
Arrowhead shape is determined by <code>Width</code>, <code>Length</code> and <code>BaseLength</code> properties,
+
Arrowhead shape is determined by <tt>Width</tt>, <tt>Length</tt> and <tt>BaseLength</tt> properties,
 
for example:
 
for example:
* Thin wedge: <code>BaseLength = 0</code>
+
* Thin wedge: <tt>BaseLength = 0</tt>
* Triangle: <code>BaseLength = Length</code>
+
* Triangle: <tt>BaseLength = Length</tt>
* Rhombus: <code>BaseLength = 2 * Length</code>
+
* Rhombus: <tt>BaseLength = 2 * Length</tt>
* Inverted Triangle: <code>BaseLength > 0</code>, <code>Length = 0</code>
+
* Inverted Triangle: <tt>BaseLength > 0</tt>, <tt>Length = 0</tt>
This image shows these arrows created for <code>Length=10</code> and <code>Width=5</code>.[[File:TAChart_Arrows.png]]<br clear="all">
+
This image shows these arrows created for <tt>Length=10</tt> and <tt>Width=5</tt>.[[File:TAChart_Arrows.png]]<br clear="all">
  
 
=== Transparency ===
 
=== Transparency ===
  
<code>Transparency</code> property of the series represents a level of transparency from 0 (fully opaque) to 255 (fully transparent -- i.e. invisible).
+
<tt>Transparency</tt> property of the series represents a level of transparency from 0 (fully opaque) to 255 (fully transparent -- i.e. invisible).
  
 
'''Compatibility note''': [[#FPVectorial drawer|FPVectorial]] and [[#TFPCanvas drawer|TFPCanvas]] drawers currently do not support transparency because of limitations of the underlying libraries. [[#Printer drawer|Printer]] and [[#WMF drawer|WMF]] drawers can not support transparency in principle.
 
'''Compatibility note''': [[#FPVectorial drawer|FPVectorial]] and [[#TFPCanvas drawer|TFPCanvas]] drawers currently do not support transparency because of limitations of the underlying libraries. [[#Printer drawer|Printer]] and [[#WMF drawer|WMF]] drawers can not support transparency in principle.
Line 1,083: Line 1,135:
 
=== ChartStyles ===
 
=== ChartStyles ===
  
<code>TChartStyles</code> can be employed to control the appearance of the "layers" of area, line, and bar series with multiple y values. They can also be used to colorize the regions between axis ticks in a banded way.
+
[[File:tchartstyles_200.png|left]]<tt>TChartStyles</tt> can be employed to control the appearance of the "layers" of area, line, and bar series with multiple y values. They can also be used to colorize the regions between axis ticks in a banded way.
 +
<br/>
 +
<br/>
  
 
== Marks ==
 
== Marks ==
Line 1,095: Line 1,149:
 
=== Mark labels ===
 
=== Mark labels ===
  
The label text can be enclosed in a box, controlled by <code>LabelBrush</code> and <code>Frame</code> properties.
+
The label text can be enclosed in a box, controlled by <tt>LabelBrush</tt> and <tt>Frame</tt> properties.
The text itself is created based on the data source items, with the help of <code>Format</code> property.
+
The text itself is created based on the data source items, with the help of <tt>Format</tt> property.
 
This property is used as a first argument for the
 
This property is used as a first argument for the
[http://www.freepascal.org/docs-html/rtl/sysutils/format.html <code>SysUtils.Format</code>] function,
+
[http://www.freepascal.org/docs-html/rtl/sysutils/format.html <tt>SysUtils.Format</tt>] function,
 
with the second argument containing following data items:
 
with the second argument containing following data items:
  
Line 1,110: Line 1,164:
 
Note that not all sources supply all the items above.
 
Note that not all sources supply all the items above.
  
Some pre-defined formats can be set via the <code>Style</code> property.
+
Some pre-defined formats can be set via the <tt>Style</tt> property.
  
 
If the source is [[#Multi-valued_sources|mutli-valued]],
 
If the source is [[#Multi-valued_sources|mutli-valued]],
<code>YIndex</code> property determines which Y value is used.
+
<tt>YIndex</tt> property determines which Y value is used.
If <code>YIndex = -1</code>, a separate label is displayed for each Y value, which is useful for stacked series.
+
If <tt>YIndex = -1</tt>, a separate label is displayed for each Y value, which is useful for stacked series.
  
The text is rendered using the <code>LabelFont</code>. Note in particular that TAChart supports arbitrary
+
The text is rendered using the <tt>LabelFont</tt>. Note in particular that TAChart supports arbitrary
font <code>Orientation</code>.
+
font <tt>Orientation</tt>.
  
 
Mark labels are usually included in [[#Margins|margins]] calculation to guarantee that all labels fit in the viewport.
 
Mark labels are usually included in [[#Margins|margins]] calculation to guarantee that all labels fit in the viewport.
This behavior can be turned off by setting <code>AutoMargins</code> property to <code>false</code>.
+
This behavior can be turned off by setting <tt>AutoMargins</tt> property to <tt>false</tt>.
  
 
==== Multi-line marks ====
 
==== Multi-line marks ====
  
If the mark text contains [http://www.freepascal.org/docs-html/rtl/system/lineending.html <code>LineEnding</code>] character sequence, it is split into several lines.
+
If the mark text contains [http://www.freepascal.org/docs-html/rtl/system/lineending.html <tt>LineEnding</tt>] character sequence, it is split into several lines.
Lines of different length are aligned according to <code>Alignment</code> property.
+
Lines of different length are aligned according to <tt>Alignment</tt> property.
  
 
==== HTML codes in marks ====
 
==== HTML codes in marks ====
Line 1,135: Line 1,189:
 
The mark position relative to the marked point is determined by the marks owner (series or axis).
 
The mark position relative to the marked point is determined by the marks owner (series or axis).
  
Common mark properties include <code>Distance</code>, which measures the distance
+
Common mark properties include <tt>Distance</tt>, which measures the distance
from the origin point to the attachment point in image units, and <code>Attachment</code>, which controls
+
from the origin point to the attachment point in image units, and <tt>Attachment</tt>, which controls
 
whether the attachment point is considered to be in the center or at the edge of the label box.
 
whether the attachment point is considered to be in the center or at the edge of the label box.
  
Additionally, [[#Basic_series|basic chart series]] have a property <code>MarkPositions</code> specifying
+
Additionally, [[#Basic_series|basic chart series]] have a property <tt>MarkPositions</tt> specifying
 
the direction of labels' offsets relative to series data points as following:
 
the direction of labels' offsets relative to series data points as following:
* lmpOutside -- away from the center of the data points cloud; for [[#Bar_series|TBarSeries]] and [[#Area_series|TAreaSeries]] it has a special meaning: away from the ZeroLevel defined for this series.
+
* <tt>lmpOutside</tt> -- away from the center of the data points cloud; for [[#Bar_series|TBarSeries]] and [[#Area_series|TAreaSeries]] it has a special meaning: away from the ZeroLevel defined for this series.
* lmpPositive -- positive direction of series' Y axis
+
* <tt>lmpPositive</tt> -- positive direction of series' Y axis
* lmpNegative -- negative direction of series' Y axis
+
* <tt>lmpNegative</tt> -- negative direction of series' Y axis
* lmpInside -- towards the center of the data points cloud; for [[#Bar_series|TBarSeries]] and [[#Area_series|TAreaSeries]]: towards the ZeroLevel
+
* <tt>lmpInside</tt> -- towards the center of the data points cloud; for [[#Bar_series|TBarSeries]] and [[#Area_series|TAreaSeries]]: towards the ZeroLevel
  
In Lazarus 2.0+, [[#Bar_series|TBarSeries]] and [[#Area_series|TAreaSeries]] have an additional property <code>MarkPositionCentered</code> which allows to center the marks origins between data points and zero level. In order to place marks exactly at the center of the bars of a BarSeries or at the center of the drop line of an AreaSeries, the following properties must be changed additionally: <code>Marks.Distance = 0</code>, and <code>Marks.Attachment = maCenter</code>.
+
In Lazarus 2.0+, [[#Bar_series|TBarSeries]] and [[#Area_series|TAreaSeries]] have an additional property <tt>MarkPositionCentered</tt> which allows to center the marks origins between data points and zero level. In order to place marks exactly at the center of the bars of a BarSeries or at the center of the drop line of an AreaSeries, the following properties must be changed additionally: <tt>Marks.Distance = 0</tt>, and <tt>Marks.Attachment = maCenter</tt>.
  
 
=== Rotation of marks ===
 
=== Rotation of marks ===
Line 1,153: Line 1,207:
  
 
The rotation normally occurs with respect to the center of the label. Axis and series marks additionally have a property <tt>RotationCenter</tt> to shift the center of rotation to an edge of the text:
 
The rotation normally occurs with respect to the center of the label. Axis and series marks additionally have a property <tt>RotationCenter</tt> to shift the center of rotation to an edge of the text:
* raCenter -- default setting, i.e. rotation occurs around the text center
+
* <tt>raCenter</tt> -- default setting, i.e. rotation occurs around the text center
* raLeft -- the rotation center is at the left edge of the label.
+
* <tt>raLeft</tt> -- the rotation center is at the left edge of the label.
* raRight -- the rotation center is at the right edge of the text.
+
* <tt>raRight</tt> -- the rotation center is at the right edge of the text.
* raEdge -- ignored in case of series marks (will be replaced by raLeft). But in case of axis marks the center of rotation is automatically moved to the text start or end in order to avoid rotation of the label into the chart.
+
* <tt>raEdge</tt> -- ignored in case of series marks (will be replaced by raLeft). But in case of axis marks the center of rotation is automatically moved to the text start or end in order to avoid rotation of the label into the chart.
  
 
== Drawers ==
 
== Drawers ==
  
For low-level drawing routines, TAChart uses special set of classes implementing <code>IChartDrawer</code> interface.
+
For low-level drawing routines, TAChart uses special set of classes implementing <tt>IChartDrawer</tt> interface.
 
This allows such features as printing charts and exporting them to SVG format.
 
This allows such features as printing charts and exporting them to SVG format.
  
Line 1,167: Line 1,221:
 
=== TCanvas drawer ===
 
=== TCanvas drawer ===
  
<code>TCanvasDrawer</code> is the default drawer used to display chart on TCanvas.
+
<tt>TCanvasDrawer</tt> is the default drawer used to display chart on TCanvas.
 
This includes screen and various raster image formats.
 
This includes screen and various raster image formats.
 
The image produced by this drawer is used as a reference when developing and debugging other back-ends.
 
The image produced by this drawer is used as a reference when developing and debugging other back-ends.
Line 1,173: Line 1,227:
 
=== TFPCanvas drawer ===
 
=== TFPCanvas drawer ===
  
<code>TFPCanvasDrawer</code> is similar to [[#TCanvas drawer|TCanvas drawer]], but based on <code>TFPCanvas</code>  
+
<tt>TFPCanvasDrawer</tt> is similar to [[#TCanvas drawer|TCanvas drawer]], but based on <tt>TFPCanvas</tt>  
 
(which is a <code>TCanvas</code> analog implemented in the FCL instead of the LCL).
 
(which is a <code>TCanvas</code> analog implemented in the FCL instead of the LCL).
  
 
See the "nogui" demo for an example.
 
See the "nogui" demo for an example.
  
Although <code>TFPCanvas</code> and, correspondingly, <code>TFPCanvasDrawer</code> have a restricted implementation
+
Although <tt>TFPCanvas</tt> and, correspondingly, <tt>TFPCanvasDrawer</tt> have a restricted implementation
 
of some TAChart features, their important advantage is the possibility they offer of compiling an application with the nogui widgetset.
 
of some TAChart features, their important advantage is the possibility they offer of compiling an application with the nogui widgetset.
 
This is particularly useful for Web applications, which can then generate raster chart images without any further graphic dependency, or a need to install X/Gtk/Qt on the server.
 
This is particularly useful for Web applications, which can then generate raster chart images without any further graphic dependency, or a need to install X/Gtk/Qt on the server.
Line 1,184: Line 1,238:
 
=== SVG drawer ===
 
=== SVG drawer ===
  
<code>TSVGDrawer</code> produces text stream with the image of the chart in [[Wikipedia:SVG|SVG]] format.
+
<tt>TSVGDrawer</tt> produces text stream with the image of the chart in [[Wikipedia:SVG|SVG]] format.
 
Similarly to [[#TFPCanvas drawer|TFPCanvas drawer]], it is independent of LCL and can be used in Web applications
 
Similarly to [[#TFPCanvas drawer|TFPCanvas drawer]], it is independent of LCL and can be used in Web applications
 
to generate vector charts in nogui widgetset.
 
to generate vector charts in nogui widgetset.
Line 1,194: Line 1,248:
 
Note that due to the nature of SVG, there is no way to measure font dimensions, so they are approximated crudely.
 
Note that due to the nature of SVG, there is no way to measure font dimensions, so they are approximated crudely.
 
This may result in problems like label text not fitting in the mark rectangle, especially in browsers
 
This may result in problems like label text not fitting in the mark rectangle, especially in browsers
like Firefox that do not support <code>textLength</code> attribute.
+
like Firefox that do not support <tt>textLength</tt> attribute.
  
 
=== OpenGL drawer ===
 
=== OpenGL drawer ===
  
<code>TOpenGLDrawer</code> draws chart on the current [[Wikipedia:OpenGL|OpenGL]] context.
+
<tt>TOpenGLDrawer</tt> draws chart on the current [[Wikipedia:OpenGL|OpenGL]] context.
 
It is suitable to be used in games and other OpenGL-only applications.
 
It is suitable to be used in games and other OpenGL-only applications.
  
Line 1,204: Line 1,258:
 
See "opengl" demo for an example.
 
See "opengl" demo for an example.
  
Note that, like in OpenGL itself, <code>TOpenGLDrawer</code> font support is extremely limited.
+
Note that, like in OpenGL itself, <tt>TOpenGLDrawer</tt> font support is extremely limited.
  
 
=== Printer drawer ===
 
=== Printer drawer ===
  
<code>TPrinterDrawer</code> draws chart on the printer canvas. It does not flush the page.
+
<tt>TPrinterDrawer</tt> draws chart on the printer canvas. It does not flush the page.
  
Although printer canvas is a descendant of <code>TCanvas</code>, and so printing can be done
+
Although printer canvas is a descendant of <tt>TCanvas</tt>, and so printing can be done
using the [[#TCanvas drawer|default drawer]], <code>TPrinterDrawer</code> does proper re-scaling
+
using the [[#TCanvas drawer|default drawer]], <tt>TPrinterDrawer</tt> does proper re-scaling
 
of image coordinates according to printer vs screen DPI.
 
of image coordinates according to printer vs screen DPI.
  
Line 1,222: Line 1,276:
 
=== AggPas drawer ===
 
=== AggPas drawer ===
  
<code>TAggPasDrawer</code> draws chart using [http://www.crossgl.com/aggpas AggPas library].
+
<tt>TAggPasDrawer</tt> draws chart using [http://www.crossgl.com/aggpas AggPas library].
  
 
AggPas offers high-speed antialiased drawing and is included in Lazarus sources.
 
AggPas offers high-speed antialiased drawing and is included in Lazarus sources.
Line 1,231: Line 1,285:
 
=== BGRABitmap drawer ===
 
=== BGRABitmap drawer ===
  
<code>TBGRADrawer</code> draws chart using [[BGRABitmap]] library.
+
<tt>TBGRADrawer</tt> draws chart using [[BGRABitmap]] library.
  
 
BGRABitmap is recently created and actively developed graphics library,
 
BGRABitmap is recently created and actively developed graphics library,
Line 1,243: Line 1,297:
 
=== FPVectorial drawer ===
 
=== FPVectorial drawer ===
  
<code>TFPVectorialDrawer</code> draws chart using [[fpvectorial]] library.
+
<tt>TFPVectorialDrawer</tt> draws chart using [[fpvectorial]] library.
 
FPVectorial offers exporting to various vector formats,
 
FPVectorial offers exporting to various vector formats,
 
including SVG, PDF, CorelDraw and even instructions for metal cutting machines.
 
including SVG, PDF, CorelDraw and even instructions for metal cutting machines.
Line 1,249: Line 1,303:
 
It currently has some limitations in TAChart support, but is actively developed.
 
It currently has some limitations in TAChart support, but is actively developed.
  
Note that this drawer is located in a separate <code>TAChartFPVectorial</code> package,
+
Note that this drawer is located in a separate <tt>TAChartFPVectorial</tt> package,
which depends on <code>fpvectorialpkg</code> package.
+
which depends on <tt>fpvectorialpkg</tt> package.
  
 
=== WMF drawer ===
 
=== WMF drawer ===
  
<code>TWindowsMetafileDrawer</code> draws chart into a [[Wikipedia:Windows Metafile|Windows Metafile]].
+
<tt>TWindowsMetafileDrawer</tt> draws chart into a [[Wikipedia:Windows Metafile|Windows Metafile]].
  
 
It uses WinAPI directly, and so will only work on Windows.
 
It uses WinAPI directly, and so will only work on Windows.
Line 1,270: Line 1,324:
 
=== Scroll bars ===
 
=== Scroll bars ===
  
<code>TChartNavScrollBar</code> is a <code>TCustomScrollBar</code> descendant with additional <code>Chart</code> property
+
[[File:tchartnavscrollbar_200.png|left]]<tt>TChartNavScrollBar</tt> is a <tt>TCustomScrollBar</tt> descendant with additional <tt>Chart</tt> property referencing the chart. <tt>TChartNavScrollBar</tt> synchronizes its position with chart extent in both directions. If the logical extent is equal to or larger than the full extent, navigation scroll bar does nothing.
referencing the chart. <code>TChartNavScrollBar</code> synchronizes its position with chart extent in both directions.
+
 
If the logical extent is equal to or larger than the full extent, navigation scroll bar does nothing.
+
Setting <tt>AutoPageSize = true</tt> lets <tt>TChartNavScrollBar</tt> pick a page size proportional to the logical extent.
  
Setting <code>AutoPageSize = true</code> lets <code>TChartNavScrollBar</code> to pick page size proportional to the logical extent.
+
Note that <tt>Min</tt> and <tt>Max</tt> properties are ''not'' changed automatically. It is recommended to set <tt>Min = 0</tt> and <tt>Max</tt> to some fairly large integer value to avoid rounding issues. Also note that <tt>TChartNavScrollBar</tt> does not automatically align or attach itself to a chart, so it can be arbitrarily positioned on the form.
  
Note that <code>Min</code> and <code>Max</code> properties are ''not'' changed automatically.
+
=== Navigation panel ===
It is recommended to set <code>Min = 0</code> and <code>Max</code> to some fairly large integer value to avoid rounding issues.
 
  
Also note that <code>TChartNavScrollBar</code> does not automatically align or attach itself to a chart,
+
[[File:tchartnavpanel_200.png|left]]<tt>TChartNavPanel</tt> component displays logical and full extent of an assigned chart as differently colored rectangles, allowing user to drag the logical extent rectangle if <tt>AllowDragNavigation = true</tt>.
so it can be arbitrarily positioned on the form.
 
  
=== Navigation panel ===
+
If <tt>MiniMap = true</tt>, the panel additionally displays the chart series.
 +
 
 +
<tt>TChartNavPanel</tt> can have arbitrary size, but it is recommended to keep height to width proportion the same as in the assigned chart. Setting <tt>Proportional = true</tt> will enforce the same proportions even if the above condition is not met, at the cost of some wasted space on the panel.
 +
 
 +
=== Live View ===
 +
 
 +
[[File:tchartliveview_200.png|left]] Although not a navigation tool directly, <tt>TChartLiveView</tt> is related to navigation. In the case of a long array of incoming data it provides an easy way to display a viewport with only the most recent data while older data are flowing to the left out of the viewport.
 +
 
 +
The viewport is updated whenever the full extent of the associated chart changes. However, when property <tt>Active</tt> is set to <tt>false</tt> the viewport is fixed -- this is a setting which allows the user to review older data, or change the extent while still new data are coming at the same time.
  
<code>TChartNavPanel</code> component displays logical and full extent of an assigned chart as differently colored rectangles,
+
Property <tt>ViewportSize</tt> defines the width of the visible viewport, in graph units. If set to 0, the width of the current <tt>LogicalExtent</tt> is used instead.  
allowing user to drag the logical extent rectangle if <code>AllowDragNavigation = true</code>.
 
  
If <code>MiniMap = true</code>, the panel additionally displays the chart series.
+
The enumerated property <tt>ExtentY = (lveAuto, lveFull, lveLogical)</tt>, finally, determines the height of the viewport:
 +
* <tt>lveAuto</tt> adjusts the height to the visible data range automatically. This works also when the chart contains several y axes. When a <tt>Range</tt> is defined for an axis (i.e. by setting <tt>axis.Range.Min</tt>/<tt>axis.Range.UseMin</tt> and/or <tt>axis.Range.Max</tt>/<tt>axis.Range.UseMax</tt>) the component keeps it as long as series values are within this range.
 +
* <tt>lveFull</tt> freezes the height to the full extent of the chart.
 +
* <tt>lveLogical</tt> freezes the height to the logical extent of the chart.
  
<code>TChartNavPanel</code> can have arbitrary size, but it is recommended to keep height to width proportion the same as in the assigned chart. Setting <code>Proportional = true</code> will enforce the same proportions even if the above condition is not met, at the cost of some wasted space on the panel.
+
The methods <tt>StoreAxisRange</tt> and <tt>RestoreAxisRange</tt> are used for internal purposes because the component may change the <tt>Range</tt> parameters of an axis. Be carefull when calling these methods because they may disrupt operation of the live view if not done properly.
  
 
== Additional components ==
 
== Additional components ==
  
 
=== Legend panel ===
 
=== Legend panel ===
<code>TChartLegendPanel</code> provides a legend which can be placed anywhere on the form. The legend is taken from the chart with is assigned to the property <code>Chart</code> of the LegendPanel. The chart’s own legend should be turned off.
+
<tt>TChartLegendPanel</tt> provides a legend which can be placed anywhere on the form. The legend is taken from the chart with is assigned to the property <tt>Chart</tt> of the LegendPanel. The chart’s own legend should be turned off.
  
 
=== Chart listbox ===
 
=== Chart listbox ===
<code>TChartListbox</code> is a versatile legend replacement which displays an icon and the series title for each series of the chart attached to the property <code>Chart</code> of the listbox. But in addition to the standard legend, it also has checkboxes for each series. Unchecking a checkbox hides the associated series, checking it shows the series again. The listbox listens to changes in the associated chart and updates automatically.
+
<tt>TChartListbox</tt> is a versatile legend replacement which displays an icon and the series title for each series of the chart attached to the property <tt>Chart</tt> of the listbox. But in addition to the standard legend, it also has checkboxes for each series. Unchecking a checkbox hides the associated series, checking it shows the series again. The listbox listens to changes in the associated chart and updates automatically.
  
The property <code>CheckStyle</code> can be used to switch the listbox from a checkbox-like behavior (<code>cbsCheckbox</code>, an arbitrary combination of series can be checked) to a radiobutton-like behavior (<code>cbsRadioButton</code>, only a single series can be checked). Depending on <code>CheckStyle</code> either a radiobutton or a checkbox state icon is displayed for each series.
+
The property <tt>CheckStyle</tt> can be used to switch the listbox from a checkbox-like behavior (<tt>cbsCheckbox</tt>, an arbitrary combination of series can be checked) to a radiobutton-like behavior (<tt>cbsRadioButton</tt>, only a single series can be checked). Depending on <tt>CheckStyle</tt> either a radiobutton or a checkbox state icon is displayed for each series.
  
Events are fired when the checkbox/radiobutton or the series title are clicked (<code>OnCheckboxClick</code> or <code>OnItemClick</code>, respectively), or when the series icon is double-clicked (<code>OnSeriesIconDblClick</code>). The latter event is thought to open a dialog for changing the series color, pointer style, series title etc.
+
Events are fired when the checkbox/radiobutton or the series title are clicked (<tt>OnCheckboxClick</tt> or <tt>OnItemClick</tt>, respectively), or when the series icon is double-clicked (<tt>OnSeriesIconDblClick</tt>). The latter event is thought to open a dialog for changing the series color, pointer style, series title etc.
  
The listbox items are collected in a different way than for a conventional legend. The populating process ignores the series property <code>Legend.Visible</code> which controls whether the series is to be shown in the legend or not. Instead of it, there is an event <code>OnAddSeries</code> in which the <code>var</code> parameter <code>Skip</code> should be set to <code>true</code> if the series passed as another argument should be excluded from the listbox. Every series is listed only with a single item, i.e. the series’ <code>Multiplicity</code> is ignored as well. Moveover, grouping of items is not supported either.
+
The listbox items are collected in a different way than for a conventional legend. The populating process ignores the series property <tt>Legend.Visible</tt> which controls whether the series is to be shown in the legend or not. Instead of it, there is an event <tt>OnAddSeries</tt> in which the <tt>var</tt> parameter <tt>Skip</tt> should be set to <tt>true</tt> if the series passed as another argument should be excluded from the listbox. Every series is listed only with a single item, i.e. the series’ <tt>Multiplicity</tt> is ignored as well. Moveover, grouping of items is not supported either.
 +
 
 +
The order of listbox items is normally given by the order of series items in the chart's legend and thus depend on the chart's <tt>Legend.Inverted</tt> and the series' <tt>Legend.Order</tt> parameters. Moreover, items can be rearranged independently of the legend by calling the <tt>ExchangeSeries(AIndex1, AIndex2)</tt> method with the listbox indices as parameters. There is also a method <tt>Sort</tt> to sort the listbox by series titles (the sort order can be inverted by setting its optional <tt>Descending</tt> parameter, or <tt>Chart.Legend.Inverted</tt> to <tt>true</tt>. Note that the <tt>Sort</tt> method works only on the series having the default <tt>Legend.Order</tt> (-1).
  
 
=== Chart image list ===
 
=== Chart image list ===
Line 1,314: Line 1,378:
  
 
=== Chart combobox ===
 
=== Chart combobox ===
The <tt>TChartCombobox</tt> is an extended combobox. Depending on the property <code>Mode</code> (<code>ccmPointerStyle</code>, </code>ccmPenStyle</code>, <code>ccmPenWidth</code>, <code>ccmBrushStyle</code>) it is populated with names and corresponding icons for pointer style, pen style, pen width or brush style selection. Therefore, it is useful for gui elements in which the user can modify the appearance of series and other chart objects.  
+
The <tt>TChartCombobox</tt> is an extended combobox. Depending on the property <tt>Mode</tt> (<tt>ccmPointerStyle</tt>, <tt>ccmPenStyle</tt>, <tt>ccmPenWidth</tt>, <tt>ccmBrushStyle</tt>) it is populated with names and corresponding icons for pointer style, pen style, pen width or brush style selection. Therefore, it is useful for gui elements in which the user can modify the appearance of series and other chart objects.  
  
The combobox is not linked to a particular chart. Use the <code>OnChange</code> event to transfer the modified property to the series.
+
The combobox is not linked to a particular chart. Use the <tt>OnChange</tt> event to transfer the modified property to the series.
  
 
== TeeChart compatibility ==
 
== TeeChart compatibility ==
Line 1,331: Line 1,395:
  
 
To assist porting of TeeChart code to the TAChart, you can use
 
To assist porting of TeeChart code to the TAChart, you can use
<code>TAChartTeeChart</code> unit. It contains class helpers adding
+
<tt>TAChartTeeChart</tt> unit. It contains class helpers adding
 
or emulating some TeeChart-specific properties and methods.
 
or emulating some TeeChart-specific properties and methods.
  
Line 1,349: Line 1,413:
  
 
There also exists an ordering among various chart elements:
 
There also exists an ordering among various chart elements:
# Background (using <code>TChart.Color</code> property).
+
# Background (using <tt>TChart.Color</tt> property).
# Back-wall (using <code>TChart.BackColor</code> property).
+
# Back-wall (using <tt>TChart.BackColor</tt> property).
# [[#Series|Series]] and axes according to <code>ZPosition</code> property. For each series and axis, graphic elements are drawn before [[#Marks|marks]]. Note that this protects marks against hiding by the axis/series they belong to, but not by other axes/series.
+
# [[#Series|Series]] and axes according to <tt>ZPosition</tt> property. For each series and axis, graphic elements are drawn before [[#Marks|marks]]. Note that this protects marks against hiding by the axis/series they belong to, but not by other axes/series.
 
# [[#Legend|Legend]].
 
# [[#Legend|Legend]].
 
# [[#Tools|Tools]].
 
# [[#Tools|Tools]].
  
Note that <code>ZPosition</code> works for both 2-D and 3-D charts, so you can overlay series and axes in arbitrary order.
+
Note that <tt>ZPosition</tt> works for both 2-D and 3-D charts, so you can overlay series and axes in arbitrary order.
  
 
=== Coding style ===
 
=== Coding style ===
Line 1,429: Line 1,493:
 
* Use ''with'' carefully, and only where its use significantly saves code size and in the minimal possible range.
 
* Use ''with'' carefully, and only where its use significantly saves code size and in the minimal possible range.
 
* Limit all procedures to 50-60 lines, and use nested procedures liberally.
 
* Limit all procedures to 50-60 lines, and use nested procedures liberally.
 
[[Category:Components]]
 
[[Category:Graphics]]
 
[[Category:TAChart]]
 

Revision as of 16:21, 2 August 2021

English (en) русский (ru) українська (uk) 中文(中国大陆)‎ (zh_CN)

Overview

TAChart is a package for drawing graphs, charts and other diagrams. It is comparable in features, but not specifically compatible, with Delphi's TeeChart package. One substantial difference is that some features (e.g. data sources and axis transformations) are implemented via separate components instead of through simple chart properties. This design gives increased flexibility and opportunity for code re-use, but at the cost of a slightly more complex API.

This document provides a concise but comprehensive overview of TAChart concepts, features and components. For a step-by-step introduction, see TAChart Tutorial: Getting started and other tutorials.

The documentation describes the TAChart package as found in the latest development version of Lazarus. Some features may not yet be available in the official Lazarus release version. We recommend that you use this latest document version because it has corrected and improved older descriptions in previous versions, as well as the fact that it includes details about the newest features.

Nevertheless, you can look at the the old version of this document to see the state of the documentation around the time of the Lazarus 1.0 release.

Series

series hierarchy-1.png

Series are the central part of TAChart. Their hierarchy is illustrated in the figure. The series inheriting from TCustomChartSeries represents data taken from a ChartSource in graphical ways, such as lines or bars; the other series get their data in another way.

Constant line series

This is the simplest series type, representing an "infinite" vertical or horizontal line. It can be used as a "central axis" in function graphs, or as a draggable marker line.

Also, by setting Active=true, Pen.Style=psClear and UseBounds=true and an appropriate AxisIndexX, it becomes an "axis extender", making sure that a given Position will always be included in the axis range.

Basic series

Basic series are most often used, and include line, bar and area series. All basic series can be "stacked" by using multi-valued source. Also, all basic series fully support rotation and 3-D drawing.

Line series

TLineSeries can be used to draw a given set of points, optionally marking each data point with a symbol and/or connecting the data points with a line. The color of the line series is defined by the SeriesColor.

ColorEach gives control over coloring inidividual data points and the adjacent line segments (the data point color is provided by the chart source):

  • ceNone -- no individual coloring, even if colors are assigend to the chart data item.
  • cePoint -- colorize only the data point symbol, not the line segment.
  • ceLineAfter -- apply the data point color to the line segment following the data point
  • ceLineBefore -- apply the data point color to the segment before the data point
  • cePointAndLineAfter, cePointAndLineBefore -- like before, but colorizes also the data point symbol.

You can get a "stepped" look by setting LineType property to ltStepXY or ltStepYX.

Using a multi-valued data source TLineSeries can handle several y values for each x value. If Stacked is set to true then the individual y values are plotted in a stacked way, i.e., the second y value is added to the first one, the third y value to the second value etc. Note, however, unlike stacked bar or area series it may not be clear that the data values are stacked, and therefore stacking is usually not recommended for a line series.

Fast lines

Some charting packages include a special "fast line" series to quickly draw line series from extremely large datasets (10000+ points). TAChart, by contrast, contains an optimized fast path inside standard line series code, which achieves comparable drawing speed. A line series will be drawn very fast if all of the following are true:

  • There are no marks.
  • There are no pointers.
  • LineType is not ltFromOrigin.

Some operating systems/widgetsets may additionally require that LinePen.Style=psSolid and LinePen.Width=1.

Additional speedups will be available if Source.Sorted=true.

You can measure line speed drawing on your platform with the "line" demo.

Point series

TLineSeries can be drawn as a "point series" showing only symbols at the position of the data points and hiding the connecting lines by setting ShowPoints to True and LineType to ltNone. Note that the SeriesColor applies only to the connecting lines; to specify the color of the points change the Pointer.Brush.Color for the fill and/or Pointer.Pen.Color for the border line color. The Pointer property also gives access to the shape (circle, box, etc) of the symbols (Style).

Bar series

TBarSeries represents data as a set or bars, extending from ZeroLevel to data points.

You can control bar width with BarWidthPercent property. Note that the it is measured relative to the neighboring bars. If the X values are not equidistant, bars will have varying width. To prevent that, set BarWidthStyle=bwPercentMin.

You can draw multiple bar series side-by-side by using BarOffsetPercent property.

Use multiple y values to create stacked bar series (Stacked = true). Beginning with Lazarus v2.0 multiple y values can also be drawn in a side-by-side arrangement (Stacked = false).

In addition to rectangular bars the data can be represented by alternative shapes: cylinder, hexagonal prism, pyramid or cone - see property BarShape which supports these values: bsRectangular, bsCylindrical, bsHexPrism, bsPyramid, bsConical. Furthermore, the event OnCustomDrawBar allows to paint the bars in any user-defined manner.

Area series

TAreaSeries represents data as a polygon extending downwards from the data points either to a ZeroLevel line or towards infinity (if UseZeroLevel=false).

You can get a "stepped" look by setting the ConnectType property.

Like TBarSeries and TLineSeries, an area series can accept several y values for the same x from a multi-valued data source. These y values are drawn in a stacked way if the property Stacked is set to True (its default value). Use a ChartStyles component to define the appearance of the individual layers. (Note that in Lazarus versions 1.8.x or older, ChartStyles do not colorize overlapping layers consistently).

The property Banded (available in Lazarus v2.0+), if set to true, suppresses painting of the lowest stack level. This way a band of data values can be highlighted: use a chartsource with two y values and set the first y value to the lower and the second y value to the upper band level. Alternatively, the width of the band can be specified in the second y value if both properties Banded and Stacked are set to true.

Multiple-y value support should be applied with caution: Stacking non-positive values may produce plots which are difficult to understand, and unstacked area series (Stacked = false) may suffer from data being covered by other y values. Also, the ZeroLevel should be included only in the lowest stack level to avoid unusual results.

A 3D-like presentation of the series can be obtained if Depth is set to a positive value, something like 10 or 20. Note that the drawing algorithm is very simple and likely produces incorrect displays when curves cross, or stacking and banding are turned off.

Polygon series

TPolygonSeries draws a filled polygon defined by the points of the series. It is intended to be the basis of contour plots or GIS plots (earth maps). The series supports both single and multiple polygons. Single polygons are closed automatically. Multiple Polygons are created by closing a first polygon and simply adding the points of one ore more subsequent polygon(s); each contributing polygon must be closed. Such polygonare are useful to display disconnected "islands" or to display "holes" in an outer shape; in the latter case the points of inner and outer polygons must have opposite orientations.

Multi-value series

Multi-value series require a multi-valued data source, and use additional X and/or Y values as extra parameters to draw complex shapes.

Bubble series

TBubbleSeries represent data as circles of variable radius centered at data points. This series requires a source with YCount of at least 2, and uses the first additional Y value as the bubble radius.

The OverrideColor property allows you to set the color of either the interior or the edge of each bubble individually.

Box-and-whiskers series

TBoxAndWhiskerSeries represents data as rectangles with a central line and two T-like shapes protruding in both directions. Although in statistics a box-and whiskers plot is supposed to be based on specific data quartiles, TAChart does not enforce this, allowing users to draw arbitrary plots.

With some effort, box-and whiskers series may be used to represent other charts of different meaning but similar appearance, such as Gantt diagrams.

This series requires a source with YCount of at least 5, and uses Y values as follows:

Index Usage
0 Lower whisker
1 Lower box bound
2 Central line
3 Upper box bound
4 Upper whisker

Open-high-low-close series

TOpenHighLowCloseSeries represents data as vertical lines with two ticks, as described here.

It usually requires YCount of at least 4, and uses Y values as follows:

Property Default Usage
YIndexLow 0 Lower point of line
YIndexOpen 1 Left-facing tick position
YIndexClose 2 Right-facing tick position
YIndexHigh 3 Upper point of line

Note that although Y values are supposed to be ordered ascending along the table above, the series does not enforce this and will draw any supplied data.

Field series

TFieldSeries displays a vector at each data point. The vector is drawn as a line segment with an optional arrow. By default, the line is centered at the x,y coordinates stored in the chart source, its direction is given by additional values stored in the XList and YList of the chart source. When property VectorCoordKind is switched to vckStartend the line is defined by start and end points directly. In total, this series type requires a source with two x and y values:

Source data item field Usage
X X coordinate of line center (or start point, if VectorCoordKind = vckStartEnd)
Y Y coordinate of line center (or start point)
XList[0] X coordinate of line direction (or end point, if VectorCoordKind = vckStartEnd)
YList[0] Y coordinate of line direction (or end point)

The method AddVector(x,y: Double; vectorx, vectory: Double; ALabel: String = ''; AColor: TColor = clTAColor) helps to assign all values correctly to the internal list source.

In order to avoid overlapping of vectors call the method NormalizeVectors(ALength: Double) to normalize their lengths such that the longest vector has the specified length.

The arrow parameters are understood to be percentages of the vector length, i.e. the arrow becomes smaller for shorter vectors.

Radial series

Radial series ignore axis transformations. You can see examples of radial series in the "radial" demo.

Pie series

TPieSeries draws pie charts.

For each data point, pie series interprets Y value as a relative size of the slice, and X value as a distance of slice from the center of the pie (only if Exploded property is true).

Beginning at StartAngle, the pies run in counter-clockwise direction around the circle. When AngleRange is at its default of 360 the pies cover the full circle; a smaller value allows to use the circle only partially.

Pie radius can be either set manually by FixedRadius property, or calculated automatically so that the whole series, including all labels, exactly fits the parent chart.

A ring can be painted instead of a pie slice by giving the property InnerRadiusPercent a value greater than 0, but smaller than 100 - this determines the radius of the inner circle as percentage of the total radius.

The slice colors are determined by either data items' Color field or hard-coded palette. Slices contours are drawn using EdgePen property.

There are several options for label positioning, controlled by MarkPositions property:

  • pmpAround -- marks are drawn outside the pie, on the continuation or radius vector for each slice
  • pmpInside -- marks are drawn inside each slice
  • pmpLeftRight -- marks are drawn directly to the left or to the right of slice

MarkDistance defines the distance between the marks starting point and the label. The starting point is defined by MarkPositionCentered to be either the pie perimeter (false) or center (true). MarkDistancePercent, if set to true, interprets Marks.Distance as percentage of the pie radius. Otherwise it is in image units.

If RotateLabels is true, each label is additionally rotated so that (if LabelFont.Orientation=0) it is parallel to the radius vector of its slice.

If the Y value of a data item is set to NaN, the item is skipped. If the X value is set to NaN, the item is not drawn, but the space for it is still reserved. This allows drawing of "partial" pie diagrams.

Pie charts have limited support for 3-d drawing. The property Depth determines the thickness of the pie. Orientation supplements the normal view (poNormal) with an oblique view of the reclined (poHorizontal) and upright (poVertical) pie series, the latter two being controlled by property ViewAngle in degrees between 0 and 89. Since TAChart does not implement a true hidden line/hidden area algorithm there may be some chance of drawing artifacts for some combinations of parameters, in particular when AngleRange is not 360. A slight change of StartAngle and/or AngleRange usually helps to fix this issue.

Polar series

TPolarSeries represents data as points in polar coordinates.

The origin of the polar coordinate system is defined in graph coordinates by OriginX and OriginY properties.

For each data point, X value is interpreted as an angle in radians and Y value -- as a distance from the center.

The TPolarSeries does not support axis transformations.

Some additional properties:

  • CloseCircle: If true the last point is connected with the first one.
  • Filled: If true the polygon of the series points is filled using the current Brush. If CloseCircle is false the fill goes to the origin.
  • ShowPoints: If true then the series pointer is drawn at the position of each data point.

User-drawn series

Provides <codtte>OnDraw and OnGetBounds events to allow arbitrary custom drawing on the TChart. Note that using TChart.Canvas directly is highly discouraged and will often not work as expected.

Functional series

Functional series are recommended way to draw functional plots as opposed to, for example, pre-calculating function data and using line series. They provide scale-independent controls of smoothness vs drawing speed.

You can see examples of functional series in "func" demo.

Function series

TFuncSeries represents a one-dimensional function defined by the OnCalculate event. The function is calculated for each Step pixels of the image, so you can use this property to increase either "smoothness" or drawing speed.

The Extent property may be used to set both x and y extents for the purpose of calculating full extent of the chart. While drawing, however, this property is ignored, and the function will be displayed according to the current extent.

The DomainExclusions property allows to exclude some intervals from the function domain. The TFuncSeries correctly draws discontinuity points set by DomainExclusions. Currently, DomainExclusions can only be set at run-time by calling the AddRange or AddPoint procedures. Intervals defined by DomainExclusions are closed by default, i.e. contain the end points; this means that the function is not calculated at the end points. If the domain exclusion must contain endpoints (as needed for the funtion y = sqrt(x)) call AddRange with the corresponding element of the set TIntervalOptions = (ioOpenStart, ioOpenEnd) as optional third parameter.

The DomainExclusions.Epsilon property controls the distance between endpoint and last drawn point (of course, in case of an open interval, the curve begins immediately at the end point). Epsilon can be adjusted in the rare cases that the default value of 1E-6 does not produce correct results.

Expression series

The TExpressionSeries is similar to the TFuncSeries, but the function is specified as a mathematical expression string such as 'sin(1.23456*x)' (property Expression). The series creates an instance of the FPExpressionParser to analyze the string and to calculate the function values. In this way functions can be plotted at designtime.

The property Params allows to define parameters for the function term; in the object inspector it opens a collection editor in which every parameter can be specified by its name (as used in the expression) and its value. If, for example, a parameter f is defined to have the value 1.23456 then above expression can also be written as 'sin(f*x)'.

Similarly to TFuncSeries, domain exclusions are supported to define the regions at which the function cannot be calculated. But in agreement with mathematical conventions, TExpressionSeries requires in property Domain the region in which the function is defined (the complement of the domain exclusions). The region is specified by a string such as 'x >= 0'. If several conditions exist they must be separated by a colon, e.g. 'x < -1; x > 1'. The colon has function of a logical OR. An interval is defined like '-1 < x < 1'. The constant parts of the conditions can be mathematical expressions as well - the following example excludes the point π/2 from calculation of the function values: 'x <> pi/2'. Decimal numbers must be entered with a dot as decimal separator, no matter what is defined in the language settings of the operating system.

Light bulb  Note: Parameters and domains must be defined before the expression is entered, otherwise the parser will report an error

B-spline series

TBSplineSeries draws B-spline of given Degree using De Boor's algorithm.

Spline segments shorter then Step pixels are represented by straight lines.

Cubic spline series

TCubicSplineSeries draws the data curve as a cubic spline using the standard NumLib package of FPC.

In Lazarus v2.0+, a property SplineType allows to select between natural and monotone Hermite splines, the latter avoiding overshoot of the interpolation.

The spline function is calculated for each Step pixels of the image, so you can use this property to increase "smoothness" or drawing speed.

The data source must contain at least two points and have strictly increasing X coordinates. (Older Lazarus versions before v2.0 require at least 4 data points; for less points a polygon is drawn instead of a spline using the BadDataPen if the csoDrawFewPoints option is set.)

If X values are unordered and the csoDrawUnorderedX option is set, the spline will be drawn ignoring offending points using BadDataPen.

The options csoExtrapolateLeft and csoExtrapolateRight enable natural extrapolation to the left and to the right correspondingly.

Fit series

TFitSeries performs least squares fitting using calculation routines contained in the standard Numlib package from the FPC. The main fitting unit is TAFitLib which is self-contained and can be applied also without TAChart.

The fitting function is selected via the FitEquation property:

  • fePolynomial: y = b0 + b1x + b2x2 + … + bnxn, where the value of n is controlled by ParamCount property (ParamCount = n + 1).
  • feLinear: y = a + bx
  • feExp: y = a * ebx
  • fePower: y = a * xb
  • feCustom: y = b0X0(x) + b1X1(x) + b2X2(x) + … + bnXn(x) where the value of n is controlled by the ParamCount property (ParamCount = n + 1), and Xi(x), i = 0..n, are "basis functions" which are defined by the method SetFitBasisFunc(AIndex: TFitFuncIndex; AFitFunc: TFitFunc; AFitFuncName: String).
    • AIndex - index i of the basis function, 1..MaxInt.
    • AFitFuncName is a text representation of the function to be used for the default legend.
    • AFitFunc - address of the basis function Xi(x) which has the signature function(x: ArbFloat; Param: Integer): ArbFloat with ArbFloat being the general floating-point data type in FPC's Numlib (unit typ). Some basis functions are readily available in unit TAFitLib:
function FitBaseFunc_Const(x: ArbFloat; Param: Integer): ArbFloat;   // constant term
function FitBaseFunc_Linear(x: ArbFloat; Param: Integer): ArbFloat;  // linear term (x)
function FitBaseFunc_Square(x: ArbFloat; Param: Integer): ArbFloat;  // square term (x^2)
function FitBaseFunc_Cube(x: ArbFloat; Param: Integer): ArbFloat;    // cubic term (x^3)
function FitBaseFunc_Poly(x: ArbFloat; Param: Integer): ArbFloat;    // power term (x^Param)
function FitBaseFunc_Sin(x: ArbFloat; Param: Integer): ArbFloat;     // sin(x*Param) 
function FitBaseFunc_Cos(x: ArbFloat; Param: Integer): ArbFloat;     // cos(x*Param)

By default, the parameters, b0, b1, ..., a, b are varied by the fitting process such that the mean square deviation between data and fitted curves is minimized. However, it is also possible to hold one or more fitting parameters constant, e.g. in order to force a fitted straight line to run through the origin. For this purpose, the values of the constant parameters must be specified in the ';' or '|' delimited list of string values of property FixedParams. The order of values must match the order of the fitting parameters. Variable parameters can be left empty or replaced by a non-numerical string.

Example: FixedParams='var;2' (or shorter: ';2') means that the first fitting parameter is variable, but the second one is held constant a the value 2; if there are more than 2 parameters, the others are considered to be variable, too.

The fitting range is usually defined by the series extent, but can be manually set via the FitRange property. The fitting function is drawn over the entire axis unless DrawFitRangeOnly = true.

When fitting is complete the ErrCode of the series is set to indicate whether the calculation was successful or not:

  • fitOK: successful
  • fitDimError: calculation was aborted because the dimensions of the data arrays (x, y, y error bars) do not match.
  • fitMoreParamsThanValues: calculation failed because there are more fitting parameters than data values.
  • fitNoFitParams:calculation aborted because no fit parameters are specified. This could happen incidentally if all fitting parameter are forced to be fixed in the FixedParams property.
  • fitSingular: the design matrix of the fit problem is found to be (nearly) singular.
  • fitNoBaseFunction: Not enough fit basis functions are specified for the case of FitEquation=feCustom.

The method ErrorMsg creates a text for an error message from the current ErrCode.

The event OnFitComplete is called after the fitting equation is found, but before the drawing starts. This is a good place to query the results of the fitting procedure:

  • Param[AIndex] is the best-fit value for the parameter with the specified index, AIndex = 0..ParamCount-1.
  • ParamError[AIndex] tells the uncertainty ("standard error" in statistical terms) of the corresponding fitting parameter.
  • The procedure GetConfidenceLimits(AIndex: Integer; out ALower, AUpper: Double) returns the range between ALower and AUpper within which the corresponding best-fit parameter is expected to be found at the probability specified by ConfidenceLevel (default: 0.95, i.e. 95%).
  • Param_tValue[AIndex] returns the value of the t statistic for the corresponding fit parameter. This is the ratio of value divided by standard error. For an accurate parameter, the t value should be much larger than 1.
  • Param_pValue[AIndex] is the probability that any t value as high as Param_tValue occurs just by chance for the given degrees of freedom. In order to "trust" the fitted value with a certainty given by ConfidenceLevel, the p value should be smaller than 1 - ConfidenceLevel, by default 0.05.
  • FitStatistics informs about other statistical parameters helpful to verify the validity of the fitted model or for further statistical calculations. These data are accessible as properties or functions of this class:
    • N (integer): the number of data points used for fitting. Note that this can be less than the data points provided by the chart source since it may contain NaN values which are skipped.
    • M (integer): the number of fitting parameters. Normally this is the value of ParamCount, but if certain parameters are forced to be constant (FixedParams) their count is subtracted.
    • DOF (integer): "degrees of freedom" - is the difference N - M, an important parameter in the statistical analysis of the fit results.
    • SST: "total sum of squares" - this is the sum of the squares of the term (y[i] - ymean)/dy[i] over all data points. Here, y[i] is the y value of a data point at index i, dy[i] the size of its error bar (standard deviation) - or 1 if not available -, and ymean is the average value of y[i]/dy[i]. The quantity identifies the total variation of data points around their mean value.
    • SSE: "error sum of squares" - the variation of the data points around the fitted curve, i.e. sum of ((y[i] - ycalc(x[i])/dy[i])^2); here ycalc(x[i]) is the calculated value of the fitted curve at the point x[i].
    • SSR: "regression sum of squares" - the variation of the fitted curve alone, i.e. sum of ((ycalc(x[i]) - ymean)/dy[i])^2.
    • xBar: average value of the x coordinates of all used data points.
    • SSx: variation of the x coordinates of the data points, i.e. sum of <cottde>(x[i] - xbar)^2.
    • VarCovar[i, j: Integer]: Double: is an element of the variance-covariance matrix for the fit parameters at the given indexes.
    • R2: "coefficient of determination". This is the ratio SSR/SSE and describes how much of the variation in the data is explained by the fitted curve. The value is 1 for a perfect fit and 0 for absolutely no agreement.
    • AdjR2: was introduced to compensate for the effect that R2 usually increases by adding more and more fit parameters.
    • Chi2: another word for SSE. In essence, this is the statistical quantity which is minimized during the fitting procedure. The value given is the minimum value found.
    • ReducedChi2: is Chi2 (or: SSE) normalized to the degrees of freedom, i.e. variation of the data around the fitted curve per degree of freedom. Should be "small" for a good fit.
    • ResidualStdError: is the overall standard error of the fit. Should be "small".
    • pValue: (fractional) probability that the residual scatter of the data points around the fitted curve is by chance. Should be high, in practice a few thenths, although sometimes values as low as 0.001 are still accepted. If no error bars are included in the fit, sometimes p turns out to be either exactly 0 or 1 - such values should be ignored.
  • The procedures GetLowerConfidenceInterval(const Ax: Double; out AY: Double), GetUpperConfidenceInterval, GetLowerPredictionInterval and GetUpperPredictionInterval can be hooked into the OnCalculate event of a TFuncSeries in order to plot the limits of the lower and upper confidence and prediction intervals around the fitted curve. These limits define areas around the fitted curve within which the overall fitted curve (confidence interval) or individual data points (prediction interval) can be expected based on the probability given by ConfidenceLevel.
  • Note: all these statistical data assume that the residual errors follow a normal distribution and that the error bars have been estimated appropriately.

The EquationText method returns an IEquationText interface, which allows to construct a string representing the fit equation. You can override names of x and y variables, numeric format, and, finally, obtain a string from Get function. Note that a transformation from IEquationText to String is defined, so usually there is no need to call Get explicitly.

Legend.Format property of fit series supports additional format argument ('%2:s') pointing to the default equation text.

After a change to TFitSeries parameters, the equation will be recalculated on the next drawing of the series. To recalculate it immediately, call ExecFit procedure. Use State property to check the validity of current equation.

Color map series

TColorMapSeries represents a 2-dimensional function defined by the OnCalculate event as a field of pixels, with color depending on function value.

The series is drawn as a set of rectangles of size StepX by StepY pixels. The function is called once for each rectangle.

Color values are defined by one of the built-in palettes (property BuiltinPalette = cmpHot, cmpCold, cmpRainbow, cmpMonochrome). The range of values mapped to the colors of the palette must be specified in BuiltinPaletteMax and BuiltinPaletteMin, otherwise the results are not predictable.

Alternatively, an external ChartSource can be assigned to property ColorSource, which must be sorted. Each data point of the chart source is interpreted as having its X value correspond to the Color value. If the actual value falls between color levels, it can be either linearly interpolated (if Interpolate is true) or rounded down to the nearest level.

When Legend.Multiplicity=lmPoint, the color map series will display the color levels in the legend.

Expression color map series

is similar to the color map series with the main difference that the 2-dimensional function is not defined by an event, but by a mathematical expression, such as x^2+y^2, like in the TExpressionSeries, but now with two variables x and y. The variables can be renamed by means of the properties VariableNameX and VariableNameY. Similar to TExpressionSeries it is also possible to introduce parameters (property Params). Domains, however, are not supported, the function must be defined within the entire visible x/y range.

Sources

chartsource hierarchy.png

Data can get into a chart from various sources.

They are implemented as a set of components derived from TCustomChartSource.

To assign a source to a series, you can set the Source property. If the property is left unassigned, the series will use its own built-in list source. Methods like AddXY are delegated to the current series source. Note that the list source is the only editable source, so after you assign, for example, a random chart source to the series, a call to AddXY will raise an exception.

Each data item has the following fields: X, Y, XList, YList, Color, Text.

Sorted sources

If it is known that X values of the source are ascending, some additional optimizations like binary search become possible. So all sources have an IsSorted property which helps determine that.

In Lazarus 2.1+, the TListChartSource can be sorted according to several criteria:

  • SortBy = sbX, sbY, sbText, sbColor, sbCustom: sorting by X or Y value, Text, Color or in a user-defined way, respectively. In the latter case a handler for the event OnCompare must be provided.
  • SortIndex: the index of the X or Y value used for sorting.
  • SortDir = sdAscending, sdDescending: sorting in ascending or descending order.

When a source is sorted by anything other than x only the drawing order of the related series is affected, and it may be possible that nothing changes in the chart. A visual effect is seen for

  • TPieSeries because the data point order determines to order of the pies around the circle
  • TBubbleSeries when bubbles overlap. Use the combination SortBy=sbY, SortIndex=1 and SortDir=sdDescending to avoid covered bubbles because large bubbles are drawn first and small bubbles last.
  • all series inherited from TBasicPointSeries when the XCount of the associated chart source is 0: in this case, the X value of the source is ignored and replaced by the data point index. Since the data point index changes upon sorting the data points will be automatically rearranged in the sorted order - see example sort_demo in the demo folder.

Multi-valued sources

Sources can contain multiple Y values for each X value. These values are stored in the YList field of the source data item. The number of Y values is determined by the YCount property. Note that the first Y value is stored in Y field anyway, so YCount=3 means that values are stored in Y, YList[0] and YList[1].

Additional values may be used by various series -- for example, stacked bars or bubble charts.

Moreover, it is also possible to store several X values for the same data point. This is required by TFieldSeries. These additional X values are stored in the XList of the source data item. Like with the Y values, the total count of X values is given by the XCount property which contains the "ordinary" X value plus the length of the XList array.

Skipping source items

It is possible to instruct TAChart to skip drawing some source items without removing them from the source. This may be useful for both optimization and user interface reasons.

To skip the item, assign NaN to either X value or one of the Y values. The exact effect of skipping depends on the series, but usually setting X to NaN means skipping the entire item, while setting Y or some element of YList means skipping only this Y value, while still drawing others.

Also note that if you set only one coordinate to NaN, the other will still take part in extent calculation.

In case of stacked series it is not clear how the missing value should be handled when the following levels are added to it. In Lazarus v2.1+ there is a property StackedNaN which can be selected as

  • snReplaceByZero -- the missing value is considered to be zero; this is the way how Excel handles this case.
  • snDoNotDraw -- skips the entire data point with all stack levels.

You can see examples of skipping items in the "nan" demo.

Error bars

TLineSeries, <cottde>TBSplineSeries, TCubicSplineSeries and TFitSeries can display error bars at each data point. The size of the error bars in both x and y direction is determined by the parameters in the XErrorBarData and YErrorBarData properties, respectively:

  • Kind: TChartErrorBarKind: defines how the following data are interpreted
    • ebkNone: ignore - no error bars will be diplayed
    • ebkConst: all data points have the same error bar given by ValuePlus and ValueMinus.
    • ebkPercent: the values ValuePlus and ValueMinus are understood as percentage of the data values.
    • ebkChartSource: every data point can have an individual error bar. The error bar length is stored in the XList or YList of a multi-valued chart source. The index among all x and y values is specified by IndexPlus and IndexMinus for positive and negative error bar, respectively.
  • ValuePlus and ValueMinus: length of the positive and negative error bars, respectively. Depending on the setting of Kind, the value is assumed to be constant for all data points (Kind = tt, axis units), or a percentage of the data point value (Kind = ebkPercent). Both values must be positive numbers with the exception of ValueMinus = -1 which indicates that the negative error bar should be equal to the positive error bar.
  • IndexPlus and IndexMinus are used when Kind is ebkChartSource and indicate the x or y index in a multi-valued chartsource from which the error bar lengths for the individual data points can be obtained. Suppose a chart source contains two x values (XCount = 2) and XErrorBarData.ValuePlus is 1 then the second x value (stored in XList[0]) is used for the positive error bar length. If IndexMinus is -1 then the negative error bar length is assumed to be equal to that of the positive error bar without having to provide an explicit value in the chart source.
Light bulb  Note: Usage of multiple y values for other purposes than individual error bars is discouraged in this context because the present implementation can display error bars only for the y value with index 0.

Each series type supporting error bars has additional properties XErrorBars and YErrorBars which determine how the error bars will be displayed:

  • Visible can be used to turn off error bars even if their size is specified in the chart source.
  • Width is the length of the crossbar drawn at the end of the error bar. The default value -1 means that its length will be equal to the corresponding size of the series' Pointer.
  • Pen defines the pen parameter used for drawing the error bars. Usually set Pen.Color to the color of the series.

List source

TListChartSource is a basic chart source, storing chart data inside itself. As such, you can use Add and Delete functions to change source data.

The Item property returns a pointer directly to the underlying storage, so you can modify item fields directly. However, doing this will not automatically update the chart and will also invalidate some internal state of list source. It is recommended:

  • To change a single item, use Set{Color|Text|XValue|YValue|YList} procedures.
  • To change many items in a time-sensitive code, call BeginUpdate, then modify items directly, then call EndUpdate.

The source also has DataPoints property to allow setting data at design time. This property is a TStringList, with each line representing a data point. Line consists of X, Y, optional YList, Color and Text values separated by | (vertical bar) character. Note that DataPoints property is designed primarily for sample and demo code. It is very inefficient, and you should not use it to add data points from the code.

You can control X value sorting by setting the Sorted property. Note when Sorted is set to true, list source sorts the data and keeps it sorted after insertion of new points. If inserted points are not sorted, this may result in quadratic running time. You should either set Sorted to true only after insertion, or pre-sort your data to avoid this.

Random source

TRandomChartSource source generates random data in the given range and is intended mostly to use in demos. You can also use it as design-time replacement for your actual data source. This will let you see and change the look of your chart without having to run the application.

Each random source uses its own independent random number generator to guarantee the stability of its values.

User-defined source

This source may be used if you already have your data in memory, but in a format different from the data items used in TAChart. With user-defined source you can access your data directly instead of first moving it all into a list source. In some cases this may improve performance or reduce memory consumption. You can of course also generate, filter or modify data with the user-defined source.

The number of data items in the source is determined by PointsNumber property. Items themselves must be returned by the OnGetChartDataItem event handler. You should call Reset method to notify the chart about changes in the data. (Other sources detect changes and perform notification automatically).

Note that if the Sorted property is set to true, it is the responsibility of the event handler to provide actually sorted data.

Database source

TDbChartSource takes data directly from a database. It is contained in a separate unit to avoid introducing a db-aware component dependency into every project using TAChart.

The following properties contain database field names for data item fields:

Property Access method
FieldX AsFloat (or AsDateTime, if option dcsoDateTimeX is set)
FieldY AsFloat (or AsDateTime, if option dcsoDateTimeY is set)
FieldColor AsInteger
FieldText AsString

If FieldX property is empty, RecNo is used instead. NULL values in coordinate fields are translated into NaNs.

To get a multi-valued source, set the FieldY property to a comma-separated list of field names. Note that YCount will be set automatically -- trying to set it by hand will raise an exception.

When the dataset returns date/time fields as strings you should set the property DateTimeFormat accordingly (e.g. 'yyyy-mm-dd') so that the strings can be converted to a TDateTime variables.

Please note that iterating through the items of a TDBChartSource is very ineffective. Do not attach other DB-aware controls to the same dataset because they will mirror the process. Usually it is recommended to copy the DBChartSource to a ListChartSource for better performance. Note also that some dataset types do not read all records of a table or query.

Calculated source

TCalculatedChartSource is the source used for manipulating data taken from the Origin source. This source performs transformations in the following order:

  • Y reordering -- Y values of multi-valued source can be duplicated, removed or exchanged according to ReorderYList property, which is a comma-separated list of original Y value indexes. Step skipped if ReorderYList is empty.
  • Accumulation -- replaces each item's Y values by a function of the neighboring values.
  • Percentage -- replace each Y value by the percentage of total of all Y values for that item. Useful for drawing "stacked percentage" bar and area charts. Step skipped if the Percentage property is false.

Accumulation is controlled by several properties:

AccumulationRange controls number of items to accumulate, counting the current item, so AccumulationRange = 1 disables accumulation. AccumulationRange = 0 is interpreted as "infinite" range, i.e. request to accumulate over all the available data. This is mostly useful in conjunction with camSum method to produce cumulative sums.

Note that the actual number of items may be lower for the points near the beginning or end of the source.

AccumulationDirection:

  • cadBackward -- use previous values from the source,
  • cadForward -- use next values from the source,
  • cadCenter -- use both previous and next values for a total number of up to 2 * AccumulationRange - 1.

AccumulationMethod:

  • camNone -- skip accumulation step,
  • camSum -- sum of the last AccumulationRange items,
  • camAverage -- average the last AccumulationRange items,
  • camDerivative -- finite differences derivative, calculated using the last AccumulationRange items. Note that the calculation method assumes equidistant X values, and may loose accuracy if the X distance varies substantially.
  • camSmoothDerivative -- smoothed finite differences derivative, more robust against random measurement errors in the data.

Interval source

TIntervalChartSource can supply arbitrarily many points in a given interval, controlled by various properties of the source. This source is the default built-in source for axis marks. If you want to set the same axis interval parameters for several axes, you can assign a single TIntervalChartSource component the Marks.Source of each of those axes.

Date-time interval source

TDateTimeIntervalChartSource is similar to the TIntervalChartSource, but provides marks formatted as date/time values. This source automatically selects appropriate calendar interval (such as week or hour) depending on the axis scale.

Note that X values of provided data items are TDateTime values, and Label values contain formatted date-time strings. If you want to use TDateTimeIntervalChartSource as the source of axis marks, you should probably set Marks.Format or Marks.Style properties to make use of provided labels.

If the DateTimeFormat property is set, it is used to format all labels. Formatting is performed with standard SysUtils.FormatDateTime function. If DateTimeFormat is empty, format is chosen automatically based on scale.

TDateTimeIntervalChartSource is defined in the TAIntervalSources unit.

Source optimization notes

Primary data source API allows random access. Nevertheless, many sources, in particular random, database and calculated, may exhibit quadratic or worse behavior if actually accessed randomly. TAChart itself takes care to only use sequential access (although it may require several passes). Sources optimize sequential access by using internal state. User code should be careful not to reset this state during chart drawing from event handlers or custom series code.

A notable exception is the list source, which is guaranteed to provide fast random access. It may be used to cache slow sources with the help of CopyFrom procedure.

Also note that the pointer returned by GetItem function may point to the internal buffer which will be overwritten by the next call to GetItem. Again the list source does not have this limitation.

Coordinates and axes

TAChart uses four coordinate systems:

  • Axis coordinates (known in some other applications as object coordinates) -- this is the "raw" coordinate values obtained from the data. As the name implies, axis coordinates are interpreted in terms of specific axis -- the same coordinate value may have different meaning depending on the axis it is applied to.
  • Graph coordinates (aka world coordinates) are converted from the axis coordinates using axis transformation, such as logarithmic scale. Graph coordinates are common for all objects in the chart.
  • Image coordinates (aka screen coordinates) are converted from graph coordinates based on the chart viewport. This transformation is always linear and can be influenced by chart tools such as zooming and panning.
  • Device coordinates are usually equal to screen coordinates, but may be adjusted to the drawing back-end to accommodate different physical resolutions (DPI values). See, for example, printer drawer.

You can add or remove an arbitrary number of axes by editing AxisList property. By default, chart have two axes: one horizontal and one vertical. They are accessible via BottomAxis and LeftAxis properties. Note that those properties are aliases to AxisList[0] and AxisList[1], so if you remove those default axes, accessing BottomAxis and LeftAxis will return nil.

Visually, axis consists of the axis line (drawn by AxisPen), grid lines (drawn by GridPen), ticks, marks and arrow.

Each axis is drawn inside its own rectangle, determined by the size of mark labels and ticks. By assigning several axes the same positive Group number, you can have them share the same rectangular area. Grouped axes can be used to achieve a "panes" look, when several series are drawn on different portions of the same graph.

Axes with the same alignment, but different groups, are stacked alongside each other. You can use the Margin property to control spacing between such axes.

Axis transformations

Axis transformations are grouped in the TChartAxisTransformations component. It contains a list of transformations which are applied in the order given. (For example, performing scale before and after logarithm will yield different results).

For transformations to have an effect, you should:

  • Make sure that the Enabled property is true for all transformations.
  • Assign transformations component to Transformations property of at least one axis.
  • Assign AxisIndexX and/or AxisIndexY properties of the series to the appropriate axis index.

Note that by default, AxisIndexX and AxisIndexY have a special value of -1, which means "ignore axis transformations". Also note that if you add or remove axes, the indexes may change. You can rotate the series by assigning both AxisIndexX to vertical axis and AxisIndexY to the horizontal axis.

Linear and logarithmic transformation

Those are simple arithmetic transformations.

Auto-scaling transformation

To display several independently-scaled series, assign them to two or more axes and apply TAutoScaleAxisTransform to each axis. See "axistransf" demo, page "Linear", checkbox "Auto scale".

By using the MinValue and MaxValue properties you can control the in graph coordinates of the auto-scaled series. For example, by setting one transformation to a range from 0 to 1, and another to a range from 1 to 2, you will confine all the series using the first transformation to the upper half of the chart, and all the series using the second transformation to the lower half (assuming there are no unassigned series left).

Cumulative normal distribution transformation

Use TCumulNormDistrAxisTransform to set cumulative normal distribution as an axis transformation. This may be useful in statistical charting.

Note that this transformation result is in range from 0 to 1. It is recommended to restrict the axis range accordingly.

See the "Normal distribution" page of the "axistransf" demo for an example.

User-defined transformation

You can create you own transformation either by inheriting from TAxisTransform, or, if you prefer "visual" programming, by using TUserDefinedAxisTransform. In either case there are two basic requirements:

  • AxisToGraph and GraphToAxis functions should be defined everywhere in data range and inverse of each other (for example, avoid now only dividing, but also multiplying by zero).
  • Functions should be monotonic.

Date and time axes

Using date/time values for axis marks is a common requirement. The correct way to do this depends on the exact nature of your date/time data:

  • If the data is actual TDateTime values, use it as an X coordinate in points, assign TDateTimeIntervalChartSource to the Marks.Source of the corresponding axis, and change Marks.Style to smsLabel. TDateTimeIntervalChartSource provides automatic labeling depending on the scale in wide range -- from centuries to milliseconds.
  • If the data is in physical units, but outside TDateTime values range, such as astronomical or micro-electronics timings, use it as a normal X coordinate with custom Marks.Format.
  • If the data is in calendar units, such as months and years, which is common for financial data, you have several options:
    • If date units are "equidistant" when interpreted as numbers (for example, simple year numbers), assign the same data source to both series and axis marks, then use custom Marks.Format, Axis.OnMarkToText event or Text field of the data items to format dates per your requirements.
    • If date units are not "equidistant" (for example, numbers in YYYYMM format or even date strings), use surrogate X coordinate (usually, simply a point index) instead and display dates using methods described above.
    • Convert coordinates to TDateTime values beforehand, then use tt as described above.

Axis ranges

Axis range is measured in axis units and determines the extent of series attached to this axis. Normally an axis range is equal to the union of all series extents, but may be overridden with the Range property.

Axis marks are displayed inside the axis marks range, which is determined as the intersection of:

  • Logical extent (converted to axis coordinates)
  • Combined extent of all data series of this axis, if Marks.AtDataOnly = true
  • Marks.Range property.

Axis intervals

Axis marks are located along the axis at equal intervals chosen by the chart. The choice of intervals can be influenced via Intervals property. This property has a few subproperties, which are applied in the following order:

  • Options property contains a set of flags controlling usage of other parameters. If the flag is not in the set, the corresponding parameter is ignored.
  • NiceSteps is a string containing a sequence of "step multipliers" -- floating point values in the range from 0 to 1, excluding 0. If this property is applied, the axis step will be a power of ten multiplied by one of the provided values. If several multipliers can be used, the leftmost one will be chosen. Multipliers are separated by the vertical bar (|) character.
  • If NiceSteps is ignored or TAChart fails to find appropriate step, the axis range will be divided into equal intervals without regard to the number of decimal digits in the representation of mark values. In this case, it is recommended to reduce the number of visible digits in Marks.Format.
  • MinLength and MaxLength properties set the limits of interval length in image units (usually pixels).
  • Count property is the desired number of axis marks. Among all mark steps passing the previous tests, TChart chooses the one which gives the number of marks nearest to the Count. If Count property is ignored, or there are several steps with equal number of marks, the longest step is chosen.
  • Tolerance property sets the maximum distance in image units by which the mark may be moved in order to reduce the length of its decimal representation. This helps to avoid a lot of meaningless digits in mark labels when previous steps have for some reason failed to generate "nice" marks. Note that this stage ignores all previous restrictions, so large Tolerance values may result in significant distortions. Setting Tolerance = 1 is often sufficient.

Note that if you set chart source manually, Intervals property may apply only partially or not apply at all. For example, list source is unable to guarantee maximum interval length, since it has only a finite number of points. See also interval chart source.

Axis position

By default, the axis is aligned to the side of the chart corresponding to the Alignment property. You can position an axis differently by setting the Position and PositionUnits properties.

The following values of the PositionUnits property are accepted:

  • cuPercent -- percentage of the clipping rectangle.
  • cuGraph -- absolute position in graph coordinates.
  • cuPixels -- position in screen units relative to the default coordinate.

Note 1: If the axis position is changed from default (Position = 0 and PositionUnits = cuPercent), it will be excluded from the margins calculation, so it will appear to overlap the series.

Note 2: The Alignment affects not only the position of the axis itself, but also of the corresponding labels. So, if two axes have both Position = 50 and PositionUnits = cuPercent, but one has Alignment = calLeft and another Alignment = calRight, they will diaplay a common axis line with labels on different sides.

See "Position" page of the "axis" demo for an example.

Axis titles

If the property TextFormat is switched to tfHTML then HTML entities and tags can be embedded for special formatting of axis titles, such as subscripts/superscripts or greek characters. See HTML for details.

The property Wordwrap, if set to true, allows to wrap extra long axis titles into new lines. Note that this feature works only when the title is horizontal for the x axis and vertical for the y axis. Moreover, html-formatted text is not supported for word-wrapping.

Axis LabelSize

Since Lazarus v1.4 the chart axes have a new property LabelSize which - if different from 0 - overrides the automatic calculation of the space needed by the axis marks. The LabelSize, approximately, defines the pixels between axis line and axis title, independently of the size of the axis labels. This feature can be used to align the axis lines of several charts that are stacked above each other or placed side by side.

See the "axisalign" demo and Graphical explanation for an example.

Light bulb  Note: If the (non-zero) LabelSize value is too small then the axis labels may reach into the axis title or may even be truncated at the chart border.

Extents and margins

Extents

Chart extent is a rectangle in graph coordinates.

There are several extents defined by TChart:

  • Full extent -- usually determined automatically as the area encompassing all the data from series and axis ranges. Is returned by the GetFullExtent function.
  • Fixed extent -- determined by the TChart.Extent property. May override full extent calculation partially or fully.
  • LogicalExtent -- the extent requested by the user to be seen on the chart image. Writing to this property is the official way to change the chart extent by external code. For example, LogicalExtent := GetFullExtent is (almost) equivalent to calling the ZoomFull procedure.
  • CurrentExtent -- the extent actually displayed to the user. May differ from the LogicalExtent due to the need to reserve space for series marks, inner chart margins etc.

The value of the minimum extent cannot be greater than the value of the maximum extent. If an attempt is made to set such values an exception will be generated. To prevent exceptions, the procedure .Extent.FixTo(aBounds: TDoubleRect) can be used to set logical extents. The values in TDoubleRect are ordered in the following way: [xmin, ymin, xmax, ymax].

In order to invert the extents, the property Inverted' of the (left, bottom, etc) axis shall be set to True.

Important: Setting logical extents will work as required only if all the Margins of the chart are set to 0 (default value is 4) and Series.Marks.AutoMargins to all series in the chart is set to False (default is True). Otherwise, the requested extent will be enlarged to include also the chart's Margins as well as the series' Marks.

Extent limits

By default, TAChart allows arbitrary extents. However, for both usability and speed reasons it may be desirable to limit extent size. For example, setting the lower bound of the size may disallow extreme zoom levels, while setting the upper bound may force the user to only see a part of the very long series at any given time.

The extent can be limited with the ExtentSizeLimit property. Sub-properties MinX, MinY, UseMinX and UseMinY control the lower bounds of the extent, while sub-properties MaxX, MaxY, UseMaxX and UseMaxY control the upper bounds.

Extent limits are expressed in graph units.

Setting Proportional = true will enforce the current extent to have the shape of the plot area. This may be useful for cartographic or some math plots which require the same scale on both axes.

Linked extents

Using the TChartExtentLink component, you can ensure that the logical extents of several charts enumerated by the LinkedCharts property always stay the same. In Laz 2.1+ the component is extended to provide an additional property AlignSides which adjusts the LabelSize properties of aligned charts such that the corresponding sides of the plot area are aligned, too. (When property AlignMissingAxes is true (default) dummy axes are created for those sides having no axes so that alignment works for these sides, too).

This is useful for simulating multi-pane chart layouts. See "panes" demo for an example.

Margins

Margin is a distance reserved around the edges of rectangular region. Margins are measured in image units (usually pixels). The chart itself has two kinds of margins:

  • Internal (Margins property) -- applied after axis drawing. Are also influenced by series marks and series themselves.
  • External (MarginsExternal property) -- applied before axis drawing. Are also influenced by axis marks and arrows.

Other chart elements, such as legend, title, footer and labels, have margins, too.

Optimization notes

Calculation of CurrentExtent and actual margins is a non-trivial iterative process (see TChart.PrepareAxis code for details). Although usually fast, in complex cases it can require multiple passes through chart sources.

Graphical explanation

TAChart Margins.png

Tools

Chart tools define how the chart reacts to various user actions, primarily mouse movements and clicks. You can see examples of tools usage in the "tools" or "barseriestools" demos.

Tools are grouped in a TChartToolset component, which should be assigned to the chart's Toolset property. The same toolset can be used in several charts.

If Toolset is unassigned, for compatibility reasons a built-in toolset consisting of zoom drag and pan drag tools is used; these builtin tools can be turned off individually by setting the chart properties AllowZoom and/or AllowPanning to false, respectively (the latter is available only after Lazarus v2.2+).

In each user action, tools in the toolset are processed in order, and for each tool:

  • If Enabled=false, the tool is ignored.
  • If Shift is not equal to the current shift state, the tool is ignored.
  • Tool is requested to process the action.
  • If the tool signals that the action is handled, processing is stopped, otherwise it continues to the next tool. This way, tools with the same Shift value may be differentiated based on special activation conditions. For example, some drag tools may be configured to not activate on a simple click, leaving the click event available for other actions.
  • Finally, if no suitable tool is found, the chart's event handler is called. Note that this means that chart event handlers will only work with all tools disabled. Generally it is recommended to use tools for interactivity, chart events are left mostly for compatibility.

In your application you can create, for example, a toolbar with each button enabling the corresponding tool in the toolset and disabling all others. Alternatively, by assigning different Shift values, you can enable several tools at once.

Some tools publish the EscapeCancels property which, if set to true, cancels the tool operation if the user pressed the ESC key.

Keyboard handling in tools

Besides mouse events, some tools may react on key presses -- for example, crosshair tool with Shift = [ssCtrl] will display crosshairs when the CTRL key is pressed, without mouse buttons. Unfortunately, the chart must be focused to receive keyboard events. This means that after the user interacted with other controls on the same form, the chart stops reacting on keyboard-only events.

To prevent this, you can either call the Chart.SetFocus method, or set Chart.AutoFocus = true, which will make a chart grab the focus when the mouse moves over it.

Drawing mode

Some tools, such as zoom drag or crosshair, display moving shapes over the chart with the mouse movement.

There are two ways to display those shapes: either simply draw them over the chart, fully redrawing the chart upon each mouse movement, or use pmXor pen mode to draw and erase the shape directly from the MouseMove event handler. The former method allows to use arbitrary pen color and style, but the latter is much more efficient. Additionally, some widgetsets ignore all drawing outside the Paint event, in such a case the latter method will not work at all.

The display method is controlled by the DrawingMode property with the following values:

  • tdmXor -- use XOR method;
  • tdmNormal -- use full chart redraw;
  • tdmDefault -- use XOR method on widgetsets where it is known to work (Windows and Gtk) and full redraw on others.

Extent tools

Extent tools modify the chart's logical extent.

Zooming tools can be animated by setting AnimationSteps to a value greater then 1 and specifying an appropriate AnimationInterval in milliseconds.

In the zooming tools, adapt the LimitToExtent property to restrict zooming to the chart's full extent on all or some directions. The same property is available also in the panning tools for the corresponding purpose when the viewport is panned.

Zoom drag tool

TZoomDragTool allows the user to zoom in by drawing a rectangle with the mouse. The rectangle then becomes the new logical extent.

Restoration of the zooming to the full extent can be achieved by several actions, controlled by the RestoreExtentOn property:

  • zreDragTopLeft, zreDragTopRight, zreDragBottomLeft, zreDragBottomRight -- dragging in the specified direction,
  • zreClick -- clicking without dragging,
  • zreDifferentDrag -- dragging in a direction different from the one used to zoom in.

By default, RestoreExtentOn = [zreClick, zreDragTopLeft, zreDragTopRight, zreDragBottomLeft] which means that the full extent is restored either by clicking or by drawing a rectangle in any direction except from top-left to bottom-right.

To get a behavior compatible with earlier versions of Delphi's TeeChart, specify RestoreExtentOn = [zreDragTopLeft, zreDragTopRight, zreDragBottomLeft].

To get a behavior compatible with newer versions of TeeChart, specify RestoreExtentOn = [zreDifferentDrag].

The enumerated property RatioLimit ((zrlNone, zrlProportional, zrlFixedX, zrlFixedY) lets you restrict zooming to one of the coordinates, or makes the zooming process keep the original proportions. In such a case of restricted zooming the zoom rectangle is drawn in the fixed direction across the entire chart when the property AdjustSelection is at its default value true; otherwise the zoom rectangle would be drawn between the mouse start and end points, like in the unrestricted case.

Zoom click tool

TZoomClickTool allows the user to zoom in or out by clicking on the chart with the mouse. ZoomFactor is the scaling multiplier applied by the tool where factors below 1 represent "zoom out", and factors above represent "zoom in".

ZoomRatio allows to create a non-proportional zooming effect by specifiying the ratio of X to Y scale. In other words, the X zoom factor is given by the property ZoomFactor, the Y zoom factor is the product ZoomFactor*ZoomRatio.

  • In particular, to zoom only horizontally, the Y zoom factor must be 1, i.e. ZoomFactor*ZoomRatio = 1 or ZoomRatio = 1/ZoomFactor. For example, when your ZoomFactor for the X axis is 1.1, then ZoomRatio must be 1/1.1 = 0.909.
  • Similarly, to zoom only vertically, the X factor must be 1, i.e. ZoomFactor = 1, and you can use ZoomRatio alone to determine the Y zoom factor.
  • And finally, in the normal case, when X and Y should zoom by the same ratio, keep ZoomRatio at 1 and determine the overall zoom factor by the ZoomFactor alone.

If FixedPoint is true, the location of the mouse click is used as a fixed point for zooming, otherwise the chart image center is used instead.

Zoom mouse-wheel tool

TZoomMouseWheelTool allows the user to zoom in and out with the mouse wheel. Its properties are identical to the zoom click tool.

The chart is scaled by ZoomFactor when the user scrolls the mouse wheel up, and by 1/ZoomFactor when the user scrolls the mouse wheel down.

Pan drag tool

TPanDragTool allows the user to move the logical extent by dragging the mouse in the directions indicated by the Directions property.

Use the MinDragRadius property to distinguish dragging from clicking.

Pan click tool

TPanClickTool allows the user to move the logical extent by clicking inside a range of Margins pixels from the corresponding border of the chart image.

The panning offset is determined by the distance from the edge of the chart (the nearer to the edge, the greater). Setting Interval in milliseconds will allow to continue panning with the given interval until the mouse button is up.

Pan mouse wheel tool

TPanMouseWheelTool allows the user to move the logical extent by scrolling the mouse wheel.

The extent is moved in WheelUpDirection when the wheel is scrolled up and in the opposite direction when the wheel is scrolled down.

The movement speed is controlled by Step property.

Data tools

Data tools are linked to specific data series via the AffectedSeries property, which is a string of comma-separated series indexes. Note that indexes may change if you add or remove series. Having AffectedSeries empty means that the tools operate on every series in the chart.

When a data tool is activated, it determines the nearest point of the affected series which is located inside of the GrabRadius (in pixels).

Using the set Targets: TNearestPointTargets it can be controlled which part of a complex series must be hit:

  • nptPoint: The tool must hit the data point at (x, y).
  • nptXList: If the series' source has several x values the tool must hit any of the values in the XList.
  • nptYList: If the series' source has several y values the tool must hit any of the values in the YList.
  • nptCustom: Meant for special effects depending on the series. In case of a bar series, for example, the function GetNearestPoint is overridden to accept hits inside series bars if this option is set.

All options are on by default. For further control, most series have the same set of Targets, named ToolTargets. An option must be included in the targets of both tool and series to be active. This way tools can be shared with series reacting differently on each option. See "barseriestools" demo as an example.

For large series, the efficiency can be improved by using a sorted source, a small GrabRadius and a DistanceMode<>cdmOnlyY .

Data point drag tool

TDataPointDragTool allows the user to change data values by dragging the data point. Requires the series' data source to be a list source.

You can use the OnDrag and OnDragStart events to limit drag direction or grab area.

See "dragdrop" demo for an example.

Data point click tool

TDataPointClickTool allows you to assign an OnPointClick event handler, which will be called when the user clicks on the data point.

Data point hint tool

TDataPointHintTool displays a hint when the user moves the mouse over the data point. The hint is either equal to the point label (if UseDefaultHintText=true) or determined by calling the OnHint event handler.

By default, this tool displays a separate hint window, independent from the application hint. To use a single hint window per application, you may set UseApplicationHint=true.

Note that the application-level hint does not work in combination with modifier keys and mouse buttons, so the hint is displayed only if no buttons are pressed (i.e. Shift property must be empty when UseApplicationHint=true).

Data point crosshair tool

TDataPointCrosshairTool displays a cross-hair centered on the data point. It replaces the "reticule" found in older versions of TAChart.

Data point distance tool

TDataPointDistanceTool allows to measure and display a distance between two points on the chart.

Chart element tools

Axis click tool

This tool fires an event OnClick when the user clicks on an axis or its title. The event has the clicked axis and a set of TAxisHitTest elements as parameters:

  • ahtTitle: click on the axis title
  • ahtLine: click on the axis line (allowed tolerance defined by the tool's GrabRadius or the axis' TickLength and InnerTickLength whichever is greater).
  • ahtLabels: click into the label area of the axis. It is not distinguished whether a label is clicked or the empty space between the labels.
  • ahtAxisStart: the click on the line or label area occured in the first quarter of the axis length
  • ahtAxisCenter: the click on the line or label area occured in the center part (two quarters) of the axis length
  • ahtAxisEnd: the click on the line or label area occured in the last quarter of the axis length.

Title/footer click tool

An OnClick event is created when the user clicks on the title or footer of a chart. The event has the clicked title/footer as parameter.

Legend click tool

Generates an OnClick event when a click on the chart's legend has occured. The event has the legend as a parameter.

User defined tool

To add your own tool, either inherit from TUserDefinedTool or use it directly, assigning one or more On{After,Before}{KeyDown,KeyUp,MouseDown,MouseMove,MouseUp,MouseWheelDown,MouseWheelUp} event handlers.

Call the Handled method of the tool to indicate that no further processing of the event should be done.

Decorative elements

Title and footer

Chart title and footer are multi-line texts appearing above and below the chart correspondingly. They support various rotations and alignments, as well as the boolean WordWrap property to wrap text wider than the chart into multiple lines.

HTML

If the Lazarus version is 1.8 or newer then html entities and some html tags can be embedded into the title/footer texts for a variety of additional formatting options. This feature is turned on by switching the property TextFormat to tfHTML. In addition to header/footer texts it is available also for axis captions, axis marks, series marks and legend texts/series titles.

  • Non-standard charcters can be embedded using the corresponding html entities, i.e. as codes beginning with an ampersand (&), a standardized appreviation of the character name (or its hex or decimal unicode value), and ending with a semicolon (;). A list of all html entities can be found at http://unicode.e-workers.de/entities.php.
    Example: The text sin 2&alpha; = 2 sin &alpha; cos &alpha; is displayed as "sin 2α = 2 sin α cos α"
  • <sub>...</sub> displays the enclosed text as subscript.
    Example: H<sub>2</sub>O is shown in the chart as "H2O"
  • <sup>...</sup> displays the enclosed text as superscript.
    Example: cm<sup>2</sup> is shown in the chart as "cm2"
  • <b>...</b> displays the enclosed text with bold type face.
    Likewise, the tags <i>...</i>, <u>...</u>, <s>...;</s> can be used to format portions of the text as italic, underlined, and strike-out
    Example: Plot of <b>x</b> <i>vs.</i> <b>y</b> is shown in the chart as "Plot of x vs. y"
  • The <font>...</font> tags can be used to modify the font of the enclosed text:
    • Text color: The embedded This text is <font color="red">RED</font> displays the enclosed text in red color, i.e. like "This text is RED". Specify the color by the most typical color names or by the html hex color codes of rgb values, in the format #rrggbb or #rgb where r, g, b are hex bytes for the red, green and blue color components. The three-digit codes #rgb are equivalent to the six-digit codes #rrggbb where both digits of the same component are equal.
    • The font name can be specified by the name attribute.
    • The font size is controlled by the size attribute. It can take the values "x-small", "small", "medium", "large", "x-large", "xx-large" for font sizes 7, 10, 12, 14, 18, 24pt, respectively. Alternatively, the point or pixel size can be specified directly if "pt" or "px", respectively, is appended.
    • Example: This code adds a two-line footer in which the 2nd line is in blue, 8-pt, underlined Times New Roman:
  Chart.Foot.Text.Clear;
  Chart.Foot.Text.Add('Reference:');
  Chart.Font.Text.Add('<font name="Times New Roman" size="8pt" color="blue"><u>www.freepascal.org/</u></font>');
Warning-icon.png

Warning: It is not recommended to switch font name and font size within the same line because TAChart drawers cannot exactly align the base line of characters in different fonts and font sizes

The demo application in folder demo/html of the Lazarus installation heavily makes use of embedded HTML codes.

Legend

Chart legend is a table with each item containing an icon and a text line. Grid lines may be controlled by GridHorizontal and GridVertical properties.

Legend supports various alignments and can be located inside the chart or on the sidebar. Legend can be displayed in two or more columns by setting ColumnCount property. Setting ColumnCount to a very large value effectively creates "horizontal" legend.

Legend items are generated based on chart series which have both Active and ShowInLegend set to true. Depending on Legend.Multiplicity series can produce a single item or one item per point.

Legend items can be grouped together under sub-headers. Sub-headers are taken from GroupNames property, and each series can use Legend.GroupIndex property to indicate its group.

Legend items are sorted as following:

  • By group index, items without group (GroupIndex=-1) going first to avoid confusion with the last group.
  • By Order property, items without explicit order (Order=-1) going last.
  • By creation order of series.
  • For multiple items per series, by generation order (for standard series it is the order of points).

Sorted items are then added to the legend table in either by rows or by columns depending on the ItemFillOrder property.

Legend item text

The text of a legend item is generated by the corresponding series based on the Legend.Format property. This property is used as a first argument for the SysUtils.Format function, with the second argument containing following data items:

  • For per-series multiplicity:
    • 0: Series Title
    • 1: Series Index
  • For per-point multiplicity:

If the property TextFormat is switched to tfHTML then HTML entities and tags can be embedded for special formatting of legend texts. See HTML for details.

User-defined legend items

Arbitrary legend items can be generated by overriding OnCreate and OnDraw events of series Legend property.

Note that user-defined item count is controlled solely by <codettUserItemsCount property and does not depend on Multiplicity. Also note that GroupIndex and Order properties are actually per-item, so you can totally override entire legend from a single (perhaps fictive) series.

Arrows

Arrowheads can be drawn at the end of axis lines, constant lines, mark links, etc. It is controlled by TChartAxis.Arrow, TConstantLine.Arrow, TChartMarks.Arrow correspondingly.

Arrowhead shape is determined by Width, Length and BaseLength properties, for example:

  • Thin wedge: BaseLength = 0
  • Triangle: BaseLength = Length
  • Rhombus: BaseLength = 2 * Length
  • Inverted Triangle: BaseLength > 0, Length = 0

This image shows these arrows created for Length=10 and Width=5.TAChart Arrows.png

Transparency

Transparency property of the series represents a level of transparency from 0 (fully opaque) to 255 (fully transparent -- i.e. invisible).

Compatibility note: FPVectorial and TFPCanvas drawers currently do not support transparency because of limitations of the underlying libraries. Printer and WMF drawers can not support transparency in principle.

Optimization note: Transparency support in the LCL is rudimentary, so current TCanvas drawer implementation may be slow with many transparent series and large charts. To improve efficiency, it is recommended to use as few different transparency levels as possible and to not interleave series with different transparencies. Alternatively, use BGRABitmap as back-end, since it has faster transparency implementation.

ChartStyles

tchartstyles 200.png

TChartStyles can be employed to control the appearance of the "layers" of area, line, and bar series with multiple y values. They can also be used to colorize the regions between axis ticks in a banded way.



Marks

Marks annotate certain points of the chart. These points can be defined by a series or an axis. Typically, mark consists of some graphical element (such as an axis tick) and a text label. However, either of these elements can be omitted.

You can see examples in the "labels" demo.

Mark labels

The label text can be enclosed in a box, controlled by LabelBrush and Frame properties. The text itself is created based on the data source items, with the help of Format property. This property is used as a first argument for the SysUtils.Format function, with the second argument containing following data items:

  • 0: Y
  • 1: Y as a percentage of the Y total
  • 2: Text
  • 3: Y total
  • 4: X

Where "Y total" is the sum of all Y values for this source. Note that not all sources supply all the items above.

Some pre-defined formats can be set via the Style property.

If the source is mutli-valued, YIndex property determines which Y value is used. If YIndex = -1, a separate label is displayed for each Y value, which is useful for stacked series.

The text is rendered using the LabelFont. Note in particular that TAChart supports arbitrary font Orientation.

Mark labels are usually included in margins calculation to guarantee that all labels fit in the viewport. This behavior can be turned off by setting AutoMargins property to false.

Multi-line marks

If the mark text contains LineEnding character sequence, it is split into several lines. Lines of different length are aligned according to Alignment property.

HTML codes in marks

If the property TextFormat is switched to tfHTML then HTML entities and tags can be embedded for special formatting of marks. See HTML for details.

Mark positions and attachment

The mark position relative to the marked point is determined by the marks owner (series or axis).

Common mark properties include Distance, which measures the distance from the origin point to the attachment point in image units, and Attachment, which controls whether the attachment point is considered to be in the center or at the edge of the label box.

Additionally, basic chart series have a property MarkPositions specifying the direction of labels' offsets relative to series data points as following:

  • lmpOutside -- away from the center of the data points cloud; for TBarSeries and TAreaSeries it has a special meaning: away from the ZeroLevel defined for this series.
  • lmpPositive -- positive direction of series' Y axis
  • lmpNegative -- negative direction of series' Y axis
  • lmpInside -- towards the center of the data points cloud; for TBarSeries and TAreaSeries: towards the ZeroLevel

In Lazarus 2.0+, TBarSeries and TAreaSeries have an additional property MarkPositionCentered which allows to center the marks origins between data points and zero level. In order to place marks exactly at the center of the bars of a BarSeries or at the center of the drop line of an AreaSeries, the following properties must be changed additionally: Marks.Distance = 0, and Marks.Attachment = maCenter.

Rotation of marks

Marks can be rotated by any angle in a resolution of 1/10 degree by modifying the Orientation of their font; it is specified by the 10-fold value in degrees, i.e. the value 450 refers to an angle of 45°. 0° means horizontal orientation, the angle increases in the counter-clockwise direction.

The rotation normally occurs with respect to the center of the label. Axis and series marks additionally have a property RotationCenter to shift the center of rotation to an edge of the text:

  • raCenter -- default setting, i.e. rotation occurs around the text center
  • raLeft -- the rotation center is at the left edge of the label.
  • raRight -- the rotation center is at the right edge of the text.
  • raEdge -- ignored in case of series marks (will be replaced by raLeft). But in case of axis marks the center of rotation is automatically moved to the text start or end in order to avoid rotation of the label into the chart.

Drawers

For low-level drawing routines, TAChart uses special set of classes implementing IChartDrawer interface. This allows such features as printing charts and exporting them to SVG format.

These classes are called drawing back-ends or drawers for short.

TCanvas drawer

TCanvasDrawer is the default drawer used to display chart on TCanvas. This includes screen and various raster image formats. The image produced by this drawer is used as a reference when developing and debugging other back-ends.

TFPCanvas drawer

TFPCanvasDrawer is similar to TCanvas drawer, but based on TFPCanvas (which is a TCanvas analog implemented in the FCL instead of the LCL).

See the "nogui" demo for an example.

Although TFPCanvas and, correspondingly, TFPCanvasDrawer have a restricted implementation of some TAChart features, their important advantage is the possibility they offer of compiling an application with the nogui widgetset. This is particularly useful for Web applications, which can then generate raster chart images without any further graphic dependency, or a need to install X/Gtk/Qt on the server.

SVG drawer

TSVGDrawer produces text stream with the image of the chart in SVG format. Similarly to TFPCanvas drawer, it is independent of LCL and can be used in Web applications to generate vector charts in nogui widgetset.

See "save" demo for an example.

For this drawer, image unit is an SVG canvas unit instead of a pixel.

Note that due to the nature of SVG, there is no way to measure font dimensions, so they are approximated crudely. This may result in problems like label text not fitting in the mark rectangle, especially in browsers like Firefox that do not support textLength attribute.

OpenGL drawer

TOpenGLDrawer draws chart on the current OpenGL context. It is suitable to be used in games and other OpenGL-only applications.

OpenGL drawer expects, but does not set by itself, an orthogonal projection. See "opengl" demo for an example.

Note that, like in OpenGL itself, TOpenGLDrawer font support is extremely limited.

Printer drawer

TPrinterDrawer draws chart on the printer canvas. It does not flush the page.

Although printer canvas is a descendant of TCanvas, and so printing can be done using the default drawer, TPrinterDrawer does proper re-scaling of image coordinates according to printer vs screen DPI.

You can use this drawer to export chart to PDF format using one of the available PDF writer products.

See "print" demo for an example.

Note that this drawer is located in a separate TAChartPrint package.

AggPas drawer

TAggPasDrawer draws chart using AggPas library.

AggPas offers high-speed antialiased drawing and is included in Lazarus sources. Unfortunately, the library is currently not maintained and there are some limitations in TAChart support.

Note that this drawer is located in a separate TAChartAggPas package.

BGRABitmap drawer

TBGRADrawer draws chart using BGRABitmap library.

BGRABitmap is recently created and actively developed graphics library, offering, in particular, anti-aliasing and rich selection of gradients.

Currently BGRABitmap supports all TAChart features, but is somewhat slower then other drawing methods.

Note that this drawer is located in a separate TAChartBGRA package, which depends on external bgrabitmappack package.

FPVectorial drawer

TFPVectorialDrawer draws chart using fpvectorial library. FPVectorial offers exporting to various vector formats, including SVG, PDF, CorelDraw and even instructions for metal cutting machines.

It currently has some limitations in TAChart support, but is actively developed.

Note that this drawer is located in a separate TAChartFPVectorial package, which depends on fpvectorialpkg package.

WMF drawer

TWindowsMetafileDrawer draws chart into a Windows Metafile.

It uses WinAPI directly, and so will only work on Windows. WMF support has been added to fpvectorial which provides a cross-platform alternative to this package.

Navigation

Chart navigation consists of two parts: moving logical extent around without changing zoom factor, and visualizing the logical extent's position and size relative to the full extent.

Moving extent (but not visualizing it) is possible by using panning tools.

You can see examples in the "navigation" demo.

Scroll bars

tchartnavscrollbar 200.png

TChartNavScrollBar is a TCustomScrollBar descendant with additional Chart property referencing the chart. TChartNavScrollBar synchronizes its position with chart extent in both directions. If the logical extent is equal to or larger than the full extent, navigation scroll bar does nothing.

Setting AutoPageSize = true lets TChartNavScrollBar pick a page size proportional to the logical extent.

Note that Min and Max properties are not changed automatically. It is recommended to set Min = 0 and Max to some fairly large integer value to avoid rounding issues. Also note that TChartNavScrollBar does not automatically align or attach itself to a chart, so it can be arbitrarily positioned on the form.

Navigation panel

tchartnavpanel 200.png

TChartNavPanel component displays logical and full extent of an assigned chart as differently colored rectangles, allowing user to drag the logical extent rectangle if AllowDragNavigation = true.

If MiniMap = true, the panel additionally displays the chart series.

TChartNavPanel can have arbitrary size, but it is recommended to keep height to width proportion the same as in the assigned chart. Setting Proportional = true will enforce the same proportions even if the above condition is not met, at the cost of some wasted space on the panel.

Live View

tchartliveview 200.png

Although not a navigation tool directly, TChartLiveView is related to navigation. In the case of a long array of incoming data it provides an easy way to display a viewport with only the most recent data while older data are flowing to the left out of the viewport.

The viewport is updated whenever the full extent of the associated chart changes. However, when property Active is set to false the viewport is fixed -- this is a setting which allows the user to review older data, or change the extent while still new data are coming at the same time.

Property ViewportSize defines the width of the visible viewport, in graph units. If set to 0, the width of the current LogicalExtent is used instead.

The enumerated property ExtentY = (lveAuto, lveFull, lveLogical), finally, determines the height of the viewport:

  • lveAuto adjusts the height to the visible data range automatically. This works also when the chart contains several y axes. When a Range is defined for an axis (i.e. by setting axis.Range.Min/axis.Range.UseMin and/or axis.Range.Max/axis.Range.UseMax) the component keeps it as long as series values are within this range.
  • lveFull freezes the height to the full extent of the chart.
  • lveLogical freezes the height to the logical extent of the chart.

The methods StoreAxisRange and RestoreAxisRange are used for internal purposes because the component may change the Range parameters of an axis. Be carefull when calling these methods because they may disrupt operation of the live view if not done properly.

Additional components

Legend panel

TChartLegendPanel provides a legend which can be placed anywhere on the form. The legend is taken from the chart with is assigned to the property Chart of the LegendPanel. The chart’s own legend should be turned off.

Chart listbox

TChartListbox is a versatile legend replacement which displays an icon and the series title for each series of the chart attached to the property Chart of the listbox. But in addition to the standard legend, it also has checkboxes for each series. Unchecking a checkbox hides the associated series, checking it shows the series again. The listbox listens to changes in the associated chart and updates automatically.

The property CheckStyle can be used to switch the listbox from a checkbox-like behavior (cbsCheckbox, an arbitrary combination of series can be checked) to a radiobutton-like behavior (cbsRadioButton, only a single series can be checked). Depending on CheckStyle either a radiobutton or a checkbox state icon is displayed for each series.

Events are fired when the checkbox/radiobutton or the series title are clicked (OnCheckboxClick or OnItemClick, respectively), or when the series icon is double-clicked (OnSeriesIconDblClick). The latter event is thought to open a dialog for changing the series color, pointer style, series title etc.

The listbox items are collected in a different way than for a conventional legend. The populating process ignores the series property Legend.Visible which controls whether the series is to be shown in the legend or not. Instead of it, there is an event OnAddSeries in which the var parameter Skip should be set to true if the series passed as another argument should be excluded from the listbox. Every series is listed only with a single item, i.e. the series’ Multiplicity is ignored as well. Moveover, grouping of items is not supported either.

The order of listbox items is normally given by the order of series items in the chart's legend and thus depend on the chart's Legend.Inverted and the series' Legend.Order parameters. Moreover, items can be rearranged independently of the legend by calling the ExchangeSeries(AIndex1, AIndex2) method with the listbox indices as parameters. There is also a method Sort to sort the listbox by series titles (the sort order can be inverted by setting its optional Descending parameter, or Chart.Legend.Inverted to true. Note that the Sort method works only on the series having the default Legend.Order (-1).

Chart image list

TChartImageList collects the icons displayed for each series in the legend and can be used for imagelist-aware controls, such as treeviews, listviews or menus to show icons for each series. The icons are extracted from the chart which is assigned to the Chart property of the component. The image list is notified of changes in the chart and updates its images automatically whenever something changes with a series. The event OnPopulate is fired if the image list is rebuilt.

Note that this kind of image list is volatile, i.e. its images are not stored in the form's lfm file. Nevertheless, at runtime, it can be used as a standard image list with other images. Just add these non-series images before assigning the chart to the image list. Use the property FirstSeriesIndex to get the image index of the first series contained in the image list. Alternatively, find the image index of a specific series by calling the function ImageIndexOfSeries(series).

In Laz 2.1+ the TChartImageList can be used also at designtime. It stores only those images not assigned to a series.

Chart combobox

The TChartCombobox is an extended combobox. Depending on the property Mode (ccmPointerStyle, ccmPenStyle, ccmPenWidth, ccmBrushStyle) it is populated with names and corresponding icons for pointer style, pen style, pen width or brush style selection. Therefore, it is useful for gui elements in which the user can modify the appearance of series and other chart objects.

The combobox is not linked to a particular chart. Use the OnChange event to transfer the modified property to the series.

TeeChart compatibility

TeeChart is a standard set of charting components used by Delphi. Although TAChart does not have a goal to to be compatible with TeeChart, basic feature set and names are very similar, so simple examples may work in both libraries equivalently.

More complex features -- in particular, multi-value series, series sources, multiple axes -- are implemented differently from TeeChart. This is by design and will not change. See comparison page for more detailed info.

To assist porting of TeeChart code to the TAChart, you can use TAChartTeeChart unit. It contains class helpers adding or emulating some TeeChart-specific properties and methods.

Note that it is NOT recommended to use this unit for normal development, since the emulation is only intended to simulate the subset of features implemented in TeeChart, and may not be reliable when used in conjunction with the full set of TAChart features.

Technical details

Drawing order

Chart drawing consists of three stages:

  1. Preparation: At this stage, various internal data structures are initialized.
  2. Measurement: At this stage, the chart calculates the sizes of all elements, and optimizes them for best presentation. Optimization may require several iterations, so the measurement stage is often the heaviest one both in terms of implementation complexity and running time.
  3. Drawing: At this stage, the actual chart image is displayed.

There also exists an ordering among various chart elements:

  1. Background (using TChart.Color property).
  2. Back-wall (using TChart.BackColor property).
  3. Series and axes according to ZPosition property. For each series and axis, graphic elements are drawn before marks. Note that this protects marks against hiding by the axis/series they belong to, but not by other axes/series.
  4. Legend.
  5. Tools.

Note that ZPosition works for both 2-D and 3-D charts, so you can overlay series and axes in arbitrary order.

Coding style

Historically FPC, Lazarus and LCL sources contain a mix of coding styles, with the general rule being "be consistent with the surrounding code".

However, since TAChart has many fewer contributors, it is feasible to adopt and maintain a consistent style across all TAChart code. If you want to contribute to TAChart, please format your code accordingly. Also remember that any coding style may be violated in certain situations when the reason is good enough, but please explain that reason if you do so.

Spaces

  • No double spaces anywhere.
  • Spaces after: operations, comma, semicolon, assignment, closing parenthesis in expressions (not in function calls).
  • Spaces before: operations, assignment, opening parenthesis in expressions (not in function calls).

Lines

  • No double empty lines anywhere.
  • Empty lines between procedures, classes, unit sections. Rare empty lines inside procedure bodies to separate logical blocks.
  • Line length below 80 characters, with rare exceptions.
  • Single statement per line, except if ... then {exit|break|continue} and some rare cases of mass assignment.
  • If the line is too long, line breaks may be inserted after at the following symbols, in order of decreasing priority: keywords, opening parenthesis, opening square bracket, semicolon, comma, operation.

Indentation and blocks

  • Always two spaces, both for blocks and continuation lines.
  • begin on the same line as the control statement, end aligned with the control statement.
  • end always alone on the line. In particular, write end else begin on two lines.
  • Put then or do on a separate line to separate a complex condition from the statement body:
 while
   long condition or
   another long condition
 do
   loop body
  • Use begin/end only when necessary (i. e. not for single statements).

Comments

  • Put a license header at the beginning of every file.
  • Single-line comments everywhere except the license header and auto-generated class headers in implementation section.
  • Use only full sentences in comments, starting with a capital letter and ending with a full stop.
  • Comments should be placed before commented code, except in rare cases where a comment fits at the end of the same line.
  • Comments should only include information not evident from the source. In particular, choose meaningful procedure and argument names in preference to adding comments describing their usage.

Names

  • Constants use ALL_CAPS_WITH_UNDERSCORE, everything else use CamelCase.
  • Local variables start with a lower-case letter, everything else starts with an upper-case letter, even when FPC library disagrees (e.g. ``Math``, not ``math``).
  • Class fields start with 'F', arguments start with 'A', types start with 'T', TAChart units start with 'TA'.

Variable declarations

  • Initialize when possible.
  • Local variables after nested procedures unless used by them.
  • Group variables by type.

Classes and methods

  • Methods are grouped per-class, methods inside class are sorted alphabetically both in interface and implementation. There should be zero Code Observer warnings about 'Unsorted members'.
  • If there is a need to group methods by topic, use visibility specifiers as topic separators. In particular, group overridden methods separately from the newly introduced ones.
  • Use strict private/strict protected visibility where possible.

Hints and warnings

  • Code should compile with zero hints and warnings.
  • Silence any "unused parameter" warning with the ``Unused`` procedure from the TAChartUtils unit, or use the {%H-} Lazarus IDE directive.

Control flow

  • Use exit or raise to abort method execution in case of a violated pre-condition.
  • Use enumerators where possible.
  • Use with carefully, and only where its use significantly saves code size and in the minimal possible range.
  • Limit all procedures to 50-60 lines, and use nested procedures liberally.