purpose
-
architecture
+---------+ | python | plots ranges axes glyphs +---------+ ↑ ↓ +--------------+ ↑ ↓ json <== | bokeh server | ↑ ↓ +--------------+ +---------+ | BokehJS | +---------+
-
sync
model objects
in python and in the browser with each other-
ui and tool events => computations or queries => python
-
auto push updates => ui
-
periodic, timeout, asynchronous callbacks drive streaming updates
-
use case scenarios
-
local or individual use
-
creating deployable apps
-
shared publishing
specifying output_server
- check my post 2016-01-29-deploying-the-bokeh-server
connecting with bokeh.client
-
introduced new
tornado
andwebsocket-based
server in bokeh 0.11 -
client api for interacting with bokeh server
-
trigger updates to the plots and widgets in the browser
-
periodic or asynchronous callbacks
-
-
demo
-
first step is to start boekh server
$ bokeh serve
-
code
import numpy as np form numpy import pi from bokeh.client import push_session from bokeh.driving import cosine from bokeh.plotting import figure, curdoc x = np.linspace(0, 4 * pi, 80) y = np.sin(x) p = figure() r1 = p.line([0, 4 * pi], [-1, 1], color='firebrick') r2 = p.line(x, y, color='navy', line_width=4) session = push_session(curdoc()) # periodic callback @cosine(w=0.03) def update(step): r2.data_source.data['y'] = y * step r2.glyph.line_alpha = 1 - 0.8 * abs(step) # run every 50 milliseconds curdoc().add_periodic_callback(update, 50) # open the doc in browser session.show() # run forever session.loop_until_closed()
-
building bokeh apps
-
single module format
-
demo
# myapp.py import numpy as np from bokeh.models import Button from bokeh.palettes import RdYlBu3 from bokeh.plotting import figure, curdoc, vplot # create a plot and style its properties p = figure(x_range(0, 100), y_range(0, 100), toolbar_location=None) p.border_fill_color = 'black' p.background_file_color = 'black' p.outline_line_color = None p.grid.grid_line_color = None # add a text renderer to out plot (no data yet) r = p.text(x=[], y=[], text=[], text_color=[], text_font_size='20pt', text_baseline='middle', text_align='center' ) i = 0 # callback that will add a number in a rondom location def callback(): global i ds.data['x'].append(np.random.random() * 70 + 15) ds.data['y'].append(np.random.random() * 70 + 15) ds.data['text_color'].append(RdYlBu3[i % 3]) ds.data['text'].append(str(i)) ds.trigger('data', ds.data, ds.data) i = i + 1 # add button widget and config callback button = Button(label='press me') button.on_click(callback) # put button and plot in a layout and add to doc curdoc().add_root(vplot(button, p))
-
run
$ bokeh serve --show myapp.py
-
-
directory format
-
run
$ bokeh serve --show myapp
-
minimum
myapp +--- main.py
-
full set of files
myapp +---main.py +---server_lifecycle.py +---theme.yaml
-
include data files and models
myapp +---data | +---things.csv +---main.py +---models | +---custom.js +---server_lifecycle.py +---theme.yaml
-
demo
from os.path import dirname, join import pandas pandas.read_csv(join(dirname(__file__), 'data', 'things.csv'))
-
-
callbacks and events
-
js callbacks in the browser
-
py callbacks with jupyter interactors
-
py callbacks in bokeh apps
-
py callbacks with
bokeh.client
-
-
application theming
-
lifecycle hooks
-
server
def on_server_loaded(server_context): pass def on_server_unloaded(server_context): pass
-
session
def on_session_created(session_context): pass def on_session_destroyed(session_context): pass
-
example and video tutorials
integration with web app frameworks
deployment scenarios
-
standalone bokeh server
-
reverse proxying with nginx
-
load balancing with nginx
-
process control with supervisord
-
a full e.g. with automation