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?
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: dash/dash/dash.py at 38994ebca24775d6b588051bef6a54699c1eb1ff · plotly/dash · GitHub
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?
Did you ever manage to solve this? I have two versions of the same exact App, one using Flask + Plotly the other one using Dash + Plotly.
The Flask one uses figure_url = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
to send the figure to the html. - takes about 3 seconds, ie. it works on the fly.
The Dash one used dcc.Graph()
to send the figure over to the respective html.Div
defined on the layout. - takes about 110 seconds (ie. 1min and 50 sec).
Something is wrong with dcc.Graph
.
Oh. this is disappointing… I have a Flask + Plotly app that’s working fine but I want to extend it with callbacks, etc. so I’m creating a new page that I had planned to be Dash + Plotly while keeping the other pages as they are. I’ve just figured out the bit about wrapping Dash and Flask objects together and was about to start building the Dash side. I am not fond of the idea of waiting two minutes to load…