Makie.jl: Update scene after *all* nodes have been updated

Created on 10 Jan 2020  路  10Comments  路  Source: JuliaPlots/Makie.jl

I am trying to visualize a sequence of 2D scatter plots using the Node/Observable feature to achieve fast update rates. However, I run into errors if the number of points changes over time as the plotting function will fail in cases where the number of x and y coordinates is not the same. Is there a way lock the scene update until all Nodes are updated?

Here is a MWE

using Makie

px = Node(zeros(1))
py = Node(zeros(1))
scatter(px, py) |> display

for t in 1:10
    # generate random dummy data (number of points may vary over time)
    n_points = rand(5:10)
    push!(px, rand(n_points))
    push!(py, rand(n_points))
    sleep(0.1)
end

Do I have to introduce fake-dependencies between nodes to make this work? Or is there some sort of mutex for Makie scenes?

Most helpful comment

Hm, that's because there is an extra level of indirection to construct the points out of x and y, I think...
Try:

using Makie

pxy = [Point2f0(0)]
puv = [Vec2f0(1)]
pxy_n = Node(pxy)
puv_n = Node(puv)
arrows(pxy_n, puv_n) |> display

for t in 1:10
    # generate random dummy data (number of points may vary over time)
    n_points = rand(5:10)
    empty!(pxy); empty!(puv);
    append!(pxy, rand(Point2f0, n_points))
    append!(puv, rand(Vec2f0, n_points))
    pxy_n[] = pxy_n[]
    sleep(0.1)
end

All 10 comments

You could use a Vector{Point} instead? That would make sure x and y update synchronously.

This does not really solve the issue. Sometimes, one might wish to also update other attributes (e.g. the color of each point in a scatter plot). Fake dependencies work but I was just wondering whether there is a more elegant solution.

Update: I have noticed that for rendering with arrows, even fake-dependencies between observables do not solve the issue. Furthermore, for arrows, Vector{Point} is not a helpful workaround because any method of arrows still requires multiple arguments who's dimensions must all match:

`arrows(points, directions; kwargs...)`
`arrows(x, y, u, v)`
`arrows(x::AbstractVector, y::AbstractVector, u::AbstractMatrix, v::AbstractMatrix)`
`arrows(x, y, z, u, v, w)`

Yeaah, this is annoying ...
I usually update the underlying vectors in place, and then just update one of the observable, once all vectors have the same length:

using Makie

px = zeros(1)
py = zeros(1)
px_n = Node(px)
py_n = Node(py)
scatter(px_n, py_n) |> display

for t in 1:10
    # generate random dummy data (number of points may vary over time)
    n_points = rand(5:10)
    empty!(px); empty!(py);
    append!(px, rand(n_points))
    append!(py, rand(n_points))
    py_n[] = py_n[]
    sleep(0.1)
end

Thank you for your reply. I guess that is a workaround that should work. Are there any plans to support more synchronized update of nodes (e.g. by locking the scene)? Or are there other reasons not to support this?

I should have never allowed to update individual vectors :D This was a bad design decision... The plan is to support this in the future:

particles = Buffer(colors = colors, positions = positions)
scatter(particles)
# Or
particles = [(color=color, position=position), (...)]
scatter(particles)

... And internally map to this!

Yeaah, this is annoying ...
I usually update the underlying vectors in place, and then just update one of the observable, once all vectors have the same length:

using Makie

px = zeros(1)
py = zeros(1)
px_n = Node(px)
py_n = Node(py)
scatter(px_n, py_n) |> display

for t in 1:10
    # generate random dummy data (number of points may vary over time)
    n_points = rand(5:10)
    empty!(px); empty!(py);
    append!(px, rand(n_points))
    append!(py, rand(n_points))
    py_n[] = py_n[]
    sleep(0.1)
end

This workaround does not seem to work for arrows for some reason I fail to understand. The code below fails with ERROR: DimensionMismatch("dimensions must match"):

using Makie

px = zeros(1)
py = zeros(1)
pu = zeros(1)
pv = zeros(1)
px_n = Node(px)
py_n = Node(py)
pu_n = Node(pu)
pv_n = Node(pv)
arrows(px_n, py_n, pu_n, pv_n) |> display

for t in 1:10
    # generate random dummy data (number of points may vary over time)
    n_points = rand(5:10)
    empty!(px); empty!(py); empty!(pu); empty!(pv)
    append!(px, rand(n_points))
    append!(py, rand(n_points))
    append!(pu, rand(n_points))
    append!(pv, rand(n_points))
    py_n[] = py_n[]
    sleep(0.1)
end

Hm, that's because there is an extra level of indirection to construct the points out of x and y, I think...
Try:

using Makie

pxy = [Point2f0(0)]
puv = [Vec2f0(1)]
pxy_n = Node(pxy)
puv_n = Node(puv)
arrows(pxy_n, puv_n) |> display

for t in 1:10
    # generate random dummy data (number of points may vary over time)
    n_points = rand(5:10)
    empty!(pxy); empty!(puv);
    append!(pxy, rand(Point2f0, n_points))
    append!(puv, rand(Vec2f0, n_points))
    pxy_n[] = pxy_n[]
    sleep(0.1)
end

Okay, that seems to work. Really subtle...

... bump this: I would like to update mesh coordinates and mesh connectivity at the same time. However what worked for arrows didn't work for mesh...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

utotch picture utotch  路  4Comments

mschauer picture mschauer  路  4Comments

Datseris picture Datseris  路  7Comments

AlexisRenchon picture AlexisRenchon  路  3Comments

asinghvi17 picture asinghvi17  路  5Comments