Skip to content

Conversation

@tomwhite
Copy link
Member

@tomwhite tomwhite commented Dec 9, 2025

This is an alternative to #830 using anywidget and re-using a lot of the cytoscape.js code. (I'd like to thank @keewis for telling me about anywidget.)

Here are some of the differences I found in implementing the two:

  1. Dash Cytoscape is a wrapper around cytoscape.js, which means that you don't have to write javascript. However, there are some things that it can't do since they haven't been implemented in the wrapper, and you can't access the cytoscape javascript object to work around them - such as being able to call reset() (to reset the graph layout). Anywidget has a more direct relationship with the javascript library - which means you have to write some javascript yourself, but you get more control (in this case adding a reset button was trivial).
  2. The way that Dash and anywidget do live updates is very different. Dash polls Python from the browser, which makes it hard to do incremental (streaming) updates. I found that just sending the update wasn't reliable since there was sometimes a old instance of the Dash component in another window or notebook cell which would get the update - and the new one would not get anything. It wasn't clear to me how to fix this - you could run each Dash instance on another port perhaps, or send the whole dataset each time, but that's something I'd like to avoid since for long running computations there are a lot of tasks. In the end I prefer the Jupyter/anywidget model where updates are pushed from Python to the browser (and in fact the reverse too), which naturally handles multiple instances of the same widget instance, and fits very neatly with Cubed's callback mechanism.
  3. Dash doesn't allow you to write raw HTML or SVG by design. So there is an awkward (but not impossible) conversion from the SVG for representing arrays to the dash-svg API.
  4. Dash encourages the dashboard to be single monolithic component, whereas anywidget fits better with smaller, more modular components that you can use together in a notebook. I've started writing memory and timeline widgets (not in this PR), that you can display in separate notebook cells (or Jupyter Lab tabs) and which update simultaneously for the same computation. There's more work to be done to make composing anywidgets easier though (see Anywidget layout library for composing anywidgets manzt/anywidget#855).
  5. Anywidget works in marimo, but Dash doesn't (afaict).

Here's a screen recording of the widget in a Jupyter notebook (compare to #821 (comment)):

Screen.Recording.2025-12-09.at.10.13.33.mov

I also added an option to produce a (static) visualisation of the plan using cytoscape.js by setting engine="cytoscape" (which just uses a PlanWidget internally):

c.visualize(engine="cytoscape")

Fixes #821

@keewis
Copy link

keewis commented Dec 9, 2025

There's more work to be done to make composing anywidgets easier though

Note that you can already do quite a bit by passing child widgets as traitlets, then using javascript and css to position and style the widgets within the parent widget (see e.g. python, js).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cubed Dashboard

3 participants