3

I am using a MongoDB to store sensordata(1 Measurement / sec.) and I would like to use flask and bokeh to plot the data in realtime in a web browser. Unfortunately my knowledge regarding web-frameworks is not that good. So far I managed to create a static plot which reads the data from the database (see example below) What would be the best way to update the plot in realtime?

from flask import Flask

import datetime
from pymongo import MongoClient
from bokeh.templates import RESOURCES

from bokeh.plotting import figure
from bokeh.resources import CDN
from bokeh.embed import file_html

app = Flask(__name__)

@app.route('/')
def index():
    client = MongoClient()

    db = client.test
    sdata = db.sensordata

    output = list(sdata.find())

    temp = [x['temperature'] for x in output]

    get_time = lambda x: datetime.datetime.strptime(x['time'], '%Y-%m-%d %H:%M:%S')
    time = [get_time(x) for x in output]

    humidity = [x['humidity'] for x in output]
    plot = figure(x_axis_type = "datetime")
    plot.line(time, temp)
    plot.line(time, humidity)

    html = file_html(plot, CDN, "my plot")

    return html

if __name__=='__main__':
    app.run(host='localhost', debug=True)

EDIT:

I think a solution with flask-socketio would be nice, but im not yet sure how to do it. To embedd the plot I need to create a script and div with script, div = components(plot) see (http://docs.bokeh.org/en/latest/docs/user_guide/embed.html) So the script is put into the html header while the div is put into the body. I don't see how to update the data since it is stored inside script file in the header and not in the div. My Idea was to change the html in the div with :

 <script type="text/javascript" charset="utf-8">
    $(document).ready(function(){
        //connect to the socket server.
        var socket = io.connect('http://' + document.domain + ':' + location.port + '/');

        socket.on('plotupdate', function(msg) {
            $('#plot').html(msg.plot);
        });

    });
</script>

But this doesn't work in this case.

1 Answer 1

3

You can use javascript's setInterval with an ajax call to refresh only a div that contains the plot. Change your route to something like "/plotIt". Showing code using jQuery for a repeated ajax call refreshing a div with id="myPlot" attribute:

setInterval(function() {
      $.ajax({
        url: "/plotit",
        type: "GET",
        dataType: "html",
        success: function (data) {$('#myPlot').html(data);},
    });
}, 60*1000); // Repeat interval is in milliseconds

Haven't tested this code, but it should work OK or with little tweaking.

I'm usually not a huge fan of repeated jobs like this and prefer a more event-driven approach. Namely, using an event listener for new sensor data (listening on mongodb) and pushing a new plot (using e.g. flask-socketio) when a new plot has generated. Choose whichever approach works for you. Above code should at least get you started.

Sign up to request clarification or add additional context in comments.

1 Comment

if the answer above is satisfactory-accept it. You can post a new question geared to socketio/real-time application instead of editing this question to prevent confusion by future readers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.