5

Struggling with Bokeh and Flask to graph data from streaming.

Data source update is scheduled and not managed by Bokeh (I see it is done every second).

How to force a refresh of the graph (possibly not of all the page as there are multiple graphs around in the final version)?

Here is a stripped down and runnable version of the faulty code. Any idea is welcome.

# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd

from bokeh.embed import components
from bokeh.plotting import figure
from bokeh.resources import INLINE
from bokeh.models.sources import ColumnDataSource

from flask import Flask, render_template_string
from flask_apscheduler import APScheduler
from apscheduler.triggers.interval import IntervalTrigger

html_template = """
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        {{ js_resources | safe }}
        {{ css_resources | safe }}
    </head>
    <body>
        <div>
            {{ plot_div.graph_1 | safe }}
        </div>

        {{ plot_script | safe }}
    </body>
</html>
"""
resources = INLINE
js_resources = resources.render_js()
css_resources = resources.render_css()

app = Flask(__name__)

@app.route("/")
def main_graph():

    script, div = components({'graph_1': graph_1.figure,})

    return  render_template_string(html_template,
        js_resources=js_resources,
        css_resources=css_resources,
        plot_script=script,
        plot_div=div)

# -------------------------------------------------------------------------------------------------------------------


class Generic3Lines:

    def __init__(self, scheduler):

        self.data_source = ColumnDataSource()

        self.figure = figure()
        self.figure.axis.visible = True

        self.update_data()

        line1 = self.figure.line(y="value_1", line_color="red",   x="date_time", source=self.data_source)
        line2 = self.figure.line(y="value_2", line_color="blue",  x="date_time", source=self.data_source)
        line3 = self.figure.line(y="value_3", line_color="green", x="date_time", source=self.data_source)

        scheduler.add_job(id="scheduled_update", func=self.update_data, trigger=IntervalTrigger(seconds=1))

    def update_data(self):

        df = pd.DataFrame(dict(
            date_time = range(180),
            "value_1" = np.random.random(size=180)*5+5,
            "value_2" = np.random.random(size=180)*5+10,
            "value_3" = np.random.random(size=180)*5+15,
        ))

        print(df.head(1))

        self.data_source = dict(date_time=df["date_time"],
                                 value_1=df["value_1"],
                                 value_2=df["value_2"],
                                 value_3=df["value_3"],
                                 )

scheduler = APScheduler()
scheduler.start()

graph_1 = Generic3Lines(scheduler=scheduler)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5050)
Alex Poca
  • 2,406
  • 4
  • 25
  • 47
  • Synchronizing front end plots and controls with a minimum of python code, i.e just by setting `.data` to something new, or by using `source.stream` to very efficiently update by only sending the new data is the express purpose of the [Bokeh server](http://bokeh.pydata.org/en/0.12.6/docs/user_guide/server.html), so my suggestion is that you investigate that. – bigreddot Jul 28 '17 at 16:41
  • @bigreddot, bokeh server has been my first idea, but graphs will be just a little part in a more complex (already existing) app based on Flask. I went through Bokeh's documentation but didn't grasp some part of it because normally examples are static or based on Bokeh server only. The previous solution I found was based on AjaxDataSource but, as I wrote in https://stackoverflow.com/questions/45301848/bokehflask-multiple-ajaxdatasource-calls, it brought some problems too... – Alex Poca Jul 28 '17 at 18:37
  • Well I don't have any specific advice then. I think any solution will involve adding JS to your page that makes Rest API or websocket message to either: ask for just the new data, and updates the plots using Bokeh JS APIs, or asks for the full scipt/div for new full plots and rebuilds those dom elements. – bigreddot Jul 28 '17 at 19:39
  • @bigreddot, do you know where to find an example of streaming data managed by bokeh server into flask? It is days I am trying to work it out and cannot develop further /examples/howto/server_embed/flask_embed.py. I read your answer at https://stackoverflow.com/questions/29949712/embedding-a-bokeh-app-in-flask?rq=1 but I don't grasp the docs. An example with – Alex Poca Aug 02 '17 at 07:10
  • @AlexPoca any progress on this? I am trying to do the same! – DevShark Nov 20 '17 at 10:30
  • @DevShark, the project became very big (bokeh is only a little part of it): even a snipped would take too long to extract from the code. Alas I cannot send you the source because it is proprietary. In the end I AM NOT using bokeh server. I requested a demo to add to the examples but I don't know it they wrote it. – Alex Poca Nov 20 '17 at 11:18
  • I see. I am looking for something fairly simple: streaming a chart that refreshes 3 times per seconds. Any advice for the solution? Does using flask+bokeh server seems reasonable? I tried to use flask+bokeh (without the server) but could not make that work – DevShark Nov 20 '17 at 12:23
  • We are using flask with bokeh successfully for streaming real-time data with 2 servers (flask gunicorn and bokeh) running in different Docker containers. It works ok, but we are looking for a way to remove bokeh server and rely on flask only. – Meir Tseitlin Jan 13 '18 at 21:53

0 Answers0