Black Lives Matter. Please consider donating to Black Girls Code today.

_dash-layout and _dash-update component "waiting"

My app takes 8-18 seconds to load a graph with 70,000 data points. The browser profile suggests that most of this is spent “waiting” for _dash-layout and _dash-update component.

Is this reasonable? What to do?

That’s the time required to serve app.layout and run your callbacks, so it’s likely related to the speed of your Python / R code. 70k points in general shouldn’t be too slow.

Am I correct in assuming that initial operations in my flask app (starting flask, loading imports, data structures etc.) occur just once when the server starts?

Surely gunicorn start all that up again with each request?

Correct - all of that happens just once. If app.layout is a constant (not a function), then all of that should be in memory. If app.layout is a function, then that function gets called on page load.

I might be wrong about what “waiting” means actually w.r.t. network requests. Waiting might refer to the fact that only 4 network requests can happen at any given time. So, if there are a few requests that take a long time to finish, then _dash-update-component might be “waiting” for the other requests to finish before it can complete. One would have to dig into the network console terminology to know for sure.

Thanks

This graph suggests that the problem is not a limit in number of network requests.

I’ve done some benchmarking on my local system.
When I trigger fig.show() in jupyter 6+ seconds pass before the figure is visible, whereas writing fig.to_html() to disk and opening it in the browser takes considerably less.

The bottle neck (the wait) seems to be in the python-based components that prepare the figure for rendering.
In the app, that’s dcc.Graph in jupyter I suspect the plugin uses that too…

In the browser it’s something else?

I have experienced similar performance issues with graphs that have a lot of data points and are created using the python objects of the plotly library.

I assume you are using this library and the go.Figure objects.

What I would advise you to do is to try a quick example of a stripped down plot that is a simple dict instead of a go.Figure object.

So, go into your layout and your callbacks and whereever you are using the go.Figure object, try to insert the corresponding dict structure that is the figure.

Hm, I suppose it could be. The main thing that happens is we serialize the component to JSON. We do this in the plotly library too in Jupyter or when writing to HTML (dash uses the same JSON serializer). If you want to test this how long this takes, you can run:

import plotly
import json


component = dcc.Graph(figure=...)

json.dumps(component, cls=plotly.utils.PlotlyJSONEncoder)

Then, flask sends it over the wire. We do compress the request with gzip, which I suppose could take some time although it is supposed to make the payload smaller for the request. You could try turning off gzip with dash.Dash(__name__, compress=False) to see if that’s the bottleneck.

Here’s the code that serves up the layout via the _dash-layout request: https://github.com/plotly/dash/blob/38994ebca24775d6b588051bef6a54699c1eb1ff/dash/dash.py#L483-L490

Thanks Chris,

Unfortunately, compress=False makes a small difference, but it’s not the big issue.

I’ve also determined that including dash libraries in a simple flask app changes the memory load from 80K to over 400K.

My full app includes dash, dbc, dcc as well as plotly and the memory load is slightly over a gig.
This overloads heroku 2x server @$50 / month.

Is this to be expected?