3

I am using a radio button with Bokeh. I want to be able to show a loading indicator when a radio button is clicked and then show that it has finished after the python callback has completed. How do you do this with Bokeh?

I've tried using combinations of js_onchange with onchange for the radio buttons. I just can't come up with a way to notify the JS side of things when the Python callback is completed.

callback = CustomJS(args={}, code="""
  document.getElementById('message_display').innerHTML = 'loading...';
""")

radio_button.js_on_change('active', callback)
radio_button.on_change('active', some_other_callback)

When I run it the innerHTML gets set to loading and the on_change Python callback runs and the graph updates but I have no way to trigger a change on the JS side of things change the innerHTML to say done.

wpercy
  • 9,636
  • 4
  • 33
  • 45
tink3r
  • 137
  • 1
  • 2
  • 13
  • Reading your post I could make it 5 questions instead of one :) **1)** how to create "load indicator? **2)** How to know when callback ended executing? **3** How to execute JS code outside a callback **4)** How to call JS callback from Python callback? **5)** How to call another JS callback from current JS callback? Which answers are you after? – Tony Apr 23 '19 at 12:21
  • Here is an overview. I have a radio button. I click the radio button. That triggers a python callback to be run using on_change. I'm trying to display a loading indicator before and a finished indicator after. I've been able to show the loading indicator using the js_on_change. Where I have the issues is knowing when the python code has finished and updating the interface with JavaScript. – tink3r Apr 23 '19 at 15:56

1 Answers1

0

Assuming the user already have a plot in view one option would be to set a callback on the start attribute of the plot's range so it will be triggered when the plot gets updated.

from bokeh.models import CustomJS

p = figure()

def python_callback()
    p.y_range = Range1d(None, None)
    # get your data here and update the plot

code = "document.getElementById('message_display').innerHTML = 'loading finished';"
callback = CustomJS(args = dict(), code = code)
p.y_range.js_on_change('start', callback)

See working example below:

import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, ColumnDataSource

points = np.random.rand(50, 2)
cds = ColumnDataSource(data = dict(x = points[:, 0], y = points[:, 1]))

p = figure(x_range = (0, 1), y_range = (0, 1))
p.scatter(x = 'x', y = 'y', source = cds)

cb_to_make_selection = CustomJS(args = {'cds': cds}, code = """
function getRandomInt(max){return Math.floor(Math.random() * Math.floor(max));}
cds.selected.indices = [getRandomInt(cds.get_length()-1)]
""")

p.x_range.js_on_change('start', cb_to_make_selection)

show(p)
Tony
  • 7,767
  • 2
  • 22
  • 51
  • 1
    I have a radio button that when clicked changes the cart data. The user doesn't interact with the chart directly other than clicking the radio button. Is there a way to run a JavaScript callback on the chart itself changing or the underlying data changing? – tink3r Apr 23 '19 at 17:01
  • I get what you are saying and it will help my situation out. What I need now is to find the event that happens when my plot changes. – tink3r Apr 23 '19 at 17:23
  • This only triggered when I actually clicked and dragged on my x range, not while the chart was loading. – Noumenon Jun 15 '22 at 15:10
  • Yes. The question in this post was to show a loading indicator when a radio button is clicked – Tony Jun 17 '22 at 12:37