Announcing Dash Bio 1.0.0 🎉 : a one-stop-shop for bioinformatics and drug development visualizations.

Plotting large number of plots of a single page

I have a Pandas data frame with around 100 rows.

In my call back I am following the example in the recipe dash-add-graphs-dynamically.py to dynamically create a plot for each row of the data frame.

For the data, the x-axis is one of the columns and y-axis is another column.

When I do this, the page takes forever to load and gets stuck and I’ll have to kill my browser then.
Is there a proper way to deal with this scenario?

Here is an example of the data frame I am using:

        label        date        value
0      label1      2018/01/02    12
1      label1      2018/01/03    14
2      label2      2018/01/03    32
2      label2      2018/01/03    45
...
...
100   label100    2018/09/02    98

Here there will be 1 plot each for label1, label2, etc. The a-axis will be date. y-axis will be the value. So far each label, it’ll the value plotted across dates.

This is somehow causing the page t freeze up. If I reduce the number of rows, it seems fine.

I discovered what was causing the slow down.

I have this code inside a for-loop:

graphs.append(html.P([
                dcc.Graph(
                    id='graph-{}'.format(label),
                    figure={
                        'data': data,
                        'layout': layout
                    }
                ),
                html.Br()
            ]))

The layout here is a go.Layout(). If I remove the layout from the figure, it takes under 3s. If I have the layout it takes more than 11s. Anyone knows what’s going on?

It’s hard to say without seeing a complete example, but perhaps it’s the validation that go.Layout does. Alternatively, you could try to just use dict, which doesn’t do any validation.

Using a dict() instead of go.Layout doesn’t help much. It is still the same. I’ll try to create a toy example of this scenario.

In the mean time, here is the code I have:

@app.callback(Output('by-tc_container', 'children'),
             [Input('by-tc_container', 'id'),
              Input('ver-dropdown', 'value'),
              Input('dropdown1', 'value'),
              Input('metric-dropdown', 'value')])
def display_graphs(id, version, ip, metric):
    df_steadystate = get_steady_state_data(version, ip)
    graphs = []

    if not df_steadystate.empty:
        # t0 = time.time()
        cases_sorted = df_steadystate.caseid.sort_values()
        # t1 = time.time()
        # print("Time taken to sort df: {}".format(t1-t0))

        t0 = time.time()
        for case in cases_sorted:
            data = []
            # t0_filtered = time.time()
            df_filtered = df_steadystate.loc[df_steadystate.caseid == case]
            # t1_filtered = time.time()
            # print("Time for filtering: {}".format(t1_filtered-t0_filtered))

            # t0_scatter = time.time()
            plot_data = go.Scatter(
                x=df_filtered['runid'],
                y=df_filtered[metric],
                mode='lines+markers',
                name=testcase,
                hoverinfo='y',
                line=dict(
                    shape='spline'
                )
            )
            data.append(plot_data)
            # t1_scatter = time.time()
            # print("Time for scatter: {}".format(t1_scatter-t0_scatter))

            layout = dict(
                title = testcase,
                titlefont=dict(
                    size=28,
                ),
                xaxis=dict(
                    title='Versions',
                    showticklabels=True,
                    type='category',
                    exponentformat='none',
                    showexponent='all',
                    categoryorder='category ascending'
                ),
                yaxis=dict(
                    title = metric,
                    showticklabels=True,
                    tickangle=45,
                    exponentformat='none',
                    showexponent='none'
                ),
                legend=dict(
                    y=0.5,
                    traceorder='reversed',
                    font=dict(
                        size=16
                    )
                ),
                hovermode='closest',
            )

            t0_graph_append = time.time()
            graphs.append(html.P([
                dcc.Graph(
                    id='graph-{}'.format(case),
                    figure={
                        'data': data,
                        'layout': layout
                    }
                ),
                html.Br()
            ]))
            t1_graph_append = time.time()
            print("Time taken for graph append: {:.8f}".format(t1_graph_append-t0_graph_append))

        t1 = time.time()
        print("Time taken for for-loop: {:.2f}".format(t1-t0))

    return html.Div(graphs)

And this is part of the main layout which are used as inputs and outputs for the callback:

html.Div(id='by-tc_container'),
html.Div(dcc.Graph(id='empty', figure={'data': []}), style={'display': 'none'}),