The chapter discusses Strip Charts, RealTime Charts with Gigasoft's charting components.
Stripcharts and real-time charts can be implemented in a variety of ways. Also, all
ProEssentials graph controls can be used in real-time high speed updating scenarios. Real-time is the repeated process of changing the graph control's data and/or
properties and refreshing the image.
Graph Control for Strip Charts
The Graph component will likely
be the most common component used in a real-time scenario. It is also designed
to be the easiest to implement. The properties AppendYData
can be used to quickly and easily implement a strip chart. A strip chart
is one that as you feed data, each new feed shifts the chart to the left
or right. The direction of the shift is controlled with the property AppendToEnd.
Below is some example code which will produce a strip chart. The first
section is used to initialize the component, preparing for real-time operation.
The second section is used in a timer or other repeated event. WinForm,
VCL, and C/C++ code will be similar in structure. The example code included
with ProEssentials also has examples of real-time implementations. Within
the demo and example projects see examples 017,
020, scientific examples 115, 116, 117, 117, and 119 for working stripchart and realtime charts.
Initialization of Strip Chart
Pego1.PrepareImages = True
Pego1.Subsets = 2
Pego1.Points = 200
Pego1.PointsToGraph = 20
Pego1.PointsToGraphInit = PEPTGI_LASTPOINTS
'Show Last Points Initially
'** Manually configure scales **'
Pego1.ManualMaxY = 100
Pego1.ManualMinY = 1
'** Set various properties commonly used in real-time **'
Pego1.NoStackedData = True
Pego1.AllowHistogram = False
Pego1.FocalRect = False
'** Needed to allocate point labels so append logic works **'
'** Set last point label, 199 = Points - 1 **'
Pego1.PointLabels(199) = ""
'** Clear out first four data points **'
Pego1.YData(0, 0) = 0
Pego1.YData(0, 1) = 0
Pego1.YData(0, 2) = 0
Pego1.YData(0, 3) = 0
'** Start Timer **'
Timer1.Enabled = True
Strip Chart Timer Section
Dim CurrentTime As String
'** new point label **'
CurrentTime = Time$ ' Time$ is a function to return the time as a string
'** new YData, we need to prepare two pieces of data **'
ReDim NewData(2) As Single
NewData(0) = (Rnd * 20) + 2
NewData(1) = (Rnd * 40) + 60
'** transfer new point label **'
Call PEvset(Pego1.hObject, PEP_szaAPPENDPOINTLABELDATA,
ByVal CurrentTime, 1)
'** transfer new YData **'
'** this will also update and view new image **'
Call PEvset(Pego1.hObject, PEP_faAPPENDYDATA,
Strip Chart Example Code Explanation
Setting PrepareImages to TRUE is
important and gives you flicker-free output.
Next, Subsets and Points
define how much data the component will hold, PointsToGraph
is set to 20 and controls how much data the user will see. There will
be a horizontal scrollbar to pan left and right through data. PointsToGraphInit
controls whether the first 20 or last 20 points are initially displayed.
Next, the graph's y axis is manually configured. This is because during
the component's real-time operation, it will not automatically adjust the
scales. However, if you do want the component's scale to adjust during real-time,
this is possible and is discussed later. ManualMaxDataString
and ManualMaxPointLabel are
used to set a string which would represent the largest string in either
the table or PointLabels respectively. This is used to reserve space during
the component's image construction process to prevent overlapping text.
Next, a few properties are set which are recommended for real-time operation.
Next, the last PointLabel element
is set to a null string. This allocates memory for all PointLabels and
this is necessary for the append logic to work correctly. If memory is
not pre-allocated, there will be nothing to shift.
Next, the first four default data points are set to zero. The default
NullDataValue is zero so these lines
of code essentially empty the graph of all valid data. Thus starting with
an empty chart.
Finally, the component is initialized with PEreinitialize
and PEresetimage, and the timer
mechanism is started.
Within the timer event, we prepare new PointLabels and YData to append
to the chart.
CurrentTime is a string which will show below the new data value. You
use PEvset and AppendPointLabelData
to pass the address of a null-terminated string to append to the PointLabels
property array. If more than one string is going to be appended, they
need to all exist in the one null-terminated string, but be delimited
with the tab character. Usually you will just pass one string at a time.
Note that ByVal is the mechanism in Visual Basic used to de-reference
a string handle and provide the actual pointer to the string data. In
Delphi you would use the @ operator to provide the address of the string,
and in C/C++ the & operator.
New YData is also prepared and also passed
by reference. NewData(0) is Visual Basic's method of passing the data
by reference. Since this graph component has 2 subsets, and we will be updating
one sample's worth of data, 2 pieces of data are prepared for appending
to the YData array. Note that the
last argument in the PEvset call
is 1. This stands for 1 new sample. Since the control knows how many subsets
are included in the graph component (2), it will automatically look for 2 pieces
of data. This is different in how PEvset
is used with the non-appending type properties such as YData. If
more than one sample's worth of data is being appended, you still format
the data in a single dimension array. In this case you will prepare all
of the first subset's data, followed by the second subset's data and so
on. Using PEvset with AppendYData
also has a special function of resetting and updating the image. Because
of this, you will always use AppendYData after AppendPointLabelData.
If you need the graph to update the y axis while in a real-time operation,
you have to call PEactions = 0, or PEreinitialize, PEresetimage, and InvalidateRect
at the end of the timer event.
All other components for Real-Time Strip Charts
ProEssentials includes appending type properties for all the data type
arrays. For example, AppendXData
is the property you would use to append data to the XData property
array. There are also double precision versions of these properties like
append PointColors if per
point coloring is being implemented.
Scientific Graph controls are implemented in a real-time operation similarly
to the Graph control. You will just use slightly different properties to
pass data and you will have to call PEreinitialize, PEresetimage, and
InvalidateRect (Refresh) at the end of the timer event.
The example code included with ProEssentials includes several Scientific
Graph Control strip chart and real-time examples. Refer to these for more information on how to
implement strip charts with the Scientific Graph. Examples
115, 116, 117, 118, and 119.
We've added example code showing another variation of real-time charting.
Refer to examples 020 within the
demo and example projects to see this realtime first hand.
This function is designed to partially update an image, in other words,
not having to update all data points. It contains two arguments which
define the first data point, and quantity of data points to update. The
developer will adjust/add a varying amount of data to the YData
and possibly XData property arrays. After changing this data, the
developer calls PEpartialresetimage
with the starting point index, and the number of data-point indices adjusted.
All subsets need to redraw the same number of points. This function will
then invoke code to draw only those point indices selected to a cached
memory device context (DC). So, when using PEpartialresetimage,
CacheBmp must be set to TRUE in the
control's initial initialization.
Two common real-time strip chart scenarios will use this function. The first is
when you have a large data set, (thousands of data points), and you want
to quickly add a data point at the end of existing data. This means that
Points is being set to a larger size than actually being currently
shown in the image. The developer is thus padding the unused data indices
with the NullDataValue or leaving
them zero if the default null data value is not changed. This type of
real-time update is great for a quick addition, however, the grid is not
updated. Occasionally, a full call to PEresetimage
is needed to update all data points along with the grid and other non-data
example 020 for an actual realtime implementation.
Another scenario is if you want to continuously plot to the grid area,
and preserve everything drawn. This will essentially let you produce a
chart with millions of plotted data values, but actually, only plotting
1 or more during any one update. For example, the developer can set the
chart up to contain only two data points. Upon a timed event, the developer
updates the two data points and calls PEpartialresetimage
to update the chart's current image. Note that when attempting to update
a currently drawn line segment, you will have to include the last point
of the last update as the first point of the current update. This will
continue the line from the last point drawn. Also note that when the control
gets a WM_PAINT event caused by the operating system, your image may be
reset and start over from an empty graph. Based on the intended use, this
may or may-not be a problem. If it is, you can increase the Points
property and redraw this larger amount of points, then revert back to
just updating one line segement per update.
3D Scientific Graph Control and 3D strip charts and realtime charting.
The PEreconstruct3Dpolygons function to aid in 3D real-time strip charts. See example 410, 411, and 412 within the demo. These examples are similar to 017 or 115 discussed above.