B4J Question [SOLVED][xChart] Zig-Zag Chart

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi All,

seeking help on creating a pulse zig-zag chart like image below using xChart.

The data is stored in a list with maps containing level 0 or 1 (y-axis) and the duration (x-axis).

1746897007820.png


Test code snippet example using linechart but the result shows only spikes and not rectangle pulses with duration.
B4X:
Private Sub DrawChart(pulses As List)
    If pulses.IsInitialized = False Or pulses.Size = 0 Then Return

    Log("[DrawChart] Pulses size=" & pulses.Size)
    
    Dim time As Int = 0
    Dim level As Int = 0  ' 0 = low, 1 = high
    Dim duration As Int
    
    Chart.ClearData
    Chart.XMaxValue = FrameDuration
    
    'Logic waveform line (square wave style)
    Chart.AddLine("IR Logic", xui.Color_Blue)
    
    'A pulse has 3 lines with height 1 or 0 and width duration d.
    '1 +--+  +-+
    '  |  |  | |
    '  |  |  | |
    '0 +  +--+ +
    '-> d  d  d
    '->   time 
    
    '1 = vert-line    from x-axis time to y-axis 0 or 1
    '2 = hor-line    from y-axis 0 or 1 to x-axis time+duration
    '3 = ver-line    from x-axis time+duration to y-axis 0
    'time is the last position of the previous pulse
    For Each pulse As Map In pulses
        ' Get the pulse level and duration, 
        level = pulse.get("level").As(Int)
        duration = pulse.get("duration").As(Int)
        'Log($"[DrawChart] level=${level},duration=${duration},time=${time}"$)

        '1 = vert-line x-axis last time, y-axis 0 or 1
        Chart.AddLinePointData(time, level, True)
        
        'Increase the time
        time = time + duration
        
        '2 = hor-line x-axis new time, y-axis 0 or 1
        Chart.AddLinePointData(time, level, True)
        
        '3 = vert-line x-axis new time, y-axis 0
        Chart.AddLinePointData(time, 0, True)

        Log($"[DrawChart] level=${level},duration=${duration},time=${time}"$)
    Next
       Log("[DrawChart] Lines added")
    
    Chart.DrawChart
    Log("[DrawChart] DONE")
End Sub
 

Attachments

  • IRLogicAnalyzer.zip
    5.3 KB · Views: 58
Last edited:

Daestrum

Expert
Licensed User
Longtime User
Not used chart, but maybe lastl line should be
B4X:
Chart.AddLinePointData(time, 0, True)
instead of
B4X:
Chart.AddLinePointData(0, 0, True)
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Thanks. Scribbled a quick-and-dirty B4XCanvas solution with the previous data shared, but want to achieve with xChart.

1746954465149.png


B4X:
private Sub DrawChartCanvas
    Dim cvs As B4XCanvas
    Dim path As B4XPath
    Dim fnt As B4XFont
    Dim pulses As List = CreateTestPulses

    Dim totalDuration As Double = FrameDuration
    Dim scaleX As Float = PaneChart.Width / totalDuration
    Dim yHigh As Float = PaneChart.Height * 0.3
    Dim yLow As Float = PaneChart.Height
    Dim x As Float = 0

    Log($"[DrawChartCanvas] pulses=${pulses.size}"$)
    
    Chart.Visible = False

    cvs.Initialize(PaneChart)
    cvs.ClearRect(cvs.TargetRect)

    fnt = xui.CreateDefaultBoldFont(12)

    path.Initialize(0, yLow)
    'Loop over the pulses and create 3 lines
    Dim cnt As Int = 0
    For Each pulse As Map In pulses
        cnt = cnt + 1
        Dim level As Int = pulse.Get("level")
        Dim duration As Double = pulse.Get("duration")
        Log($"[DrawChartCanvas] pulse=${cnt},level=${level},duration=${duration}"$)

        cvs.DrawTextRotated($"${NumberFormat(duration,0,0)}"$,x + ((duration*scaleX)/2),100,fnt,xui.Color_Black,"LEFT", 90)

        Dim y As Float = IIf(level = 1, yHigh, yLow)
        'Line 1 = vert
        path.LineTo(x, y)
        'Increase x
        x = x + duration * scaleX
        'Line 2 = hor
        path.LineTo(x, y)
        'Line 3 = vert
        path.LineTo(x,0)
        
    Next
    x = PaneChart.Width
    y = PaneChart.Height
    path.LineTo(x, y)

    'Go back to start
    cvs.ClipPath(path)

    cvs.DrawPath(path, xui.Color_Green, True, 2dip)
    cvs.Invalidate
