✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Switching tabs incredibly slow

I have an app with several menus on the top and two tabs on the bottom.
One tab shows a datatable and one shows several graphs.
Switching between these tabs is incredibly slow. I have limited the display of the datatable to only the first 20
rows. Switching from the datatable tab to the graph tab takes around FIVE seconds, and switching to the
datatable tab sometimes makes the app freeze completely when it has too many columns (~30, not exactly an obscene amount of columns)
How can I improve the performance?

@Snizl

We would like to investigate deeper if it’s performance related, but it’s not convenient for the community to debug from the text, can you share the code or a dummy version which can reproduce the problem? thanks

Byron

I understand, that it is difficult with this.
However the code complete code for this would be around 2000 lines, so it does not really make sense to post it here.
The section with the tabs is the following:

#tabs section start
    dcc.Tabs(id='tabs', children=[
             dcc.Tab(label='Table', 
                     children= [html.Table(id='output-data-upload'),

                                            ]),
                     #calling the table
                             
             dcc.Tab(label='Graph',
                     #calling the graph 
                     children= [html.Div([
                                     #graph for showing data
                                     html.Div([html.P('Graph Display: '),
                                               html.Div([dcc.Graph(id='migration_data', )],
                                                        id='graph_div'),
                                               ], 
                                          className= 'six columns'),
                                               #graph for showing the image
                                     html.Div([dcc.Graph(id='image-overlay',
                                                         ),
                                               #slider for selection of image
                                               MD.image_slider(),
                                               
                                               html.Div(id='image_slider_output', style={'margin-top': 20},),
                                               html.P('Adjust the brightness of the image'),
                                               MD.brightness_slider(),
                                               html.Div([
                                                    dcc.Markdown(("""
                                                         
                                        
                                                        Click on points in the graph.
                                                    """)),
                                                    html.Pre(id='click-data', style={
                                                'border': 'thin lightgrey solid',
                                                'overflowX': 'scroll'
                                            })]),
                                                MD.track_comment(),
                                                MD.comment_submit(),
                                                html.P('Do you want to flag all, or a single timepoint?'),
                                                MD.flag_options(),
                                                MD.save_path(),
                                                MD.save_button(),

                                                  ],className='six columns', )
                                          
                                               
                                 ], className='row')]
                                 
                     )
            ]),

Which I believe is not very helpful for trouble shooting either.

I’m having the same issue, its really slow switch tabs with multiple subtabs under it. I have used both callback methods for tabs but both still are slow (5-10 second loading time). I have graphs and dash data tables. Could be normal?

Did anybody every find a solution to this?
I have the same situation.
3 tabs.
Seven charts on one tab.
text on other two tabs.
When I switch Back to the charts tab it is very slow.
I am not using callbacks for populating the charts, they are populated when the page loads.
I see in my debug info that no server side code is executed when tab switching happens…

Thanks

We’re working on some performance enhancements right now. Could you share a simple, reproducible example that demonstrates the performance issues?

Hi @chriddyp,
Thanks for your response.
I’m afraid this problem does not arise in a simple example.
When I started out with this, using a couple of graphs then performance was fine.
Its only when I am past the point of no return on the project that I now find I am in trouble.
There is a huge amount of code involved now.
If you want to PM me then I can send you a link to see what this looks like in practise.

Thanks

Hi, @peej
Having the same issue with tabs. It takes too much time to switch between two views. I am using the second method from the tutorial. It seems, what the problem is really due to the ploty’s browser behaviour, because there is no any request to the server.
However, I’ve managed to solve the issue for me. I am using tabs from dash-bootstrap-components library
link. Now it seems to work much faster!

Hi @garrick,
Thanks very much.
I will try that now and see how I get on.
Thanks

Hi again @garrick,
Yeah, I changed the code to use the dbc tabs.
But it only shaved a second off the display switch time… 5 secs down to 4 secs.
I am using the “Tabs with callback” approach.

I think its just too much data… I have seven charts on one tab and its the switching back to that tab after it has been rendered initially that is really slow.

I’ve been trying to model my dashboard on a similar Shinyapps one… and it falls down on this point.
The shinyapps can render a page/tab initially showing spinners… but then when you switch between pages there is no perceptible delay.

The shinyapp dashboard I am comparing against has 9 charts/graphs on the page.

Hi @chriddyp,
Is there any way to improve performance of switching tabs.
The same issue I am facing. Initially, for small data and charts, everything is fine… but now for some tabs, it is taking more than 5 seconds

