I want to plot real-time flight control data to get a better and faster understanding of the performance of our flight controllers.
The incoming data stream might be decoded in a C-function (because it already exists).
But then I would like to plot one to three data streams in Julia with an update rate of about 30 Hz. Just an oscilloscope like plot.
In addition it would be nice to select the data stream(s) in the GUI.
Which plotting package might be the best choice?
Perhaps this could be useful:
I think you’ll get highest performance and frame rates from Makie, but I think GR is also able to do pretty well. I believe InspectDR is designed to be quite fast, but I haven’t used it.
Depending on the size of the data you are plotting, PlotlyJS might also work for you. I recently used the
react! function in PlotlyJS to in-place update an existing plot and Interact as an interface, and I was surprised at how responsive it was. It was updating at least at 30Hz.
Thanks a lot for all your responses! I will try some of your suggestions soon.
I was wondering how InspectDR would handle this myself… so I made a small test:
using InspectDR using Colors function getmeasdata(t, φ) sigA = sin.(t .+ φ) sigB = cos.(t .+ φ) return (sigA, sigB) end #Build general structure of animation plot function buildanimplot() NPOINTS = 1000 NCYCLES = 2 #To display RED = RGB24(1, 0, 0) GREEN = RGB24(0, 1, 0) BLUE = RGB24(0, 0, 1) #collect: InspectDR does not take AbstractArray: t = collect(range(0, stop=NCYCLES*2pi, length=NPOINTS)) (sigA, sigB) = getmeasdata(t, 0) #Using Plot2D simplified "template" constructor: p = InspectDR.Plot2D(:lin, [:lin, :lin], title = "Measured Data", xlabel = "time (s)", ylabels = ["Amplitude (V)", "Amplitude (V)"] ) p.layout[:enable_legend] = true wfrmA = add(p, t, sigA, id="Signal A", strip=1) wfrmA.line = line(color=RED, width=2) wfrmB = add(p, t, sigB, id="Signal B", strip=2) wfrmB.line = line(color=BLUE, width=2) gplot = display(InspectDR.GtkDisplay(), p) return (gplot, t, wfrmA, wfrmB) end #Update animated plot in "real time": function testanimplot() DURATION = 5 #sec NSTEPS = 1000 RADPERSEC = 2pi tstep = DURATION/NSTEPS ϕstep = RADPERSEC * tstep (gplot, t, wfrmA, wfrmB) = buildanimplot() @time begin #Curious to see how long it actually takes for ϕ in range(0, step=ϕstep, length=NSTEPS) sleep(DURATION/NSTEPS) (sigA, sigB) = getmeasdata(t, ϕ) wfrmA.ds.y = sigA wfrmB.ds.y = sigB InspectDR.refresh(gplot) end end return gplot end gplot = testanimplot()
This might make it easier to see if InspectDR is adequate for your task…
How did you do it? Hints will be much appreciated.
The general premise is to keep your trace objects that are used in constructing the plot, update them inplace, and then call
react! with your plot objects and your (modified) traces. Here’s an example:
using PlotlyJS t = 1:25 x1 = sin.(t./(pi)) x2 = rand(25) .+ 2 trace1 = scatter(;x=t, y=x1) trace2 = scatter(;x=t, y=x2) l = Layout() p = plot([trace1, trace2], l) for i in 1:100 trace1[:y] .= sin.((t .+ i) ./ pi) trace2[:y] .= rand(25) .+ 2 react!(p, [trace1, trace2], l) sleep(0.1) end
Nice. That is pretty much what I ended up doing, except that I thought it too much work to sort through existing traces to change them up. I just regenerated the traces from scratch every time they needed to be plotted.
Now the trickier part: Make the plot respond to user input during the simulation/plotting.