End Sub
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
You cannot make this kind of chart with the xChart library.
LINE charts do not have a proportional X scale, all points are equally spaced.
Only the XYChart type has a proportional X scale.
I tried to make your chart with an XYChart, but it does not look as you expect it.

1746966021316.png


The X scale is not what you want, and there is no way to fill the pulses.

It would be easier to make your own specific chart for this.
 

Attachments

  • IRLogicAnalyzer1.zip
    5.4 KB · Views: 62
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi Klaus,

thanks for your help and demo project = Appreciated.
Will explore further, because xChart is a great library ... else indeed will develop B4XCanvas based zig-zag-chart.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
I would have done something like this with B4XCanvas.

1747208672077.png


It is a CustomView, tested with B4J and B4A.
Advantages:
It is specific to your particular case and you have full control on it.
Only 320 lines of code versus 9100 lines of code of the xChart library.
 

Attachments

  • XZigZagChartDemo.zip
    59.9 KB · Views: 48
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi Klaus,

thanks for this CustomView (xZigZagChart) = Appreciated ... Let me share why such a chart.

Background
Based on a request from a factory: Working on a solution to enable controlling some old equipment via B4A and Bluetooth + IR. This equipment is currently controlled with old IR remote controls which are end-of-live (. There is no further info available. The equipment can not be replaced for now.
So there is a need to reverse-engineer to understand the IR protocol & commands (deep-dive) - which has been analyzed as a PULSE-DISTANCE protocol.
Whilst developing the IRRemoteEx library further, thought this could be used to create a custom IRLogicAnalyzer ... of course I know that there are solutions out on the market, but developing an custom solution gives more flexibility and ... is fun (thanks to B4X and its community).

Status
The IRLogicAnalyzer uses an Arduino/ESP (B4R) to capture IR signals and a PC/Raspberry Pi (B4J) to show the IR data (pulses, properties).
The B4R programs sends JSON string to the B4J application which parses the data and displays.
The B4J application is still work-in-progress as want to display additional data.
  • Ready = B4R program as IR-Receiver (using the IRRemoteEx library which has been enhanced). Sends captured frame as JSON string via serial line to B4J.
  • Progress = B4J program can handle live-data received via the serial line from B4R. Still making up-my-mind on the look-and-feel.
  • Not Started = B4R IR-Transmitter; B4R Bluetooth-to-IR-Bridge; B4A app to send Bluetooth commands.
xZigZagChart
Have your xZigZagChart included (TOP) in the B4J application to compare against what I did using xChart (BOTTOM).
Think the displayed data and the pulses (zig-zag-chart) should be separated = just show the pulses as zig-zag 0 and 1 with duration but not data (make the chart too busy).
Then above the pulses show 3 x-scales:
  • Top = "classic" x-scale for the duration from 0 to totalduration in ms with linear scale f.e. 0, 10, 20, 30 ...). Label direction: horizontal
  • Mid = pulseduration for every pulse. Label direction: vertical
  • Bot = level 0 or 1.Label direction: horizontal
1747224883690.png


Next
B4J: Explore enhancing the xZigZagChart, add more fields to the tableview, explore how to show rawticks.

