Search code examples
pythondata-visualizationplotly-dashreal-time-updates

ways to create Python data visualization website receiving realtime asynchronous feed


I'm looking for ways to visualize tick data and put it on a website. I've came across the below methods that have clear limitations.

I am aware that it's possible with node.js libraries but I dont want javascript at all because a) I hate JS as a language, b) d3.js it seems like a overkill for a small project.

Plotly + dash can host real time python applications but foundationally it only support interval updates, not tick updates. It is possible to hack it by setting update function to high frequency but I'm looking for a solution designed for this specific application. This would be my fallack soln if nothing better comes up.

I also came across articles that describes using matplotlib.animations, but I am not aware of a way to put matplotlib live feed on a server website.

Some other articles describe exporting images daily with matplotlib which I find as an abusive usage of the term realtime.

Finally, Python only please.


Solution

  • One option would be to use a websocket to stream the data. You could use e.g. the WebSocket component in dash-extensions==0.0.41. Here is a small example,

    import json
    import dash_html_components as html
    import random
    import dash_core_components as dcc
    import plotly.graph_objects as go
    from gevent import sleep
    from dash import Dash
    from dash.dependencies import Input, Output, State
    from dash_extensions import WebSocket
    from dash_extensions.websockets import SocketPool, run_server
    
    
    # Generator to simulate continuous data feed.
    def data_feed():
        while True:
            sleep(random.uniform(0, 2))  # delay between data events
            yield random.uniform(0, 1)  # the data value
    
    
    # This block runs asynchronously.
    def ws_handler(ws):
        for data in data_feed():
            ws.send(json.dumps(data))  # send data
    
    
    # Create example app.
    app = Dash(prevent_initial_callbacks=True)
    socket_pool = SocketPool(app, handler=ws_handler)
    app.layout = html.Div([dcc.Graph(id="graph", figure=go.Figure(go.Scatter(x=[], y=[]))), WebSocket(id="ws")])
    
    
    @app.callback(Output("graph", "figure"), [Input("ws", "message")], [State("graph", "figure")])
    def update_graph(msg, figure):
        x, y = figure['data'][0]['x'], figure['data'][0]['y']
        return go.Figure(data=go.Scatter(x=x + [len(x)], y=y + [float(msg['data'])]))
    
    
    if __name__ == '__main__':
        run_server(app, port=5000)  # 5000 if the default port
    

    Disclaimer: I am the author of dash-extensions.