Loading Indicator during plot rendering

I have created a simple dash application which uses the plotly express library, I have used the dcc.Loading to show a loading indicator after the input callback is triggered by a button click until the plot is ready.

But given the size of the csv which is currently 250mb and might increase over time, currently the csv file has about 2million records, the indicator stops once the plot is ready but the rendering and display of the plot takes over a second or 2.

I want to continue showing the loading indicator until the plot is completely rendered, is there any possible way to show a similar loading spinner or indicator until the plot is rendered.

I have gone through the plotly documentation and the express plots do not support any loading properties as such.

Posted the code below

import time
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
import numpy as np

df = pd.read_csv(
    '2m Sales Records.csv',
    index_col=0)

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button('Update Plot', id='update-button', n_clicks=0),
    html.Div([
        dcc.Loading(
            id="loading",
            type="default",
            fullscreen=True,
            children=[
                html.Div(id='graph-container')
            ]
        )
    ])
])


@app.callback(
    Output('graph-container', 'children'),
    [Input('update-button', 'n_clicks')]
)
def update_plot(n_clicks):
    x_column = 'Units Sold'
    y_column = 'Total Profit'

    if n_clicks > 0:
        fig = px.scatter(df, x=x_column, y=y_column, title='Scatter Plot')
        fig.update_traces(textposition='top center')

        return dcc.Graph(id='volcano-plot', figure=fig)

    return html.Div()


if __name__ == '__main__':
    app.run_server(debug=True)

Thank you

Hey @Yokogawa-Akshay welcome to the forums.

You could change the callback to return the figure instead of the dcc.Graph(), this should help.

import dash
from dash import dcc, html, Input, Output
import plotly.express as px
import numpy as np

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button('Update Plot', id='update-button', n_clicks=0),
    html.Div([
        dcc.Loading(
            id="loading",
            type="default",
            fullscreen=True,
            children=[
                html.Div(id='graph-container'),
                dcc.Graph(id='graph')
            ]
        )
    ])
])


@app.callback(
    # Output('graph-container', 'children'),
    Output('graph', 'figure'),
    [Input('update-button', 'n_clicks')],
    prevent_initial_call=True
)
def update_plot(n_clicks):
    if n_clicks > 0:
        fig = px.scatter(
            x=np.random.randint(1, 100_000, 2_000_000),
            y=np.random.randint(1, 100_000, 2_000_000),
            title='Scatter Plot'
        )
        fig.update_traces(textposition='top center')

        # return dcc.Graph(id='volcano-plot', figure=fig)
        return fig

    # return html.Div()


if __name__ == '__main__':
    app.run_server(debug=True)

Hey @AIMPED , Thank you for the suggestion. This would lead me to having an empty graph plot initially even before the plot is updated and rendered again, which is not something I would like to have. I want to display the plots only after the button click.

Is there any other possible options which can cover this scenario? If there is a property within plotly which can indicate the rendering is completed in the form of a flag?
Thank you

You can hide the dcc.Graph() initially.

import dash
from dash import dcc, html, Input, Output
import plotly.express as px
import numpy as np

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.Button('Update Plot', id='update-button', n_clicks=0),
        html.Div(
            [
                dcc.Loading(
                    id="loading",
                    type="default",
                    fullscreen=True,
                    children=[
                        html.Div(id='graph-container'),
                        dcc.Graph(id='graph', style={'visibility': 'hidden'})
                    ]
                )
            ]
        )
    ]
)


@app.callback(
    # Output('graph-container', 'children'),
    Output('graph', 'figure'),
    Output('graph', 'style'),
    [Input('update-button', 'n_clicks')],
    prevent_initial_call=True
)
def update_plot(n_clicks):
    if n_clicks > 0:
        fig = px.scatter(
            x=np.random.randint(1, 100_000, 2_000_000),
            y=np.random.randint(1, 100_000, 2_000_000),
            title='Scatter Plot'
        )
        fig.update_traces(textposition='top center')

        # return dcc.Graph(id='volcano-plot', figure=fig)
        return fig, {}

    # return html.Div()


if __name__ == '__main__':
    app.run_server(debug=True)