B4J Library [B4X] [XUI] xChart Class and b4xlib

emexes

Expert
Licensed User

I had a run-in with Klaus a few years ago about rotating gauges, where he taught me a thing or three so I'd be pretty certain his chart class can do two lines that don't have common x-values. Worst case is we'd have to merge (x1, y1) and (x2, y2) into (x, y1, y2), which would be mildly painful but not impossible.
 

Mark Read

Well-Known Member
Licensed User
Longtime User
Worst case is we'd have to merge (x1, y1) and (x2, y2) into (x, y1, y2), which would be mildly painful but not impossible.
This is a good idea. The data is loaded backwards, last value first. If I join the two datasets together and assume the time is from the first then it would work. Temperatures are not going to change very much in 15 minutes, unless the house burns down - then I don't need the values any more!

With B4J.

The weather data you can see here.
 

emexes

Expert
Licensed User
With B4J.

I would imagine that if you

start with a blank chart,
.AddYXLine("Inside",...) 'is LineIndex = 0?
.AddYXLine("Outside",...) 'is LineIndex = 1?

For I = 0 to NumInsideTemperatures - 1
.AddYXPoint(0, InsideTimeStamp(I), InsideTemperature(I))

For I = 0 to NumOutsideTemperatures - 1
.AddYXPoint(1, OutsideTimeStamp(I), OutsideTemperature(I))

and then do an update redraw

you might be 90% of the way to what you're looking for.

 

emexes

Expert
Licensed User
For I = 0 to NumInsideTemperatures - 1
.AddYXPoint(0, InsideTimeStamp(I), InsideTemperature(I))

For I = 0 to NumOutsideTemperatures - 1
.AddYXPoint(1, OutsideTimeStamp(I), OutsideTemperature(I))

I doubt that it matters whether your points are ordered in ascending or descending time... at worst, if you have super-fast eyes, you might see the lines being drawn backwards, but the end result should be the same.
 

klaus

Expert
Licensed User
Longtime User
How are your data saved and how do or can you synchronize the data for the two lines with different time stamps ?
You can display several lines, but you need to synchronize somehow the X axis ticks.
You cannot have two X axis scales.
If you have missing data values you can set their value to the MissingDataValue property.
The default value = 1000000000, but you can set your own value.
 

Mark Read

Well-Known Member
Licensed User
Longtime User
I doubt that it matters whether your points are ordered in ascending or descending time.
Thats not what I meant. In the weather station cloud I have 103000 datapoints. I can get the last x number of points from the cloud up to 8000. So the last 96 would be 24 hours for example. The json reply is cronological, so the last point is the newest.

I do not want 2 x-axes, I need only one but two sets of data. One point might be (14.10.2022 10:31:30, 15.5) and the corresponding point (14.10.2022 10:31:41, 35.2). The x-coordinate is a string and the y-coordinate a double. So for every point on one line, there is no exact point for the same time on the second line.

If I plot them, they will not be above one another but close enough to show the relationship between outside temperature and heating.
 

emexes

Expert
Licensed User
Are we in the ballpark? :



B4X:
Sub FirstDraft
        
    xChart1.ChartType = "YX_CHART"

    xChart1.Title = "Inside Outside Temperatures"
    xChart1.XAxisName = "Time of Day"
    xChart1.YAxisName = "°C"
    
    xChart1.XScaleMinValue = 0
    xChart1.XScaleMaxValue = 24
    xChart1.NbXIntervals = 12

    xChart1.YScaleMinValue = -5
    xChart1.YScaleMaxValue = 40
    xChart1.NbYIntervals = 9

    xChart1.AddYXLine("Inside", xui.Color_Red, 2Dip)
    xChart1.AddYXLine("Outside", xui.Color_Blue, 2Dip)
    
    For I = Rnd(0, 50) To Rnd(150, 200)
        xChart1.AddYXPoint(0, (I + Rnd(0, 10) / 10) / 201 * 24, 15 + Rnd(0, 10))
    Next
    
    For I = Rnd(0, 50) To Rnd(150, 200)
        xChart1.AddYXPoint(1, (I + Rnd(0, 10) / 10) / 201 * 24, 5 + Rnd(0, 10))
    Next
    
    xChart1.DrawChart
    
End Sub
 
Last edited:

Mark Read

Well-Known Member
Licensed User
Longtime User

Yes!
 

Mark Read

Well-Known Member
Licensed User
Longtime User
So, couldn't you not use a same time stamp for both like 14.10.2022 10:31 without the seconds ?

Sorry Klaus, the values are up to 15 minutes apart but even that would not make much difference. I just gave a (bad) example.
 

klaus

Expert
Licensed User
Longtime User
How do you get the values for the two lines ?
What is the time sampling of these data with up to 15 minutes time delay.
Is the sampling rate the same for both ?
Are there data in between ?
Could you admit a mean time stamp for both?
How do you imagine filling the chart ?
Many questions, but i need to understand.

YXChart structure is different from the other chart types, you add points, each point has an X and a Y coordinate with numerical values and the X axis is scaled.
This means that the X position of a point in the chart is proportional to the X values.

In the other charts you add lines, the X axis has String values and it is not scaled.
The width of the successive points is always the same independent of any value difference.

What kind of X axis scale do you want to see?

If i understand well what you want to do, you expect having the X axis as a scaled time axis but with date and time display.
X axis as a scaled time axis, the YXChart type was made for this.
but with date and time display, this cannot be done with the xChart class.

