Last active
September 8, 2016 18:27
-
-
Save dmitriy-serdyuk/bd6cfcc49b5bce0bf2975d93d085053a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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