Get help from the marimo community

Updated 3 weeks ago

mo.state(), treatlets.link(), and infinite loops

Working in data visualisation, I created a brushable_widget python package (available at pypi) so that I can draw an SVG with circles, brush those circles, and get the selected IDs back into marimo (python).
What I really want to do, is build brushing/linking between 2 plots: having 2 plots next to each other showing different views on the same data. If you brush (select) points in the first plot, the points in the second plot are also highlighted; and vice versa.

The API is the following, where circles1 and circles2 are arrays of circles based on the same datapoints but different axes.
Plain Text
svg1 = SVG(width=200, height=200, elements=circles1)
svg2 = SVG(width=200, height=200, elements=circles2)

The SVGs are then wrapped in an anywidget and

Plain Text
plot1 = mo.ui.anywidget(BrushableWidget(svg=svg1.as_str(), selected_ids = []))
plot2 = mo.ui.anywidget(BrushableWidget(svg=svg2.as_str(), selected_ids = []))
mo.hstack([plot1, plot2])


When hovering over datapoints, the selected_ids trait of that widget is updated. And here's the thing: it should be propagated to the other widget.

I have tried 2 approaches, but each have issues:

Approach 1: traitlets.link((plot1, "selected_ids"),(plot2, "selected_ids"))
Problem: even though they are linked, a plot1.selected_ids is not updated in other marimo cells.

Approach 2: get_selected, set_selected = mo.state([])
Problem: you end up with infinite loops: set_selected(plot1.selected_ids), plot1.selected_ids = get_selected(), set_selected(plot2.selected_ids) and plot2.selected_ids = get_selected() will keep triggering each other.

Any ideas on how to get this working? (cc @manzt )
M
J
14 comments
it's possible for Approach 1 that we don't handle linking in marimo. do you have a runnable snippet of code i can try out myself?
i think i got it to work
Thanks for the help, Myles. But I'm afraid it still does not work as expected. The last cell p1.selected_ids only updates if you do the brush directly in plot1, but not when you brush in plot2 (which changes p2.selected_ids which should lead to p1.selected_ids to be changed, which should in turn update that last cell).
On a (probably different?) note, I notice that I often have to restart the kernel because one or two of the plots are not shown. No message in the console, though...
BTW, if you're interested: I'm using this to create a new tutorial for my data visualisation course (see https://gitlab.kuleuven.be/aida-lab/teaching/g0r72a-tutorial-pythonsvg for the marimo code). Hoping to switch from svelte to python for custom visuals and interactions.
Oh i see, yes you are right, p2 is not updating. I thikn we would need to handle traitlets.link properly in marimo then (it is not obvious to me yet how we could, but i am sure its doable)

I notice that I often have to restart the kernel because one or two of the plots are not shown

I have not come across this. can you reliably produce this?
I can reproduce the issue with the kernel needing a restart, but not reliably. I haven't found a specific trigger yet.
Regarding the traitlets.link: if that does not work, do you see method using mo.state() or something else (just so that I can use python in my course)? Getting the traitlets to work properly in marimo would be great, though!
Is this something that would need to get done at the marimo level, or anywidget?
ah yes, i got it to work with state
i did experience the chart dissapearing too, when i toggled the App Mode (to hide the code cells)
This seems to work! That's great. Can you explain the lambda function to me? Specifically: why the x["new"], and what the names="selected_ids" is. Where do the new and names= come from? (I couldn't find documentation)
The issue of the disappearing charts is indeed mostly when I toggle to App mode, but not always. Interestingly, I just had the case where of 3 plots only the middle one did not display (see screenshot).
Attachment
Screenshot_2025-02-20_at_22.50.25.png
I’m not too familiar with the traitlets api but I noticed it returned a dictionary with the new and old data, so I am just grabbing out the new data. There may be a better way to listen for updates
Add a reply
Sign up and join the conversation on Discord