Example JSON data send by B4R
JSON:
{"protocol":"NEC","address":"0","command":"19","repeatperiod":8090,"repeatcount":0,"repeat":0,"bits":32,"flags":0,"rawdata":3860463360,"pulses":[{"level":1,"duration":8850},{"level":0,"duration":4450},{"level":1,"duration":600},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":550},{"level":1,"duration":600},{"level":0,"duration":550},{"level":1,"duration":600},{"level":0,"duration":550},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":1700},{"level":1,"duration":550},{"level":0,"duration":600},{"level":1,"duration":550},{"level":0,"duration":550},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550},{"level":0,"duration":1650},{"level":1,"duration":600},{"level":0,"duration":1650},{"level":1,"duration":550}],"pulsecount":67,"frameduration":67850,"rawticks":[177,89,12,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,33,11,33,12,33,11,33,12,33,11,33,12,33,11,33,12,33,11,12,11,12,11,33,12,33,11,12,11,12,11,12,11,12,11,33,11,34,11,12,11,11,12,33,11,33,12,33,11],"rawtickcount":67,"headermark":0,"headerspace":8850,"len":68}
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
Attached a modified version with the durations on top.
The time scale would be a bit more complicated depending on the total time and then in µs or s.

For me, no need to have a 'scale' for the level, this one is obvious with the colors.

1747233071116.png
 

Attachments

  • XZigZagChartDemo.zip
    59.6 KB · Views: 47
Upvote 0

klaus

Expert
Licensed User
Longtime User
add more fields to the tableview
What does this mean ?
Do you have several charts in a TableView ?

explore how to show rawticks.
What are these rawticks ?
Does one rawtick represent a certain number of microseconds ?

It might be interesting to use a cursor displaying these information when hovering on the chart.
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Thanks a lot for the update = well done.

Chart
Have tested and made few corrections (attached), but can develop further, like showing the axis names etc.
Then no need to use the YXChart of the xChart library.

TableView
The TableView is displayed above the chart and shows detailed protocol information.
So far had only added IR protocol name, address and command - but more info to add.
The TableView is not part of the chart as such - supplemental information.

RawTicks
  • rawticks is a compact, low-level version of the waveform (zig-zag).
  • pulses is the decoded, easier-to-use version with level + duration, already converted to microseconds.
    • duration = rawtick * tickDurationUs
    • level = IIf(index Mod 2 = 0, 1, 0)
For the reverse-engineering of the protocol, I do not know the tickDurationUs (common is 50Us), so wanted to check with the rawticks and the pulse durations.
?But currently rethinking if required to show.

Next
Now that the IR protocol data is available and visualized, can do deeper protocol analysis. Critical items to tackle are the repeatperiod & repeatcount.
 

Attachments

  • xZigZagChart.zip
    2.1 KB · Views: 53
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Thanks for brainstorming.
Still very much in exploring mode and started to enhance the chart (cv code attached) => The chart is far too busy; only used to test getting the fields.
Next steps = my thoughts

1. wave form in the chart center
2. bits direct above the pulses
3. field labels above the bits but grouped on one row of color-coded blocks with start/end positions highlighted
4. pulse duration (vertical) draw only for selected or hovered pulse by default. add toggle: Show All Durations [x]
5. x-axis top show group duration with start/end positions highlighted
6. x-axis bottom minimal: start time (0) , end time (max ms or µs), optional center label

1747331002369.png
 

Attachments

  • xZigZagChart.zip
    3 KB · Views: 50
Upvote 0

klaus

Expert
Licensed User
Longtime User
The chart is far too busy; only used to test getting the fields.
What do you mean with this ?

I do not understand some points:
1. OK
2. What are bits ?
3. What are field labels and grouping ?
4. OK
5. What are groups ?
6. OK

I see that you are able to improve the chart to your needs so i leave it up to you to continue.
My goal was to show that it is relatively easy to make a specific customview chart with B4XCanvas with much much less code rather than trying to adapt a huge existing library which is basically not made for this kind of charts.
But, if you want me to do something, let me know.
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Could you not use a pop-up when you hover over a bar to see all the info for that bar. It may be easier to read all the details for that 'pulse'.
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Thanks for the help so far.
I am further working enhancing the xZigZagChart which is a great base to start = again many thanks for providing.
I will share the solution at some point under B4R Share My Creations IR Frame Visualizer.
Think we can close this thread.
 
Last edited:
Upvote 0
Top