Producing plots in real time - "The applicable method may be too new"

plotting

#1

I have existing code that does some complex calculations in “real time”, and I’ve written it so that I can customize its output with user-defined callback functions. This works well for text output or network interfaces, but I cannot for the life of me get it to do anything useful for plotting. I’d like for it to produce a plot that gets extended and displayed as the calculation proceeds forward in time. But without calling gui(), no plot ever gets displayed on the screen. And when I do try to call gui() (or display(plt)), I get the cryptic message

ERROR: MethodError: no method matching getindex(::PyPlot.Figure, ::Symbol)
The applicable method may be too new: running in world age 21889, while current world is 21892.```

I’ve managed to reproduce this behavior with the following code:

using Plots

function myinit()
    pyplot()
    return plot()
end

function mycallback(p, t, x)
    push!(p, [t,], [x,])
    #display(p)
    gui(p)
end

function calculate(t, fn1, fn2)
    foo = fn2()
    for i=1:size(t,1)
        println(t[i], "\t", sin(t[i]))
        fn1(foo, t[i], sin(t[i]))
    end
end

function doall()
    t=0:1:100
    calculate(t, mycallback, myinit)
end

#2

Put pyplot() outside any function. The way Plots load the backend doesn’t really support loading it in a function like that.


#3

OK. Interesting. That does indeed get rid of the error message. But I get a blank plot.


#4

Can you try the simplest possible plot example?


#5

Sure. This gives me a good plot:

t = 0:0.1:pi
x = sin.(t)
plot(t,x)

This gives me an empty plot:

t = 0:0.1:pi
x = sin.(t)
foo = plot()
push!(foo, t, x)

#6

OK, fixed it. Not sure why the above doesn’t work, but the following does:

t = 0:0.1:pi
x = sin.(t)
foo = plot([0.], [0.])
push!(foo, t, x)

It looks like push!() doesn’t know what to do with a plot that has no existing series - it doesn’t default to establishing a new series. That seems like a bug to me.


#7

try

t = 0:0.1:pi; x = sin.(t); foo = plot() plot!(foo, t, x)


#8
plot!(foo, x, t)

creates a new series every time it’s called. That isn’t what I want. I want to append newly generated data to the existing series.

Specifically, I’d like to (for instance) read a value from a sensor once a second, and add the new reading to a time series of older values, and have the plot update on the screen after the data is added.