Skip to content

Instantly share code, notes, and snippets.

@dmitriy-serdyuk
Last active September 8, 2016 18:27
Show Gist options
  • Save dmitriy-serdyuk/bd6cfcc49b5bce0bf2975d93d085053a to your computer and use it in GitHub Desktop.
Save dmitriy-serdyuk/bd6cfcc49b5bce0bf2975d93d085053a to your computer and use it in GitHub Desktop.
import tinydb
from tornado import gen
from functools import partial
from bokeh.models import ColumnDataSource
from bokeh.plotting import curdoc, figure
# this must only be modified from a Bokeh session allback
source = ColumnDataSource(data=dict(x=[0], y=[0]))
# This is important! Save curdoc() to make sure all threads
# see then same document.
doc = curdoc()
p = figure(x_range=[0, 1], y_range=[0, 1])
l = p.circle(x='x', y='y', source=source)
doc.add_root(p)
@gen.coroutine
def update():
db = tinydb.TinyDB('./database.db')
all = db.all()
source.data = (dict(x=[e['time'] for e in all], y=[e['value'] for e in all]))
doc.add_periodic_callback(update, 2000)
import tinydb
from flask import Flask, g, request
PAGE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bokeh Scatter Plots</title>
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-0.12.0.min.css" type="text/css" />
<script type="text/javascript" src="http://cdn.pydata.org/bokeh/release/bokeh-0.12.0.min.js"></script>
</head>
<body>
{}
</body>
</html>
"""
app = Flask(__name__)
def connect_db():
"""Connects to the specific database."""
rv = tinydb.TinyDB("./database.db")
return rv
def get_db():
"""Opens a new database connection if there is none yet for the
current application context.
"""
if not hasattr(g, 'db'):
g.db = connect_db()
return g.db
@app.teardown_appcontext
def close_db(error):
"""Closes the database again at the end of the request."""
if hasattr(g, 'sqlite_db'):
g.sqlite_db.close()
@app.route('/flask/plot')
def hello_world2():
from bokeh.embed import autoload_server
script = autoload_server(model=None, app_path="/bokeh_app")
return PAGE.format(script)
@app.route('/flask/plot/add')
def plot_add():
db = get_db()
db.insert({k: request.args.get(k)
for k in ['plot', 'name', 'time', 'value']})
# but update the document from callback
return 'hi' # What should I return?
#!/usr/bin/env python
import sys
import argparse
import logging
from bokeh.command.subcommands.serve import Serve, build_single_handler_applications, log, die, Server, settings, Application, getpid
from tornado.wsgi import WSGIContainer
from tornado.web import FallbackHandler
from flasky import app
tr = WSGIContainer(app)
class MyServe(Serve):
def invoke(self, args):
# I had to copy-paste it from bokeh since the server is glued into this
# method.
argvs = { f : args.args for f in args.files}
applications = build_single_handler_applications(args.files, argvs)
log_level = getattr(logging, args.log_level.upper())
logging.basicConfig(level=log_level, format=args.log_format)
if len(applications) == 0:
# create an empty application by default, typically used with output_server
applications['/'] = Application()
if args.keep_alive is not None:
if args.keep_alive == 0:
log.info("Keep-alive ping disabled")
else:
log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive)
# rename to be compatible with Server
args.keep_alive_milliseconds = args.keep_alive
if args.check_unused_sessions is not None:
log.info("Check for unused sessions every %d milliseconds", args.check_unused_sessions)
# rename to be compatible with Server
args.check_unused_sessions_milliseconds = args.check_unused_sessions
if args.unused_session_lifetime is not None:
log.info("Unused sessions last for %d milliseconds", args.unused_session_lifetime)
# rename to be compatible with Server
args.unused_session_lifetime_milliseconds = args.unused_session_lifetime
if args.stats_log_frequency is not None:
log.info("Log statistics every %d milliseconds", args.stats_log_frequency)
# rename to be compatible with Server
args.stats_log_frequency_milliseconds = args.stats_log_frequency
server_kwargs = { key: getattr(args, key) for key in ['port',
'address',
'allow_websocket_origin',
'host',
'num_procs',
'prefix',
'develop',
'keep_alive_milliseconds',
'check_unused_sessions_milliseconds',
'unused_session_lifetime_milliseconds',
'stats_log_frequency_milliseconds',
'use_xheaders',
]
if getattr(args, key, None) is not None }
server_kwargs['sign_sessions'] = settings.sign_sessions()
server_kwargs['secret_key'] = settings.secret_key_bytes()
server_kwargs['generate_session_ids'] = True
if args.session_ids is None:
# no --session-ids means use the env vars
pass
elif args.session_ids == 'unsigned':
server_kwargs['sign_sessions'] = False
elif args.session_ids == 'signed':
server_kwargs['sign_sessions'] = True
elif args.session_ids == 'external-signed':
server_kwargs['sign_sessions'] = True
server_kwargs['generate_session_ids'] = False
else:
raise RuntimeError("argparse should have filtered out --session-ids mode " +
args.session_ids)
if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " +
"the `bokeh secret` command can be used to generate a new key.")
server_kwargs['use_index'] = not args.disable_index
server_kwargs['redirect_root'] = not args.disable_index_redirect
# Only difference from vanilla bokeh is extra patterns here:
server = Server(
applications,
extra_patterns=[('/flask/.*', FallbackHandler, dict(fallback=tr))],
**server_kwargs)
if args.show:
# we have to defer opening in browser until we start up the server
def show_callback():
for route in applications.keys():
server.show(route)
server.io_loop.add_callback(show_callback)
if args.develop:
log.info("Using develop mode (do not enable --develop in production)")
address_string = ''
if server.address is not None and server.address != '':
address_string = ' address ' + server.address
log.info("Starting Bokeh server on port %d%s with applications at paths %r",
server.port,
address_string,
sorted(applications.keys()))
log.info("Starting Bokeh server with process id: %d" % getpid())
server.start()
def main(argv):
''' Execute the Bokeh command.
Args:
argv (seq[str]) : a list of command line arguments to process
Returns:
None
'''
parser = argparse.ArgumentParser(prog=argv[0])
# we don't use settings.version() because the point of this option
# is to report the actual version of Bokeh, while settings.version()
# lets people change the version used for CDN for example.
parser.add_argument('-v', '--version', action='version', version=0.12)
subs = parser.add_subparsers(help="Sub-commands")
for cls in [MyServe]:
subparser = subs.add_parser(cls.name, help=cls.help)
subcommand = cls(parser=subparser)
subparser.set_defaults(invoke=subcommand.invoke)
args = parser.parse_args(argv[1:])
try:
args.invoke(args)
except Exception as e:
die("ERROR:" + str(e))
if __name__ == "__main__":
main(sys.argv)
python main.py serve bokeh_app.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment