Reputation: 539
I am trying to get Bokeh server to print out, however all I get is an instance running on http://localhost:5006/?bokeh-session-id=default with the radio buttons. When I click the buttons nothing happens. Is there something I am missing?
from bokeh.models.widgets import RadioButtonGroup
from bokeh.plotting import figure, show, output_server
def my_radio_handler():
print 'Radio button option selected.'
radio_button_group = RadioButtonGroup(
labels=["Option 1", "Option 2", "Option 3"], active=0)
radio_button_group.on_click(my_radio_handler)
output_server()
show(radio_button_group)
Upvotes: 2
Views: 3488
Reputation: 34568
The answer above shows how this can properly be accomplished with bokeh.client
and push_session
and session.loop_until_closed
.
I'd like to add a few more comments for context. (I am a core developer of the Bokeh project)
There are two general ways that Bokeh applications can run:
These are scripts that are run something like:
bokeh serve --show my_app.py
In this case, the code, the objects, all the callbacks, etc. are running in the bokeh server itself. The situation looks like this:
browser <---> Bokeh Server
This is the method I would always recommend first. It takes the least amount of code, is the simplest to deploy, can be scaled out, uses less network traffic, and is more robust.
It's also possible to create the app and run callbacks in a separate process, using bokeh.client
. Then the situation looks like this:
browser <---> Bokeh Server <---> another python process
Then the Bokeh server really just become a middleman, relaying messages between the browser and your python process. This has disadvantages:
session
stuff not need in "Server Apps")session.loop_until_closed
)In the past, there were specific use-cases where using bokeh.client
was necessary, for example: being able to customize app sessions per-use. But now that HTML request arguments are available to "Server Apps" that can be accomplished without bokeh.client
. I would say there are now fewer reasons to reach for the bokeh.client
approach. For this reason I always recommend the bokeh serve my_app.py
method as the first, best way to use the Bokeh server.
But, getting back to the question at hand: So what happens in the Separate Python Process scenario, if you forget to call session.loop_until_closed
? Well the python process (the one that has your callbacks!) finishes, and the process terminates. Then there is nothing left to actually run the callbacks.
Well, this is essentially exactly the situation with output_server
. It does the "first half" of the session setup, loading the objects in to the server, but then your python script that calls output_server
finishes, and nothing is left to execute any callbacks. output_server
is basically still around due to accidents of history, but I would say it is not very useful at all. At best, it can load apps with no callbacks into a Bokeh server, but then why would you need a Bokeh server except to connect web apps to real python callbacks?
There is currently (as of release 0.12.2
) an open issue discussing deprecating output_server
for this reason:
https://github.com/bokeh/bokeh/issues/5154
TLDR; I would not recommend using output_server
for any reason at this point.
Upvotes: 6
Reputation: 7150
You need to sync the server and the current session to get informations back.
from bokeh.client import push_session
from bokeh.models.widgets import RadioButtonGroup
from bokeh.plotting import curdoc, figure, show, output_server
def my_radio_handler(new):
print 'Radio button ' + str(new) + ' option selected.'
radio_button_group = RadioButtonGroup(
labels=['Option 1', 'Option 2', 'Option 3'], active=0)
radio_button_group.on_click(my_radio_handler)
# Open a session to keep our local document in sync with server
session = push_session(curdoc())
# Open the document in a browser
session.show(radio_button_group)
# Run forever (this is crucial to retrive callback's data)
session.loop_until_closed()
You can get more control on the click handler using on_change()
:
def my_radio_handler_complete(attr, old, new):
print(attr, old, new)
print('Radio button ' + str(new) + ' option selected.')
radio_button_group.on_change('active', my_radio_handler_complete)
FYI, in the source-code, on_click
is just a proxy for on_change()
and defined as:
def on_click(self, handler):
self.on_change('active', lambda attr, old, new: handler(new))
Upvotes: 2