Automatic update in Makie with Observable of vector

I need to iteratively call a Makie recipe according to an observable value.

Lets say I write a recipe MyPlot and I want to iteratively call Scatter inside.

using Makie

@recipe(MyPlot, x) do scene
    Theme(
        repeat = 3
    )
end

function Makie.plot!(myp::MyPlot)
    obs = @lift [$(myp.x) .* i for i in 1:$(myp.repeat)]

    hlines!(myp, 5, color=:red) # always plot a horizontal line

    for valrow in obs[]
        scatter!(myp, valrow) # depends on the attribute
    end

    myp
end

Works fine with first call:

julia> f,a,p = myplot([1,2,3]; repeat=5)

I get what I want

But I cannot update it:

julia>  p.repeat[] = 10 # doesn't update the figure
10

I know that theoretically I need to call the scatter recipe with an observable passed in, but I cannot wrap my head around it how to do it.

Any suggestions ?

Please keep in mind this is just a minimal example for a more complicated code, where the iteration is necessary. So please don’t suggest solutions that involve calling scatter only once with scatter!(myp, obs) or similar.

As far as I know, this is the solution to this problem. When I have had this come up in the past, I have used iteration to create an Observable{Point2f[]} that I then pass to scatter! once. In this simple example, that looks like

obs = @lift reduce(vcat, [Point2f.(i, $(myp.x) .* i) for i in 1:$(myp.repeat)])

Thanks for the answer but this solution involves calling scatter only once, which is circumventing the problem.

In reality I don’t call scatter but GraphMakie.EdgePlot with different transparent colors, so that in the end a mixture of transparencies and colors is drawn.

If there is really no way around to get it working iteratively, I guess I should focus to somehow transform my data as you suggested for my problem as well…

I was also thinking of transforming Observable{Vector} to a Vector{Observable} and pass this* in scatter, but again it didn’t work.

* each Observable

I believe the color= kwarg for edgeplot can be a vector, so I would try creating two observables, one the vector of edges and one the vector of colors and then calling edgeplot with those.

1 Like

You cannot have the existence of a plot depend on an observable, so you cannot have x scatter plots where x changes dynamically. At least not how things currently work. You can always concatenate the data and work with a single plot as suggested above, not sure why you don’t want to / can’t do that.

PS: Actually you can do it but you’d have to write more complex logic that adds and deletes the plot objects, renews observable connections etc. Probably not worth it