B4J Question xChartLite : Crash while adding series

Pxs

Member
Licensed User
Hello all
I've been using this fantastic library from @klaus to plot live data.
Everything goes well if i add all the variables i need to track at the start, calling "LineChart.AddLine2" many times.
But, i now need to allow the user to add and remove tracked variables mid-run, while the graph is going...

i call drawchart on a timer, making it 'advance'
B4X:
Public Sub Ticker_tick
    Dim valuesToPlot(TrackedParameters.Size) As Double
    
    'gets the value for each tracked variable into an array of doubles
    For i=0 To TrackedParameters.Size-1
        Dim p As Parameter = TrackedParameters.Get(i)       
        valuesToPlot(i)=p.VALUE
    Next
    
    LineChart.AddLineMultiplePoints(ElapsedTime,valuesToPlot, True)
    LineChart.DrawChart
end sub

And the user can add tracked variables mid-run, like this:
B4X:
Public Sub TrackParameter(p As Parameter, parcolor As Int) As Boolean
    TrackedParameters.Add(p)
    LineChart.AddLine2(p.PNAME, parcolor, 2dip, "CIRCLE", False, parcolor)       
end sub

But it crashes on Drawchart at the next tick, with an OutOfBounds exception (bounds being the number of lines i added at the start)...

is this because the chart, once drawn with N variables, can't handle new ones that lack the same history (past values) ?
is there any way to solve it without having to add 'fake points' to the new line?
...And how can i even do that? i see LineChart.Points, but i'm not sure what's the object laying underneath it, or how to manipulate it to add a 'fake history'?

Sorry for the many questions, and thanks for your time!
 

klaus

Expert
Licensed User
Longtime User
is this because the chart, once drawn with N variables, can't handle new ones that lack the same history (past values) ?
Yes.
is there any way to solve it without having to add 'fake points' to the new line?
No.
And how can i even do that? i see LineChart.Points, but i'm not sure what's the object laying underneath it
Points is a List with all points.
Each item contains a typed variable:
B4X:
Type PointDataL (X As String, YArray() As Double, ShowTick As Boolean)
X is the a String for the x axis tick display.
YArray is an Array of Doubles wich represent the numeric values of the point for each line.
ShowTick is a Boolean which indicates if the tick will be displayed or not.
The drawing routine goes through the list of lines and draws one line after the other, by reading the corresponding Y value.
This means that all YArrays of the Points before adding the new line are too small.

or how to manipulate it to add a 'fake history'?
What you are trying to do is not possible with the XChartLite library.

Maybe it could be done with the full xChart library wich handles missing data.
Missing values are defined by the MissingDataValue property which is by default 1000000000, but can by user defined.

What is the structure of Parameter in the TrackedParameters List ?
Depending on your structure you could add MissingDataValues to the previous points, then you have no OutOfBounds.
 
Upvote 0

Pxs

Member
Licensed User
Thanks alot for the exhaustive answer!

What is the structure of Parameter in the TrackedParameters List

"Parameter" is a custom class i wrote with dozens of properties (min,max,decimals etc), but unfortunately no hystoric data to 'copy' inside the chart.

I thought about switching to the fullxChart lib, using MissingDataValue, but that would mean using the same default value for every line, and that would look a bit weird in some cases...

So, using your tips about the structure of PointDataL ,i wrote this to fill the missing values in YArray (uses the external size of a trackedparameters list and bc, a global bytecoverter var):


B4X:
'Fills hystoric data in the linechart, using the FillerValue parameter, to avoid crashes
Public Sub FillPointGaps(FillerValue As Double)
    If LineChart.IsInitialized=False Then Return
    If LineChart.Points.IsInitialized=False Or LineChart.Points.Size<1 Then Return
  
    For i=0 To  LineChart.Points.Size-1
        Dim ModdedPoint As PointDataL = LineChart.Points.Get(i)
       
        If ModdedPoint.YArray.Length < TrackedParameters.Size Then
            'mismatched size, must update Yarray
            Dim newYarray(TrackedParameters.Size) As Double
          
            'copy the other values
            bc.ArrayCopy(ModdedPoint.YArray,0,newYarray,0,ModdedPoint.YArray.Length)
          
            'fill the missing values with the filler parameter
            For j=ModdedPoint.YArray.Length To newYarray.Length-1
                newYarray(j)=FillerValue 
            Next
          
            '...and reassign Yarray
            ModdedPoint.YArray=newYarray 
        End If
    Next

End Sub

...To invoke every time i add a new line mid-run. Or to invoke once after i added multiple lines, if using the same default value is acceptable.

I still have to test a little, see how big the overhead is when the points become thousands, but seems to be working well so far.

Thanks alot for the answers and the fantastic lib!
 
Last edited:
Upvote 0
Top