SGraph selected notes

Axis limits
Data series
Plot markers
Plot drawing
Plot print
Real Time Graphing
Solve compile problems in Borland C++ Builder 3

Sgraph description

Axis limits

The Tsp_Axis has properties and method to control axis limits.

property Min : double
Min is the lowest value an axis
property Max : double
Max is the highest value an axis
procedure SetMinMax(m1,m2:double);
Used to set Min and Max at once. The minimal value of the m1 and  m2 will be assigned to the  Min and maximal to the Max.
procedure MoveMinMax(aDelta:double);
Used to change Min and Max on value of aDelta with 'frozen' ticks position.The aim is to permit smooth scroll of plot, without ticks jumps. Procedure is especially useful for the program which emulates transient recorder.
property AutoMin : boolean default False
The AutoMin property controls if axis will adjust the Min value automatically to based on the minimum value of its associated data series.
property AutoMax : boolean
The AutoMax property controls if axis will adjust the Max value automatically to based on the maximum value of its associated data series.

There are some features. Suppose we try to set new value to the Min, while this value greater then current Max, this value will be assigned to the Max instead of Min. If then you set new value to Max you will have incorrect Min value (Min value did not changed). To avoid this problem, use SetMinMax method, if you want to assign arbitrary values to the Min and Max at once. Note, changing properties Min or/and Max will reset the AutoMin or/and AutoMax to False.

The axis limits also changed after zooming or panning of the plot by the mouse (z&p). This processes did not change AutoMin and AutoMax. Shift+Click on the plot will restore limits after z&p if properties Min and Max was not changed by another way after z&p.

Data series

There are no many kinds of data series. But you can write it yourself, and they will match your needs. Inherit it from Tsp_DataSeries component and implement 1 procedure and 4 functions:
· procedure Draw; virtual;
· function GetXMin(var V:double):boolean; virtual;
· function GetXMax(var V:double):boolean; virtual;
· function GetYMin(var V:double):boolean; virtual;
· function GetYMax(var V:double):boolean; virtual;
Draw procedure called by parent plot to draw series. In this procedure you place code which
draws your data on plot DCanvas. Get?Min and Get?Max functions are used by parent plot during auto scaling process. In this procedures you can find minimal or maximal value of your data and assign it to variable V. Function must return True if they set valid value to the V, otherwise they must return False. For example if data series has no data you cannot set valid value to the V.
There is also procedure which is reserved to draw Legends of the plot series.
procedure DrawLegendMarker(const LCanvas:TCanvas, MR:TRect); virtual;
It should paints series marker (for example line and point marker image) on LCanvas using rectangle  MR. Of course you should also implement data storage wich are drawn by series. See sgr_data.pas and sgr_def.hlp for more details.
If you agree to store data in variant array there is more simple way. Derive Data Series from Ts_XYDataSeries. See how Tsp_XYLine was derived from Tsp_XYDataSeries in sgr_data.pas. At last, simplest way is to use Tsp_XYLine. In this case Draw procedure paints lines between data points and/or points markers.

Plot markers

Some times I need mark visually points on plot. First I use OnDrawField and OnDrawEnd handlers, but now I implements plot marker. There are Tsp_LineMarker and Tsp_ImageMarker in the current version. Tsp_LineMarker draws "infinite" vertical or horizontal line. For example to show X=0 and Y=0 lines as quasi axis you can create 2 LineMarker   vertical and horizontal with Position=0.0. In this case you will have to line on plot field. One from top to bottom at X=0 and second from left to right at Y=0.   Tsp_ImageMarker can be used to mark point and so on. Notice one exotic way to use it. One guy wrote me that he used plot to draw trajectory of flight and ask about map. It can be done with Tsp_ImageMarker, place it and assign Picture property metafile with map image, set WhenDraw property=dmBeforeSeries and you will have background image which is scaled and moved same as data.

Plot drawing

Plot has 2 areas - Field and Around Area. Field is area surrounded by 4 axis. The data series are painted on the Field. The axis caption, ticks and ticks label are painted on the Around Area.

plot_img.gif (3965 bytes)

Sequence of draw operations to create plot image
· Fill Around Area by Color 
· Draw axis
· IntersectClipRect(DCanvas, FieldRect)
· Fill Field by FieldColor
· Process OnFieldDraw event
· Draw Grids
· Draw plot markers with WhenDraw=dmBeforeSeries
· Draw series
· Draw plot markers with WhenDraw=dmAfterSeries
· RestoreClipRect
· Process OnDrawEnd event
· Draw border
during operation selected by color custom draw procedures are called.

Custom draw rules
This rules apply for Data Series Draw procedure and OnFieldDraw, OnDrawEnd and OnDrawCustomPoint event handlers. They must
· use DCanvas to draw
· use DWidth as plot width, DHeight as plot height
· do not change MapMode or Clipping Region of the DCanvas
· do not change plot Font property

Custom draw tips
Use FieldRect if you need to know Field position on the plot image.
Use P2V and V2P axis methods to convert position to value and back.

Plot print

There is no special print method of component. You can draw plot on the printer canvas using method DrawPlot(CC : TCanvas; W, H : integer) and of course you would create user interface to control how to print plot. But there is special dialog form (sgr_sprint.pas) in sgr_demo program. You can look it as example of plot printing through metafile and simple preview. Note that it is important to set true-type font to Font property for correct print scaling.

Real Time Graphing

The Tsp_XYPlot and Tsp_XYLine have special features to help data graphing in real time or to suppress flickering. This features are:
· property Tsp_XYPlot.BufferedDisplay
· procedure Tsp_XYDataSeries.AddXYArrays(pX,pY:pointer; n:integer);
· property Tsp_XYDataSeries.LockInvalidate
· procedure Tsp_XYLine.QuickAddXY(aX,aY:double);

If data rate is relatively slow (<10 1/sec) it simplest way set BufferedDisplay=True to draw plot throughout internal buffer and have flicker free paint. To add data point by point and immediately reflect changes on screen use procedure AddXY(aX,aY:double). This procedure add values at the end of series data and update Plot (not invalidate but update!).

If it is not enough, then use procedure AddXYArrays(pX,pY:pointer; n:integer) to add data by portion of several (n) points. In this case the plot will invalidate only one time for several (n) points. Notice, there is also property LockInvalidate, set it to True and use AddXY several times and then set LockInvalidate to  False.

At last, to have maximum visualisation data rate, use procedure QuickAddXY(aX,aY:double). It adds values at end of data storage like AddXY, but does not spend time to update Plot, instead of that it directly draw next line segment or/and last point, but because of that the AutoMin and AutoMax are ignored.

Solve compile problems in Borland C++ Builder 3

Jimmy J. C. Wu (Taiwan)  wrote to me this note

I use SGraph component in Borland C++ Builder 3 and it was something occured as I compiled the program I made :
  [C++Error] sgr_scale.hpp(152): Parameter mismatch in read access specifier of property OX.
  [C++Error] sgr_scale.hpp(153): Parameter mismatch in read access specifier of property OY.
  I tried to modify the hpp file that compiler produced and I find that OX and OY were taken as integer in this file. But I took a look at your pascal file that data type of OX and OY were long integer. I modify the data type of OX and OY from "int" to "long" in the hpp file and that component worked very well. I found this solution and provided you a reference to solve the problem in Borland C++ Builder.

Sergei. P. Pod'yachev. Novosibirsk, Russia.
WWW : www.iae.nsk.su/~lab12/pod

List100