Search code examples
javascriptpythonbokeh

Bokeh widgets call CustomJS and Python callback for single event?


I have a Bokeh application that makes use of the Python callbacks for various widget events. With certain events, I'd like to execute some JavaScript code before making the callback to the Python function. Is this possible?

In this case, the Python callback is potentially long-running, and I'd like to start and stop a Javascript spinner object before and after the long-running Python code executes.


Solution

  • As of Bokeh 1.0.4, "busy" / "done" events (to enable things like triggering spinners or other UI events) are still an open feature request.

    In the mean time, your best bet is to use some "dummy" model to trigger a CustomJS callback. For instance, you could add an invisible glyph, and trigger a CustomJS any property on it as a proxy for a "busy" event. This is clunky, but serviceable.

    Here is a very rough outline example. The first alert will pop up immediately. Close it, the next alert will pop up 5 seconds later.

    import time
    
    from bokeh.io import curdoc
    from bokeh.layouts import column
    from bokeh.models import Button, CustomJS
    from bokeh.plotting import figure
    
    p = figure()
    p.circle([1,2,3,4,5], [2,6,3,1,6])
    
    dummy = p.circle([1], [2], alpha=0)
    dummy.glyph.js_on_change('size', CustomJS(code="""
    alert(cb_obj.size.value)
    """))
    
    b = Button()
    def cb():
        dummy.glyph.size = 10
        time.sleep(5)
        dummy.glyph.size = 20
    
    b.on_click(cb)
    
    curdoc().add_root(column(b, p))