Skip to content

Instantly share code, notes, and snippets.

@telegraphic
Created June 3, 2018 05:07
Show Gist options
  • Save telegraphic/6e192491af08c0655e106cea5dfc8e0b to your computer and use it in GitHub Desktop.
Save telegraphic/6e192491af08c0655e106cea5dfc8e0b to your computer and use it in GitHub Desktop.
Example bottle.py app showing how to embed Bokeh plots that update dynamically with AJAX, using AjaxDataSource.
"""
# app.py -- Example bottle.py app showing how to embed AJAX Bokeh plots that update automatically.
"""
from bottle import *
from bokeh.plotting import figure
from bokeh.embed import components
from bokeh.resources import CDN
from bokeh.models.sources import AjaxDataSource
from bokeh.layouts import gridplot
import simplejson as json
import numpy as np
####################
## MAIN WEBSERVER ##
####################
@route('/dashboard')
def show_dashboard():
""" Generate HTML for main dashboard """
adc_plot = bokeh_adc_plot()
bandpass_plot = bokeh_bandpass_plot()
return template('dashboard.html', adc_plot=adc_plot, bandpass_plot=bandpass_plot)
####################
## AJAX CALLBACKS ##
####################
@route('/adc_data/<idx>')
@route('/adc_data/<idx>', method='POST')
def bokeh_adc_data(idx):
""" Return JSON data for ADC RMS plot.
Returns JSON data when requested. Used by Bokeh AjaxDataSource """
idx = int(idx)
a = np.random.normal(size=1024) * (float(idx) + 1)
b = np.random.normal(size=1024) * (float(idx) + 1)
pola, bins = np.histogram(a, bins=31, range=(-64, 64))
polb, bins = np.histogram(b, bins=31, range=(-64, 64))
return json.dumps({'bins': list(bins[:-1]), 'pola': list(pola), 'polb': list(polb)})
@route('/bandpass_data/<idx>')
@route('/bandpass_data/<idx>', method='POST')
def bokeh_bandpass_data(idx):
""" Return JSON data for bandpass plot.
Returns JSON data when requested. Used by Bokeh AjaxDataSource """
idx = int(idx)
pola = np.random.normal(size=1024) * (float(idx) + 1)
polb = np.random.normal(size=1024) * (float(idx) + 1)
f = np.linspace(1.1, 1.5, 1024)
return json.dumps({'f': list(f), 'pola': list(pola), 'polb': list(polb)})
####################
## BOKEH PLOTTING ##
####################
def bokeh_adc_plot():
""" Generate ADC RMS bokeh layout.
Creates 13x plots in a grid layout. Each plot has a AjaxDataSource that updates automatically.
"""
n_sources = 13
sources, plots = [], []
for n in range(n_sources):
# Create AJAX data source
source = AjaxDataSource(data_url='/adc_data/%i' % n, polling_interval=2000, mode='replace')
a = np.random.normal(size=1024) * (float(n) + 1)
b = np.random.normal(size=1024) * (float(n) + 1)
pola, bins = np.histogram(a, bins=31, range=(-64, 64))
polb, bins = np.histogram(b, bins=31, range=(-64, 64))
source.data = dict(bins=bins[:-1], pola=pola, polb=polb)
sources.append(source)
# Generate bokeh plot
plot = figure(plot_height=150, plot_width=150, title=str(n))
plot.line(source=source, x='bins', y='pola')
plot.line(source=source, x='bins', y='polb', color='green')
plots.append(plot)
# Put plots into a grid layout
plots.append(None)
PP = gridplot([
[plots[ii] for ii in range(0, 7)],
[plots[ii] for ii in range(7, 14)]
])
# Generate the HTML and javascript required for embedding
script, div = components(PP, CDN)
return script, div
def bokeh_bandpass_plot():
""" Generate Bandpass bokeh layout.
Creates 13x plots in a grid layout. Each plot has a AjaxDataSource that updates automatically.
"""
n_sources = 13
sources, plots = [], []
for n in range(n_sources):
source = AjaxDataSource(data_url='/bandpass_data/%i' % n, polling_interval=2000, mode='replace')
pola = np.random.normal(size=1024) * (float(n) + 1)
polb = np.random.normal(size=1024) * (float(n) + 1)
f = np.linspace(1.1, 1.5, 1024)
source.data = dict(f=f, pola=pola, polb=polb)
sources.append(source)
plot = figure(plot_height=150, plot_width=150, title=str(n))
#plot.vbar(source=source, x='x', bottom=0, width=0.5, top='y')
plot.line(source=source, x='f', y='pola')
plot.line(source=source, x='f', y='polb', color='green')
plots.append(plot)
plots.append(None)
PP = gridplot([
[plots[ii] for ii in range(0, 7)],
[plots[ii] for ii in range(7, 14)]
])
script, div = components(PP, CDN)
return script, div
##########
## MAIN ##
##########
if __name__ == '__main__':
# Option parsing to allow command line arguments to be parsed
from optparse import OptionParser
p = OptionParser()
p.set_usage('app.py [options]')
p.set_description(__doc__)
p.add_option("-i", "--hostip", dest="hostip", type="string", default="0.0.0.0",
help="change host IP address to run server. Default is localhost (127.0.0.1)")
p.add_option("-p", "--hostport", dest="hostport", type="int", default=8888,
help="change host port for server. Default is 8888")
(options, args) = p.parse_args(sys.argv[1:])
hostip = options.hostip
hostport = options.hostport
# Development mode
debug(True)
# Start bottle server
# See: http://bottlepy.org/docs/dev/tutorial_app.html#server-setup
run(host=hostip, port=hostport, reloader=True, server=PasteServer)
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Bokeh includes-->
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-0.12.13.min.css" type="text/css" />
<script type="text/javascript" src="http://cdn.pydata.org/bokeh/release/bokeh-0.12.13.min.js"></script>
</head>
<body>
<div>
<h1>ADC RMS</h1>
{{!adc_plot[1]}}
</div>
<div>
<h1>Bandpass</h1>
{{!bandpass_plot[1]}}
</div>
{{!adc_plot[0]}}
{{!bandpass_plot[0]}}
</body>
</html>
@telegraphic
Copy link
Author

@rbiswas4
Copy link

rbiswas4 commented Dec 3, 2020

I was trying to run this to get a working example. If I go to the localhost and port I see a Jupyter Authentication page, which was not what I was expecting. Can you please confirm this should not be what I see. Thanks!

@telegraphic
Copy link
Author

Sounds like you have a jupyterhub server running on that port already. You'll need to stop jupyterhub, or use the -p option to select a different port.

PS: I've been using https://plotly.com/dash/ for my most recent project, which might be work checking out if you're not tied to bokeh + flask.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment