Issue
Struggling with Flask + Bokeh AjaxDataSource:
I have a function that returns json data:
@app.route("/data", methods=['POST'])
def get_x():
global x, y
x = x + 0.1
y = math.sin(x)
return flask.jsonify(x=[x], y=[y])
I can use use it with a Bokeh AjaxDataSource no problem to create a streaming plot:
source = AjaxDataSource(data_url="http://localhost:5000/data", polling_interval=1000, mode='append')
p = figure()
p.line('x', 'y', source=source)
show(p)
However, when I try to embed this in a flask page, the AjaxDataSource does not query the server. The plot fails to render with no errors. Note that if I use a static plot instead of an AjaxDataSource, it plots fine. Here's the relevant code:
template = Template('''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Streaming Example</title>
{{ js_resources }}
{{ css_resources }}
</head>
<body>
{{ plot_div }}
{{ plot_script }}
</body>
</html>
''')
@app.route("/")
def simple():
streaming=True
source = AjaxDataSource(data_url="http://localhost:5000/data",
polling_interval=1000, mode='append')
fig = figure(title="Streaming Example")
fig.line( 'x', 'y', source=source)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
script, div = components(fig, INLINE)
html = template.render(
plot_script=script,
plot_div=div,
js_resources=js_resources,
css_resources=css_resources
)
return encode_utf8(html)
If anyone has any thoughts, I'd be thankful.
Brian
Solution
First, as a gentle suggestion, please always post complete runnable code examples. It took a few minutes to reproduce all the missing necessary imports, for something that only took seconds to diagnose once there was a runnable script.
UPDATE: Since Bokeh 0.12.15
the workaround described below should not be required. AjaxDataSource
should stream without complaint into an empty CDS with no empty columns created up front.
Recently some of the BokehJS code paths were made more "strict" which is good in almost every instance, but it appears this left a bad interaction with AjaxDataSource
that was not noticed. FWIW when I run example I do see an error in the browser JS console:
Error: attempted to retrieve property array for nonexistent field 'x'
And this is the key to the workround, which is just to make sure the data source does have (empty) columns for x
and y
:
source.data = dict(x=[], y=[])
There is a complete working script below. I'd ask that you please make an issue on the Bokeh issue tracker with this information so that this bug can be prioritized and fixed
from flask import Flask, jsonify
from jinja2 import Template
import math
from bokeh.plotting import figure
from bokeh.models import AjaxDataSource
from bokeh.embed import components
from bokeh.resources import INLINE
app = Flask(__name__)
x, y = 0, 0
@app.route("/data", methods=['POST'])
def get_x():
global x, y
x = x + 0.1
y = math.sin(x)
return jsonify(x=[x], y=[y])
template = Template('''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Streaming Example</title>
{{ js_resources }}
{{ css_resources }}
</head>
<body>
{{ plot_div }}
{{ plot_script }}
</body>
</html>
''')
@app.route("/")
def simple():
streaming=True
source = AjaxDataSource(data_url="http://localhost:5000/data",
polling_interval=1000, mode='append')
source.data = dict(x=[], y=[])
fig = figure(title="Streaming Example")
fig.line( 'x', 'y', source=source)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
script, div = components(fig, INLINE)
html = template.render(
plot_script=script,
plot_div=div,
js_resources=js_resources,
css_resources=css_resources
)
return html
app.run(debug=True)
Answered By - bigreddot
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.