Open staticfloat opened 8 months ago
It's totally a footgun, I agree. It's quite hard to get around though, because the update of an observable can cause arbitrarily complex behavior. So if you want to update two of them, they can have effects that can be consolidated or not. I've not been able to come up with a general solution to this problem, yet. We work around some cases with updating .val
but that also doesn't always work.
What's not good is that to do the .val
strategy correctly, you have to know what the effects of the observables are, which for the general case, a user cannot know (without reading all the source code). As far as I know, in the beginning Makie used some other signalling pattern, and switched to eager Observables later because it was simpler in some aspects. Maybe @SimonDanisch can give more context on that.
I've been thinking about this more recently, since the problem is especially visible in the line updating for WGLMakie, where you update positions and an array of colors.
I think after https://github.com/MakieOrg/Makie.jl/pull/3650, this should probably become a priority.
My current plan is to refactor the Plot object internals, to allow update!(plot; multiple_attributes...)
which then gets correctly implemented in the backends.
Yes, I think a batch update solves one half of the problem. The other half is that a function like scatter needs to know if both xs and ys are being updated, and if so, it needs to wait until the update is complete before consuming the values.
I propose that when the batch update is started, it first iterates through the network of observables and “locks” them all, without changing their values. Then, it propagates the changes through, and only after a value has been changed is it unlocked, and only after all previously-locked input arguments to a plotting function are unlocked does it consume the values.
We could make the lift macro automatically wait until all interpolated observable values are unlocked before evaluating the expression, for instance. This would provide a natural building block for this kind of synchronization primitive.
On Tue, Feb 27, 2024 at 01:30 Simon @.***> wrote:
I've been thinking about this more recently, since the problem is especially visible in the line updating for WGLMakie. I think after #3650 https://github.com/MakieOrg/Makie.jl/pull/3650, this should probably become a priority. My current plan is to refactor the Plot object internals, to allow update!(plot; multiple_attributes...) which then gets correctly implemented in the backends.
— Reply to this email directly, view it on GitHub https://github.com/MakieOrg/Makie.jl/issues/3658#issuecomment-1966133203, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA762BSCAHG3AFUZWJM3HDYVWRU5AVCNFSM6AAAAABD3MXJGOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNRWGEZTGMRQGM . You are receiving this because you authored the thread.Message ID: @.***>
Some other solutions to DimensionMismatch errors we've talked about about before:
obs.val
updates like in the docs. I first liked the PullObservables approach, but it has one big problem. When you "pull" an observable, you rely on knowing which of the observables it depends on have changed, so that you only do as much updating as necessary. However, it's really easy to change values in mutable objects that are just referenced somewhere by these observables. And then you never receive the update because nobody invalidated the downstream observables that were implicitly dependent on those mutable objects.
That's true for the current Observables too though?
obs = Observable(zeros(10))
obs[][1] = 1
is not going to trigger an update
It appears that if I use
@lift()
to make a recipe dynamic, I can quickly run into issues where one half of my observables have updated, but not both. Example:Running this and moving the slider results in the error:
If I change the recipe to instead do a single conversion to
Point2f
I can fix this:However this is not obvious from the error message, and IMO is a bit of a footgun. Reading the docs, I see there is a paragraph at the very end of the
Problems with Synchronous Updates
section that seems related, only I argue this behavior is even more surprising because from the user's perspective it feels like a single observable goes in.