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. 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.


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 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 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?


1 Like

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

on my notebook 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 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("")).default

I’m seeing an error if I require clustergrammer-gl from 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('')
Octokit = require(await FileAttachment("octokit.js").url())

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

I’m using webpack (


I’m following the link from to, 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 ( 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.


I followed the instructions to host my own local instance ( 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).