Axis limits
Data series
Plot markers
Plot drawing
Plot print
Real Time Graphing
Solve compile problems in Borland C++ Builder 3
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.
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.
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 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.
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.
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.
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.
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