Mega Code Archive

 
Categories / Delphi / Graphic
 

Notes on Using TeeChart

Title: Notes on Using TeeChart Question: I worked with TeeChart... and thought this article should be in this archive here at D3K ! Answer: Notes on Using TeeChart June 2003 - Phil Sheppard - Creative Analytics Pty Ltd The following notes have been compiled on the TeeChart configurations Ive 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. Configuring the Chart 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; Configuring an Axis 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; Adding and Configuring a Series 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: The Marks property relates to coloured rectangles with a text string near to each Series point. The pointer property relates to boxes or circles etc at each data point in addition to the series line The XValues.DateTime is used for timeseries data (see below). The MultiBar property of the TBarSeries is used to specify whether the series is stacked on another bar series or simply drawn beside. The BarPen.Visible property specifies whether a line is drawn around each bar. 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; Adding Data to a Series 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 to the Clipboard Copying the chart as a picture is straightforward, however if we just use a standard method such as Chart.CopyToClipboardMetafile(True)style='"Courier New"' we may get a border on the top and left side (depending on the Bevel settings). So I tend to set the Bevels 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 tee Files 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 dont 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. Functions There are many things you can do with functions. What Ive 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. Timeseries Charts Datetime based series can be plotted in TChart by setting the DateTime property of the style='font-family:"Courier New"'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.style='font-family:"Courier New"' MyLine.XValues.DateTime := True; Chart.BottomAxis.DateTimeFormat := 'hh:mm'; Chart.BottomAxis.Increment := DateTimeStep[dtOneMonth]; Chart.BottomAxis.Increment := DateTimeStep[dtThirtyMinutes]; Gantt Charts 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]); 3-D Charts While 3D charts look cool, they are harder to read than a 2D chart so I dont 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 Ive 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); TChartGrid I have found that the grid doesnt always populate properly and so I always call ChartGrid.RecalcDimensions once Ive 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: style='font-family:"Courier New"'TeeMsg_Text := my text. This requires the TeeConst in the uses clause.