CustomJS Varriable with Common Scope

Hi all,

I suspect this is a duplicate somewhere, but I can’t seem to find an answer that cleanly answers how to do this.

I have a plot that is dynamically generating glyphs and placing them on an X axis. To avoid overlapping glyphs, I’m using CustomJS to track the location of placed glyphs and increment up the Y axis points appropriately when a glyph would overlap on the X axis. These glyphs are generated by a selected table. This works great, since I can calculate each position just by polling the table.

The problem comes when I have multiple tables. I’m having issues sending that persistent variable across multiple CustomJS blocks.

I can create static templates quite easily by passing any arbitrary python dictionary to the CustomJS class. I also saw this way to create a ‘global’ variable, but this seems still seems like it doesn’t create a common javascript object on the back end.

I could probably do this by passing around all the different tables in my code or using a class that manages all the tables and creates some humongous javasctipt block, where I pass all of the relevant tables to the same CustomJS that systematically scans all of them and draws each glyph, but that seems a lot more spagetti than multiple blocks logging the things it placed somewhere.

TLDR How can I track persistent, arbitrary data across diverse CustomJS objects?

Minimal example:

from bokeh.io import curdoc
from bokeh.models import CustomJS
from bokeh.models.widgets import Button
from bokeh.plotting import show
from bokeh.layouts import column

js1 = """
tracker['tracked_item']++
console.log(tracker['tracked_item'])
"""

js2 = """
console.log(tracker['tracked_item'])
"""

curdoc().tracker = {"tracked_item": 0}

# Increments appropriately
increment_button = Button(label="Increment")
increment_button.js_on_click(
    CustomJS(
        args=dict(tracker=curdoc().tracker),
        code=js1,
    )
)

# Does not increment with the increment button
report_button = Button(label="Report")
report_button.js_on_click(
    CustomJS(
        args=dict(tracker=curdoc().tracker),
        code=js2,
    )
)

buttons = column(increment_button, report_button)

show(buttons)

I’ve just stored stuff in a sort of dummy ColumnDataSource in the past, but if you need a different kind of data structure, you can use a custom Data Model → see data_models — Bokeh 3.0.1 Documentation

1 Like