🚀 Gen 5 of the leading AI app deployment platform launches October 6. Click for the livestream.

Update plot in dash from REST API

I’m attempting to receive data from a POST request and plot the resulting data. As a initial test I’m simply attempting to display the json data. How can I create a callback which accepts the data from the POST and put it into a Div?
Here is my code so far:

from flask import Flask, jsonify, abort, make_response, request, url_for
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pprint

server = Flask(__name__)
app = dash.Dash(__name__, server=server)

styles = {
    'pre': {
        'border': 'thin lightgrey solid',
        'overflowX': 'scroll'
    }
}

nice_text = "{}"

def serve_layout(nice_text):
    return html.Div(children=[
        html.H1(children="Python version of the JSON viewer"),
        html.Div([dcc.Markdown(nice_text)]),
        html.Pre(id='json_data', style=styles['pre']),
        html.Div(id='cache', style={'display': 'none'})
    ])

@server.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

@server.route('/VA', methods=['POST'])
def generate_response():
    if not request.json or not 'data' in request.json:
        abort(400)
    nice_text = pprint.pformat(request.json)
    
    return nice_text, 201


app.layout = serve_layout(nice_text)

# @server.callback(
#     Output('json_data', 'children'),
#     [Input()]
# )

if __name__ == "__main__":
    app.run_server()
2 Likes

I would also like to find a solution to this. I’m not sure it’s even possible as the dash app is hosted at a different route ?

An alternative would be to pass query parameters to the dcc.Location component. However with a large amount of json it’s not very practical.

I’m not quite sure exactly what you’re trying to do. It sounds like you mean some client other than the Dash React client to be making the POST request? In which case, the response will go to that client as opposed to the Dash client app, so the Dash app won’t be able to do any rendering. In general, a Dash app will make a request to the Flask server (based on component properties changing etc) and it will render the response. You can’t really have some arbitrary client post to the server and cause a Dash client to update. Which Dash app would you be updating? There could be many Dash apps currently being served.

You could make a Flask endpoint that accepts POST requests which updates a database and have you Dash app use a callback which retrieves current values from the database. But this endpoint can’t trigger an app to draw a plot though.

I think what is essentially required to make this possible is to have the dcc.Location (or another component) pass on json/data from a get/post request. Then dash can render a layout based on what is passed as json.

1 Like

That’s pretty much exactly what I’m looking for. I have a working d3.js implementation, but I wanted to do it in Python since I’m more comfortable in that environment.

Ultimately, what I’m looking to do is create data driven content in SAS Viya. So, Viya will contain the data and will send bits that need to be visualized via a POST message. The dash app should receive that message and draw a plot (in my case I want a venn diagram).

Here is a working example (it has default data to begin with)
http://drjeckyl.github.io/venn.js/examples/VA_venn_diagram.html

if you care to look at the source it’s in:

Dash doesn’t currently have any ‘push’ functionality, meaning that external connections can’t push events to the renderer. So you should be thinking about Dash requesting information rather than automagically receiving information.

It sounds like the general pattern of a) having your JSON POST endpoint save your data somewhere and b) having your dash app read from that location, could be the way to go.

There’s lots of ways you can do this, so long as you avoid the trap of storing this data as global variables. Which one you choose depends on the needs of your app. if you only ever need to retrieve the last submitted data, you could just save it to disk and read that file in Dash. Or even save to a directory and have the Dash interface present to you a selection of files. If you need any more complexity to how results are retrieved, you’ll probably need to use a database to manage results. sqlite would be a could choice for this kind of thing.

1 Like

Ok, as an update. I’ve since learned that what I want to do is not actually use POST, but rather interact with the app via messages.

Hence the javascript using event handlers

	messagingUtil.setOnDataReceivedCallback = function(callback)
	{
		var onMessage = function (evt) {
			if (evt && evt.data && evt.data.hasOwnProperty("data"))
			{
				callback(evt.data);
			}
		}
		
		if (window.addEventListener) {
			// For standards-compliant web browsers
			window.addEventListener("message", onMessage, false);
		}
		else {
			window.attachEvent("onmessage", onMessage);
		}
	};

Is there a way to implement this same functionality in Dash/Plotly? Or Flask?

Is it possible to then use a flask-wtf form that people can fill in and graphs get updated from this on the dashboard? If so, would love you input. I’ve started a topic here on this: How to connect Flask wtf-form responses to a Plotly Dash Dashboard

@DrJeckyll Is your server.errorhandler working in this app?

I have been trying to handle 403 errors without success and was just wondering if anyone had success with this.

How then to update the dash components when new data is posted? Sould I poll the file or there is a smarter way?