I need to visualize embedded multiple graphs from streaming data on a web browser for a quick visualization. Alas my knowledge of Javascript is null and I thought to know a little of Bokeh before this test, but it looks like I don't.
I am very confused by the dozens of examples that you can find around but don't work with the last Bokeh library (0.12.6). Already gave a look to Streaming two line graphs using bokeh, but alas I need to use Flask.
I help to understand where the proper direction to solve the problem is, not to rewrite my code.
Up to now I found a solution but it is very CPU consuming (this is a working code, sorry for the length: I stripped it down already). Again, it refreshes the whole page instead of the graphs only. It is ok in Chromium 58 (Linux), very slow in Firefox 53 (Linux).
Change Bokeh to another library is an option. Flask is compulsory.
app.py:
from bokeh.models import (FactorRange, LinearAxis, Grid, Range1d)
from bokeh.models.glyphs import Line
from bokeh.plotting import figure
from bokeh.embed import components
from bokeh.models.sources import ColumnDataSource
from flask import Flask, render_template
import random
app = Flask(__name__)
class SingleLine():
def __init__(self, color, elem_number):
self.color = color
self.elem_number = elem_number
self.data = {"time": [], "value": []}
for i in range(1, elem_number + 1):
self.data['time'].append(i)
self.data['value'].append(random.randint(1,100))
def create_line_plot(self, plot, x_name, y_name):
source = ColumnDataSource(self.data)
glyph = Line(x=x_name, y=y_name, line_color=self.color)
plot.add_glyph(source, glyph)
#----------------------------------------------------------------------------------
class CompleteGraph():
def __init__(self, lines_list, x_name, y_name, title, height=300, width=1000):
self.lines_list = lines_list
self.x_name = x_name
self.y_name = y_name
self.title = title
self.height = height
self.width = width
def create_graph(self):
xdr = FactorRange(factors=self.lines_list[0].data[self.x_name])
ydr = Range1d(start=0, end=max(self.lines_list[0].data[self.y_name]) * 1.5)
plot = figure(title=self.title, x_range=xdr, y_range=ydr,
plot_width=self.width, plot_height=self.height,
h_symmetry=False, v_symmetry=False,
tools=[],
responsive=True)
for l in self.lines_list:
l.create_line_plot(plot, self.x_name, self.y_name)
xaxis = LinearAxis()
yaxis = LinearAxis()
plot.add_layout(Grid(dimension=0, ticker=xaxis.ticker))
plot.add_layout(Grid(dimension=1, ticker=yaxis.ticker))
return components(plot)
@app.route("/")
def chart():
elem_number = 30
line1 = SingleLine(color="#ff0000", elem_number=elem_number)
line2 = SingleLine(color="#00ff00", elem_number=elem_number)
line3 = SingleLine(color="#00ff00", elem_number=elem_number)
# first graph
lines_list = [line1, line2]
lg1 = CompleteGraph(lines_list, "time", "value", "title graph 1")
# second graph
lines_list = [line1, line3]
lg2 = CompleteGraph(lines_list, "time", "value", "title graph 2")
script1, div1 = lg1.create_graph()
script2, div2 = lg2.create_graph()
return render_template("test_stackoverflow.html",
div1=div1, script1=script1,
div2=div2, script2=script2,
)
if __name__ == "__main__":
app.run(port=5000, debug=True)
and the respective template:
test_stackoverflow.html
<html>
<head>
<style>
#wrapper { display: flex; }
#left { flex: 0 0 50%; }
#right { flex: 1; }
#wide { flex: 0 0 90% }
</style>
<title>Multiple realtime charts with Bokeh</title>
<link href="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.6.min" rel="stylesheet">
<link href="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.6.min.css" rel="stylesheet">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.6.min.js"></script>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.6.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
(function worker() {
$.ajax({
url: '/',
success: function(data) {
location.reload();
},
complete: function() {
// Schedule the next request when complete
setTimeout(worker, 1000);
}
});
})();
</script>
</head>
<body>
<div id="wrapper">
<div id="left">
<h1>left graph</h1>
{{ div1 | safe }}
{{ script1 | safe }}
</div>
<div id="right">
<h1>right graph</h1>
{{ div2 | safe }}
{{ script2 | safe }}
</div>
</div>
</body>
</html>
Any help is welcome.