You can only have numerical values on the x axis like emexes shows it.
 

emexes

Expert
Licensed User
Update as promised (no joke).



B4X:
Sub ThirdDraft
    
    '*** MAKE THE DATA ***
    
    Dim FirstInsideTime As Int = Rnd(200, 220)
    Dim LastInsideTime As Int = Rnd(320, 336)
    
    Dim FirstOutsideTime As Int = Rnd(200, 230)
    Dim LastOutsideTime As Int = Rnd(320, 336)
    
    Dim NumInsidePoints As Int = LastInsideTime - FirstInsideTime
    Dim NumOutsidePoints As Int = LastOutsideTime - FirstOutsideTime
    
    Dim InsideTime(NumInsidePoints) As Double
    Dim InsideTemperature(NumInsidePoints) As Float
    
    For I = 0 To NumInsidePoints - 1
        InsideTime(I) = FirstInsideTime + I + Rnd(0, 15) / 60
        InsideTemperature(I) = 20 + Sin(I / 4) * 6 + Rnd(0, 4)
    Next

    Dim OutsideTime(NumOutsidePoints) As Double
    Dim OutsideTemperature(NumOutsidePoints) As Float
    
    For I = 0 To NumOutsidePoints - 1
        OutsideTime(I) = FirstOutsideTime + I + Rnd(0, 15) / 60
        OutsideTemperature(I) = 5 + Sin(I / 4 + 1) * 6 + Rnd(0, 4) + Sin(I / 40 + 1) * 6
    Next

    '*** PLOT THE DATA ***s
    
    xChart1.ChartType = "YX_CHART"

    xChart1.Title = "Inside Outside Temperatures"
    xChart1.XAxisName = "Hours since last midnight"
    xChart1.YAxisName = "Temperature °C"

    xChart1.XScaleMinValue = 0
    xChart1.XScaleMaxValue = 24
    xChart1.NbXIntervals = 12

    xChart1.YScaleMinValue = -5
    xChart1.YScaleMaxValue = 40
    xChart1.NbYIntervals = 9

    xChart1.AddYXLine("Inside", xui.Color_Red, 2Dip)
    xChart1.AddYXLine("Outside", xui.Color_Blue, 2Dip)
    
    Dim MinTime As Double = InsideTime(0)
    Dim MaxTime As Double = InsideTime(0)
    
    For I = 0 To NumInsidePoints - 1
        If InsideTime(I) < MinTime Then
            MinTime = InsideTime(I)
        else if InsideTime(I) > MaxTime Then
            MaxTime = InsideTime(I)
        End If
    Next
    
    For I = 0 To NumOutsidePoints - 1
        If OutsideTime(I) < MinTime Then
            MinTime = OutsideTime(I)
        else if OutsideTime(I) > MaxTime Then
            MaxTime = OutsideTime(I)
        End If
    Next

    Dim TimeOffset As Double = Floor(MaxTime / 24) * 24    'time value of most recent midnight
    
    xChart1.XScaleMinValue = Floor((MinTime - TimeOffset) / 24) * 24
    xChart1.XScaleMaxValue = Ceil((MaxTime - TimeOffset) / 24) * 24

    For I = 0 To NumInsidePoints - 1
        xChart1.AddYXPoint(0, InsideTime(I) - TimeOffset, InsideTemperature(I))
    Next
    
    For I = 0 To NumOutsidePoints - 1
        xChart1.AddYXPoint(1, OutsideTime(I) - TimeOffset, OutsideTemperature(I))
    Next
    
    xChart1.DrawChart

End Sub
 
Last edited:

emexes

Expert
Licensed User
If you have missing data values you can set their value to the MissingDataValue property.
The default value = 1000000000, but you can set your own value.

That could be a neat trick to remember in case ever need to merge two arrays (x1, y1) and (x2, y2) data into one longer array of (x, y1, y2).
 
Last edited:

emexes

Expert
Licensed User
One point might be (14.10.2022 10:31:30, 15.5) and the corresponding point (14.10.2022 10:31:41, 35.2). The x-coordinate is a string and the y-coordinate a double.

The x-coordinate is conceptually a DateTime tick (ie Long) but it's formatted to be human readable. The stringiness of it has led this discussion on a wild goose chase.
 

Mark Read

Well-Known Member
Licensed User
Longtime User
Sorry to take a while to get back to you Klaus.

I have a weather station outside which sends data every 15 minutes to Thingspeak Cloud, where it is timestamped on arrival. I am adding a second arduino with sensor to my heating and will also upload to Thingspeak but a different channel. In order to get data for the two lines, I can post a request (http) and get a json answer iwth all the data for 1 day or week or month, up to 8000 points. I send two requests and parse them to get data for the two lines but the x-values (date and time) will never be the same. I want to draw both sets of data on one chart to compare outside and heating temperatures.

Sampling rate is the same for both: every 15 minutes

No data in between.

Mean Time: Possible

How do you imagine filling the chart ? Sorry I don't understand the question.

What I would like is :



But with a seond line. This is a single line chart showing the data for 1 day, could also be a week or month. In this example there are 96 data points.
 

klaus

Expert
Licensed User
Longtime User
If i understand well, the time stamp difference between the two data is +/- 7.5 minutes.
Two suggestions:
1. Use one time stamp for both.
2. Still use one time stamp for both, and calculate the temperature difference during the time difference, assuming that the temperature evolution is linear.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…