The following notes have been compiled on the TeeChart configurations I’ve found useful in my applications. TeeChart is very comprehensive which can tend to make it a little complex to understand and use. I find that in most applications I need to configure the chart and series’ in run-time, and so these examples focus on that approach. The following examples are based on TeeChart Pro version 6 and I commonly use the TChart and TChartGrid components.
The information contained in this document is believed to be reliable however Creative Analytics Pty Ltd does not guarantee its completeness or accuracy.
By default TeeChart will place the values of the series in the legend, however I prefer the series names so I generally set the following two properties.
Chart.Legend.LegendStyle := lsSeries; //to display series’ names in legend Chart.Legend.ShadowSize := 0; //to remove shadow in legend Chart.Legend.Visible := True;
I find the following method useful to undo a user-invoked zoom.
Chart.UndoZoom;
It is possible to set the range of any axis (rather than have it automatic). The labels can also be set at an angle by specifying the angle in degrees.
Chart.BottomAxis.Automatic := False; Chart.BottomAxis.SetMinMax(0, 1); Chart.BottomAxis.LabelsAngle := 90;
When you add a series to a chart in run-time, there are quite a few properties that need setting, so I often use a local procedure for this and MyLine or MyBar are local variables.
Most of the properties are self explanatory, however:
procedure AddLineSeries(const Title: string); begin MyLine := TLineSeries.Create(Chart); Chart.AddSeries(MyLine); MyLine.Title := Title; MyLine.ShowInLegend := True; MyLine.Marks.Visible := False; MyLine.Pointer.Visible := True; MyLine.XValues.DateTime := True; MyLine.LinePen.Width := 2; end; procedure AddBarSeries(const Title: string); begin MyBar := TBarSeries.Create(Chart); Chart.AddSeries(MyBar); MyBar.Title := Title; MyBar.ShowInLegend := True; MyBar.Marks.Visible := False; MyBar.MultiBar := mbStacked; MyBar.BarPen.Visible := False; end;
The Pointer property relates to boxes or circles etc at each data point in addition to the series line.
MyLine.Pointer.Style is one of psRectangle, psCircle, psTriangle, psDownTriangle, psCross, psDiagCross, psStar, psDiamond, or psSmallDot
By default each series has the same pointer (!) so I use the following to set a different pointer styles for each series. I set p to zero for the first series, and then incrementing it for each series, checking that p is valid.
MyLine.Pointer.Style := TSeriesPointerStyle(p); if p > Ord(High(TSeriesPointerStyle)) then p := 0; //Check for valid p
The Y values can be sorted using the following:
MySeries.YValues.Order := loDescending; MySeries.YValues.Sort; MySeries.XValues.FillSequence;
The easiest way to add data is to using the Add method, specifying the Y value and its associated label. For example:
for i := 0 to n-1 do MyBar.Add(YData[i], MyLabel[i]);
Y values can be modified in a series as follows:
for i := 0 to n-1 do MyLine.YValue[i] := YData[i];
X labels can be modified in a series as follows:
for i := 0 to n-1 do MyLine.XLabel[i] := MyLabel[i];
Alternatively, an array of data can also be added in one hit as follows (YData is an array of Real):
for s := 0 to Chart.SeriesCount-1 do Chart.Series[s].AddArray(YData);
Copying the chart as a picture is straightforward, however if we just use a standard method such as Chart.CopyToClipboardMetafile(True) we may get a border on the top and left side (depending on the Bevel settings). So I tend to set the Bevel’s to bvNone before calling the copy to remove the partial-border.
procedure TMainForm.BtnCopyChartClick(Sender: TObject); begin Chart.BevelInner := bvNone; Chart.CopyToClipboardMetafile(True); Chart.BevelInner := bvLowered; end;
Copying the data underpinning a chart is a bit more complex, however the following seems to work well. (This requires TeeStore in uses clause).
procedure TMainForm.BtnCopyDataClick(Sender: Object);
var
Data: TSeriesDataText;
begin
Data := TSeriesDataText.Create(Chart, nil);
try
Data.IncludeLabels := True;
Data.IncludeHeader := True;
Data.IncludeIndex := False;
Data.IncludeColors := False;
Data.CopyToClipboard;
finally
Data.Free;
end;
end;
Saving and loading charts as TeeChart files has a couple of complications. The procedures are globals, and not methods of the Chart object. They require both TeeStore and TeeEdiSeri (!) in the uses clause. The application will compile with just TeeStore but will generate run-time errors if you don’t include TeeEdiSeri.
LoadChartFromFile(TCustomChart(Chart), FileName); SaveChartToFile(Chart, FileName, True);
Events and linked components such as a popup menu cannot be saved, and you must set all events to nil before saving the chart and re-assign them after the chart is loaded.
There are many things you can do with functions. What I’ve used here relates to creating a series that is the total of the other series. This requires TeeFunci in uses clause.
Create the TLineSeries as above then
MyLine.SetFunction(TAddTeeFunction.Create(Self)); for i := 0 to Chart.SeriesCount-1 do MyLine.DataSources.Add(Chart.Series[i]); MyLine.CheckDataSource; //required to update function-series!
Apparently this is the correct way of using a TeeFunction, however it does create an access violation when exiting the application. This is a bug and the work-around is to include a Chart.FreeAllSeries in the FormClose event.
Datetime based series can be plotted in TChart by setting the DateTime property of the XValues property. The datetime format of the bottom axis can be specified and then TChart will create x-axis labels according to your format with having to expressly define labels. I tend to use the AddXY() method when adding data to a timeseries chart, where X is your timestamp and Y is the value at that timestamp.
MyLine.XValues.DateTime := True; Chart.BottomAxis.DateTimeFormat := 'hh:mm'; Chart.BottomAxis.Increment := DateTimeStep[dtOneMonth]; Chart.BottomAxis.Increment := DateTimeStep[dtThirtyMinutes];
I set the Order properties because I didn't want the chart to automatically sort each series. I wasn't sure how many series' I should have, but I just used one series for 50 plus bars in the Gantt chart. You can then superimpose other series (such as a line) over the Gantt if your require this.
MyGantt := TGanttSeries.Create(Chart); Chart.AddSeries(MyGantt); MyGantt.ShowInLegend := False; MyGantt.XValues.Order := loNone; MyGantt.YValues.Order := loNone; MyGantt.ConnectingPen.Width := 2; For i := 0 to n-1 do MyGantt.AddGanttColor(StartDate[i], EndDate[i], i, Name[i], MyColour[i]);
While 3D charts look cool, they are harder to read than a 2D chart so I don’t tend to use them too much. They are a little more complex to configure (and populate with data) than a 2D series, but this is how I’ve implemented a 3D surface.
MySurface := TSurfaceSeries.Create(Chart);
Chart.AddSeries(MySurface);
Chart.DepthAxis.Visible := True;
Chart.View3DOptions.Orthogonal := False;
Chart.View3DOptions.Zoom := 90;
Chart.Chart3Dpercent := 40;
MySurface.IrregularGrid := True;
MySurface.UseColorRange := False;
MySurface.UsePalette := True;
MySurface.PaletteStyle := psPale;
MySurface.Pen.Visible := True;
MySurface.ShowInLegend := False;
for i := 0 to n-1 do
for j := 0 to m-1 do
MySurface.AddXYZ(j, MyData[i,j], i);
I have found that the grid doesn’t always populate properly and so I always call ChartGrid.RecalcDimensions once I’ve finished adding series and data.
The top left cell in the ChartGrid contains the word “Text” by default, and this can be changed by setting the global variable: TeeMsg_Text := ‘my text’. This requires the TeeConst in the uses clause.