Lazy Loading of Charts

Is there a way (using Plotly Dash) to render charts only when the chart is in the viewport? For example, if I have 50 charts on the page, I would like to render the first 10 charts and then only load the remaining charts as the user scrolls down the page.

Here’s an example from another charting library?
https://www.amcharts.com/docs/v3/tutorials/lazy-loading-120-charts-page/

1 Like

I am looking for something like this! This is a pretty old post. Let me know if you found any solution to this. Please update!

@skwolvie

I think that if you have the graph in different Tabs you could use the “value” property of the dcc.Tabs as Input for the graph figure update, and only trigger the callback when this value is equal to the Tab where your graphics are.
Also use prevent_initial_call=True after the Input in the decorator to avoid the callback to trigger when the app is loaded

    @app.callback(Output('graph 1', 'figure'),
                   Input('my_Tabs', 'value'),
                   prevent_initial_call=True
    )

how to set the prevent_initial_call=False to first tab (Tab1) and True for all other tabs

@skwolvie

It prevents the entire callback to fire, if you want update just one tab you need to split the code in two different callbacks.

Im new to this how do you suggest I do that?

This is my code:

app = dash.Dash(__name__, meta_tags=[{
      'name': 'viewport',
      'content': 'width=device-width, initial-scale=1.0'
    }])

#prevent_initial_callbacks=True
    
server=app.server
abs_styles = {'display': 'inlineBlock', 'height': 'auto', 'width': 'auto',
               'position': 'fixed', "background": "#323130", 'top': '12.5vh', 'left': '7.5vw',
               'border': 'grey', 'border-radius': '4px'}

tab_style = {
    "background": "#323130",
    'text-transform': 'uppercase',
    'color': 'white',
    'border': '#A9A9A9',
    'font-size': '10px',
    'font-weight': 600,
    'align-items': 'center',
    'justify-content': 'center',
    'border-radius': '4px',
    'padding':'6px'
}

tab_selected_style = {
    "background": "#A9A9A9",
    'text-transform': 'uppercase',
    'color': 'white',
    'font-size': '10px',
    'font-weight': 600,
    'align-items': 'center',
    'justify-content': 'center',
    'border-radius': '4px',
    'padding':'6px'
}

app.layout = html.Div([
    dcc.Tabs(id='tabs-example', value='tab-1', mobile_breakpoint=0, children=[
        dcc.Tab(label='India', value='tab-1',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Ahmedabad', value='tab-2',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Bengaluru', value='tab-3',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Chennai', value='tab-4',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Hyderabad', value='tab-5',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Kolkata', value='tab-6',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Mumbai', value='tab-7',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='Pune', value='tab-8',style=tab_style, selected_style=tab_selected_style),
        dcc.Tab(label='NCR', value='tab-9',style=tab_style, selected_style=tab_selected_style)
    ]),
    html.Div(id='tabs-example-content'),
    html.Div(id='footnote', style={'text-align': 'right', 'font-size':14, 'color': 'black', 'font-family': 'cursive'})
])

@app.callback(Output('tabs-example-content', 'children'),
              Output('footnote', 'children'),
              Input('tabs-example', 'value'))
#prevent_intial_call=True
def render_content(tab):
    if tab == 'tab-1':
        return html.Div([
            dcc.Graph(id='g2', figure=india)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"
    elif tab == 'tab-2':
        return html.Div([
            dcc.Graph(id='g2', figure=ahm)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"
    elif tab == 'tab-3':
        return html.Div([
            dcc.Graph(id='g2', figure=blr)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

    elif tab == 'tab-4':
        return html.Div([
            dcc.Graph(id='g2', figure=che)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

    elif tab == 'tab-5':
        return html.Div([
            dcc.Graph(id='g2', figure=hyd)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

    elif tab == 'tab-6':
        return html.Div([
            dcc.Graph(id='g2', figure=kol)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

    elif tab == 'tab-7':
        return html.Div([
            dcc.Graph(id='g2', figure=mum)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

    elif tab == 'tab-8':
        return html.Div([
            dcc.Graph(id='g2', figure=pune)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

    elif tab == 'tab-9':
        return html.Div([
            dcc.Graph(id='g2', figure=ncr)], 
            className="row", 
            style={"display": "block","margin-left": "auto","margin-right": "auto"}), "Data Source: housing.com"

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

Hey @skwolvie

You are using Method 1 of the Tabs documentation, then tabs_example_contents is the unique output for all the options. This could be a problem because In Dash you can not target the same output with different callbacks.

If you use the Method 2, you will have one dcc.Div in each dcc.Tab in the layout, then you can split the callbacks. But you will need one callback for each Tab.

Another alternative is using multiplexertransform from @Emil enrichment components to target one output from different callbacks:

Then you can have one collback only for the Tab you want to update and the other with the rest of the Tabs, both with the same structure except for the prevent_update option.