Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API suggestion for avoiding synchronous update issues #798

Closed
yha opened this issue Dec 29, 2020 · 0 comments
Closed

API suggestion for avoiding synchronous update issues #798

yha opened this issue Dec 29, 2020 · 0 comments
Labels
enhancement Feature requests and enhancements Observables planning For discussion and planning development

Comments

@yha
Copy link
Contributor

yha commented Dec 29, 2020

I would like to suggest a change to the API, which is somewhat of an extension of the "API wishlist" in #725.
I'm assuming the API will be modified so that basic plotting command (plot, lines, heatmap etc.) return a plot object which can then be added into a scene or axis, as in the example in #725.

Suggested change

The basic use pattern should be changed from observable parameters to plot commands (push!(ax, plot(Node(data)))), to observable plot objects over plain data (push!(ax, Node(plot(data)))).
Support for the former pattern can be dropped to make for a more consistent interface (and guard against the problem described below). Alternatively, it can be implemented easily on top of this API, with definitions such as

lines(obs::Observable)      = lift(lines, obs)
lines!(ax, obs::Observable) = push!(ax, lift(lines, obs))

The problem

The main advantage is solving problems with update synchronization, as described in this docs section http://makie.juliaplots.org/dev/interaction.html#Problems-With-Synchronous-Updates.

For example this:

# (1)
i = Observable(5)
x = @lift rand($i)
y = @lift rand($i)
c = @lift rand($i)
push!(ax, lines(x, y, color=c))
# or the current:
# lines!(ax, x, y, color=c)

would become

# (2)
i = Observable(5)
lns = lift(i) do i
    x = rand(i)
    y = rand(i)
    c = rand(i)
    lines(x, y, color=c)
end
push!(ax, lns)

Example (1) doesn't actually work because of the synchronous update problem: updating i updates x first, which updates the lines plot and throws an error, since x and y are of different length. Example (2) would achieve an atomic update of the plot, so there is no such issue.

A smaller advantage is that listening on the plot can make sense sometimes. Arguably on(lns) do lns; update_limits!(lns) end is better than on(i) do _; update_limits!(lns) end as it expresses the intent more precisely, and therefore more robust to changes in how lns is constructed.

Current workarounds

A possible workaround in the current design is doing lines(Point2.(x,y)), but this trick doesn't work for the color kwarg. It also wouldn't work for heatmap(x,y,z).
I was able to get synchronous updates for my own code by defining ad-hoc intermediate object and recipes for each such plot. (You can do heatmap(::Observable{MyCustomHeatmapDataStruct}) with a type recipe. Dealing with kwargs requires a full recipe as far as I can see). Changing the API would solve the problem more generally for all plot types, and for both their positional and keyword arguments.

@ffreyer ffreyer added enhancement Feature requests and enhancements planning For discussion and planning development Observables labels Aug 22, 2024
@MakieOrg MakieOrg locked and limited conversation to collaborators Aug 22, 2024
@ffreyer ffreyer converted this issue into discussion #4193 Aug 22, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement Feature requests and enhancements Observables planning For discussion and planning development
Projects
None yet
Development

No branches or pull requests

2 participants