help with reactive updates from custom library

Hi, I would like some help getting our Clustergrammer-GL library to work reactively on Observable. This example Trying to make Clustergrammer-GL Reactive / Nicolas Fernandez / Observable shows a pre-calculated hierarchically clustered dataset (JSON loaded as file attachment) being visualized using our library (big thanks to @john-guerra for help us get our library working on Observable). Clustergrammer-GL updates variables (e.g. cgm.param.int.mouseover.row.name) based on user interaction. However, these variable updates appear to be incompatible with Observableā€™s reactive updates (at least in the way Iā€™m trying to implement them). I would like help understanding if/how I could have Observable reactively update variables based on user interaction with the Clustergrammer-GL visualization. Based on my reading, I think the solution might involve using views and setting up an input event.

We are currently able to get this type of behavior in Jupyter notebooks using: Clustergrammer2 widget library (which Clustergrammer-GL is a dependency), the widget bqplot, the dashboard library voila, and the hosting service MyBinder. See example: GitHub - cornhundred/citibike-clustergrammer2.

small_gif

Any help or advice would be greatly appreciated and we would love to get this CitiBike example on Observable as well :smile: !

Hereā€™s my suggestion:

And a quick summary:

  1. Clustergrammer-GL requires that the container be inserted into the DOM before initializing, and requires a globally-unique identifier for that container. If it didnā€™t have these requirements, it would be easier to initialize in Observable (where cells normally run with detached DOM elements, and only insert them into the DOM by returning a value at the end).

  2. The most natural way to make Clustergrammer-GL reactive would be for it to emit custom events when things change. I did that manually by intercepting when some internal parameters are set, and by listening to browser native events (mousemove). But if Clustergrammer-GL emitted these events itself, itā€™d be more straightforward to expose those as reactive values in Observable using Generators.observe.

  3. Itā€™s best to avoid bundle.run in notebooks, as it isnā€™t very reliable. I re-attached the generated bundle to your notebook, but if you published an AMD- or UMD-compatible bundle to npm, then folks could require("clustergrammer-gl") and it would work out of the box.

Hope this helps! Please let us know if you have more questions.

1 Like

Thank you for all the help @mbostock!! I see the state is now reactive, but I will have to do some homework to figure out how everything is working and see if I can make your recommended changes. Iā€™ll let you know if I have any more questions!

Another quick question, I merged your changes to the notebook, but is there a way to see the previous suggestions?

Youā€™re very welcome. The link above should still show you the proposed changes, even after youā€™ve merged them. Is that what you are looking for?

Thanks, I see the changes but I do not see the suggestions/comments (little text boxes) from before. There was a suggestion/comment about not using bundle.run but I donā€™t see it after merging - itā€™s not a huge deal cause I think you said the same thing here in this thread.

Also, just a little suggestion - the color scheme for showing parent and fork changes is a little difficult for me to see (red/green colorblind).

Ah, sorry, no, comments are hidden after you merge or close the suggestion. But weā€™re fixing that real soon now! You should have a copy in your email however.

We just improved the color contrast of our diffs last week:

Sorry itā€™s still hard to read. :frowning:

1 Like

Hi @cornhundred, sorry that the diff colors are still hard for you to distinguish. I see that you linked to Github above - do the colors in Github diffs happen to work better for you?

thanks,
Kerry

1 Like

Hi @mbostock I just noticed I was getting the following invalid module error

on my notebook Reviewing COVID-19 SARS-CoV-2 preprints from medRxiv and bioRxiv / Human Immune Monitoring Center at Mount Sinai | Observable. I switched to attaching my clustergrammer-gl library using a file attachment. Was this the issue you were warning about

Are you seeing an error loading clustergrammer-gl from the file attachment? That seems to work fine for me, although I also see youā€™re using bundle.run to load @octokit/rest, and that fails. So you might try attaching that as a file attachment, too.

Alternatively, it appears Pika CDN will work:

Octokit = (await import("https://cdn.pika.dev/@octokit/rest@16.28.3")).default
2 Likes

Iā€™m seeing an error if I require clustergrammer-gl from bundle.run but not as a file attachment. Iā€™ll try that change to octokit also.

Update: Iā€™m also able to load octokit from a file attachment

// Octokit = require('https://bundle.run/@octokit/rest@16.28.3')
Octokit = require(await FileAttachment("octokit.js").url())

Hi @mbostock, sorry for the simple question but how we can do this:

Iā€™m using webpack (clustergrammer-gl/webpack.config.js at master Ā· ismms-himc/clustergrammer-gl Ā· GitHub).

Update

Iā€™m following the link from https://bundle.run/ to pkg.module Ā· rollup/rollup Wiki Ā· GitHub, which appears to contain the information I need to make an AMD/UMD compatible bundle (will update).

I tried following what was happening behind the scenes on bundle.run (GitHub - Rich-Harris/packd: Rollup as a service (with a little help from Browserify)) and using browserify:

$ browserify clustergrammer-gl.js > clustergrammer-gl.0.11.10.bundle.js

But Iā€™m getting an invalid module error with that file.

Solution

I followed the instructions to host my own local instance (GitHub - Rich-Harris/packd: Rollup as a service (with a little help from Browserify)) and was able to bundle the package. This feels like a convoluted solution but it appears to work. Iā€™ll update when I understand how to do this in a more streamlined manner (e.g. build the bundle automatically, add it into the package.json, have it hosted on a CDN).