Search code examples
pythonflaskplotly-dashcytoscape

Receive data via a rest call using Flask and Dash and update the graphs


I am implementing a flask application on which I want cytoscape graphs on it. I also want to dynamically update the data by sending a rest API call on the flask application and based on the data the cytoscape graph updates the graphs.

This is the code I have written to do so, but the update process is slow i.e. it receives the data but that data isn't updated on the dash code.

import dash  # pip install dash
import dash_cytoscape as cyto  # pip install dash-cytoscape==0.2.0 or higher
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input
import pandas as pd  # pip install pandas
import plotly.express as px
import requests
from flask import Flask, request   


external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

server = Flask(__name__)
app1 = dash.Dash(__name__, server=server, external_stylesheets=external_stylesheets)

@server.route('/data', methods=['POST'])
def query_example():
    global data_out
    data =  request.get_data()
    data = (literal_eval(data.decode('utf8')))["data"]
    print("Data Received")
    with open('topology_data.pkl', 'wb') as f:
        pickle.dump(data, f)
    return {"Data":True}

with open('topology_data.pkl', 'rb') as f:
    data_out = pickle.load(f)


app1.layout = html.Div([
    html.Div([
        cyto.Cytoscape(
            id='org-chart',
            layout={'name': 'breadthfirst'},
            style={'width': '100%', 'height': '500px'},
            elements=data_out,
            stylesheet=[
                            # Group selectors
                            {
                                'selector': 'node',
                                'style': {
                                    'content': 'data(label)',
                                    'background-color': 'green',
                                    'line-color': 'green'
                                }
                            },
                            {
                                'selector': 'edge',
                                'style': {
                                    'background-color': 'green',
                                    'line-color': 'green',
                                    'label': 'data(label)'
                                }
                            },
                            {
                                'selector': '[weight = 1]',
                                'style': {
                                    'line-color': 'red'
                                }
                            }
                            ]
        )
    ], className='six columns'),

], className='row')


if __name__ == '__main__':
    app1.run_server(debug=True)

Please tell me a solution to integrate the data receiving process using the REST API and updating the data on the graphs.


Solution

  • You need to use callbacks to update the data.

    @app.callback(Output('org-chart', 'elements'),
            [Input("button", "n_clicks")],
        def update_data(nclicks):
            """Retrieves data from api call    
            
            Parameters
            ----------
            nclicks : int | None
                The number of times the button was pressed.
                Used to prevent initial update with empty state.
    
            """
            if nclicks in [0, None]:
                raise PreventUpdate
            else:
                data = api_call()
                return data
    

    You can find a lot more details and an example on https://dash.plotly.com/cytoscape/callbacks under "Adding and removing elements"

    You need to add a button in your app layout of course

    html.Button('Make api call', id='button', n_clicks=0)