Thanks for reporting! We’ve noticed something similar - Currently the dash code crawls through all of the rendered components on the page to see if it needs to display a loading component whenever an update changes. So, if you have 1000 components on the page (which is very easy to achieve if you are using html.Table because each cell is a component), the it’ll crawl through 1000 items and perform some checks on each item. Most of the time it’s unnoticeable, but in certain apps it can feel pretty slow.
We’re reworking this part of the code right now in https://github.com/plotly/dash/pull/1254. It will be available in the next release and we’d love your feedback once it’s out!

This request still stands! We can only fix issues that we can reproduce, so if anyone can create an example with synthetic or mock data (eg it could be the same string in every element) that mimics the structure and number of components in your app, that’s be much appreciated.

Hi @chriddyp,
I’m sorry, I’m up to my ass trying to get this dashboard finished.
So I’ll try make an example in July when the deadline is over.

But in the meantime I can tell you that I sort-of fixed the problem for myself by moving to a multipage app instead of tabs.
Also, importantly, in the tabs, I had been just populating the charts on the layout directly… without using callbacks.

dbc.Row(
                [
                    dbc.Col(
                        dcc.Loading(id="loading-1", children=[
                            dcc.Graph(figure=wave1_figs.get_mychart(df) , config={'displayModeBar': False } )
                        ], type="default")
                    , width=8),
                    dbc.Col(html.Div(dcc.Markdown(w1.para_2, dangerously_allow_html=True) )),
                ]
            ),

Note: get_mychart() is just a python function, so its being called synchronously.

And I have since changed that, started using callbacks and am using a dcc.loading on all of them.

dbc.Col( [
                    dbc.Card([dcc.Loading(id="loading-1", children=[
                        html.H1('People Chart'),
                        dcc.Graph(id='home_peopleyoumeet', className="pretty_container" )
                        ], type="default")
                    ]) # end card
                ]), # end col

That doesn’t speed anything up but does help with user perceptions cos the page around the charts does render while the rest of the callbacks are being worked on.

What I notice with shiny apps is that, when switching tabs, they just switch and show you the view as it was when you switched to the other tab… when you switch back, they don’t re-render … its only then when you modify some chart filters that it re-renders… Or so it would appear anyway…

Funny enough, when dash switches tabs… it doesn’t appear to be doing any backend calls… so I am confused as to why it should take so long to switch when there is a lot of data…
I suppose if its all happening in the browser then its a question of the RAM and power of the client machine… I wish I had more time to dig into this for you… sorry…

Same is in my case. In one of the tabs I am displaying all tables as soon as data is loaded in the drag and drop data load tab. So after loading when I click on this tab it takes time to show the content.

How do you get the data into the app? Are you using the dcc.Upload component?

Yes I have the data already from upload component.

The dcc.Upload does save the data into its contents property as a string, in the browser (DOM). If you make a table (or graph) from the data, you have doubled the amount of data in the browser memory. Large amounts of data in the browser memory might slow it down, and eventually crash it.

Without seeing your code and the data you are using, it is hard to guess. but if there is large amount of data, maybe it would help to empty the contents of the dcc.Upload element after you have saved it somewhere. Do you think the amount of data could be the problem? How much of data you upload when it starts to slow down?

Wow, I did not knew that the contents data is stored and if I store same data Let us say in a hidden DIV I am duplicating it. How do I clear the contents data from upload after I saved that data in a hidden DIV in json.

Yes and if you put the data into hidden DIV and draw a graph (or create a table), you will have the same data three times, in a bit different formats. I suppose if the amount of data is some tens of Mb, there is a high chance of slowing the browser down. There might be also other parts of your app that may be affecting the speed, but it would be good practice anyway to have only one set of your data in the browser at a time (in one format or another).

I played around with the dcc.Upload component and it looks like the contents string, while visible in the DOM (with React Developer Tools extension), is not accessible from within python. I also did not find any mentions about a “clear contents” -method, so it might be that there is not (yet) such thing. Perhaps the dash-core-components developers can help you with that.

One way to circumvent the problem would be to send the file to the server hard disk as a file, and then read the relevant parts in a callback back to the browser, to the graph/table you want it to be read. I did an upload component (du.Upload) for this purpose in one repository: dash-uploader. This way you could minimize the data stored in the browser. If you need to access the data many times after upload, maybe you could make use of the Flash-Caching with Redis for extra performance.