Rendering multiple scatter plots via clientside callback

Hi All,
I’m having some trouble with scatter plot load speeds. I’m trying to render a 3x9 grid of scatter plots in my dash app. My system works with regular callbacks at the moment and it takes more than 10 seconds to load all the plots. I also added a feature to highlight data points across all plots with an onClick command which is making it run even slower. I’m trying to render the plots via clientside callback instead but keep getting a “Cannot read properties of undefined (reading ‘figure’)” error.

Is it possible to render multiple plots through clientside callbacks? Also am I on the right track here? Will this help my problem or is it just unrealistic to use dash to render this many visualizations.

any help is much appreciated

Thanks!

1 Like

HI @dashingpy
:wave: Welcome to the community.

You might be able to use the Plotly Resampler library to speed up the rendering of the graphs. Otherwise, If you want to render graphs through clientside, here’s an example I created about a year ago where I update the graph title through clientside callback. I realize it’s not an example of a rendering of multiple scatter plots, but I hope it will help you get started.

from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd


df = pd.read_csv('https://raw.githubusercontent.com/Coding-with-Adam/Dash-by-Plotly/master/Callbacks/Client-side-callback/opsales.csv')

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    dcc.Graph(
        id='clientside-graph'
    ),
    dcc.Store(
        id='clientside-store-figure', data={}
    ),
    dcc.Dropdown(
        id='shipping-type',
        options=[
            {'label': x, 'value': x} for x in df['Shipping Mode'].unique()
        ],
        value='Second Class'
    ),
    dcc.Input(
        id='clientside-graph-title',
        value='Placeholder Title'
    ),
])

# Serverside callback
@app.callback(
    Output('clientside-store-figure', 'data'),
    Input('shipping-type', 'value'),
)
def update_store_data(shipping):
    dff = df[df['Shipping Mode'] == shipping]
    stored_figure = px.histogram(dff, x="Customer Segment", y="Sales", color='Department Name')
    # store histogram on client side - browser
    return stored_figure


app.clientside_callback(
    """
    function(figure_data, title_text) {
        if(figure_data === undefined) {
            return {'data': [], 'layout': {}};
        }
        const fig = Object.assign({}, figure_data, {
                'layout': {
                    ...figure_data.layout,
                    'title': {
                        ...figure_data.layout.title, text: title_text
                    }
                }
        });
        return fig;
    }
    """,
    Output('clientside-graph', 'figure'),
    Input('clientside-store-figure', 'data'),
    Input('clientside-graph-title','value')
)


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


Hi Adam,
Thanks for your help, I’ve already got this structure to work on one plot but still having trouble expanding it to multiple, running into the same error as a I mentioned in my earlier post. Would I be better off trying to create individual clientside callbacks for each plot or would combining them into one and returning an array of figures work better.

Also tried figureResampler out and it doesn’t seem to run any faster.

any feedback is much appreciated
thanks!

Hi @dashingpy
It depends. If the computation is shared between graphs (their data update each other), you should do everything in one clientside callback. If the computation is not shared (the graphs are independent of one another), then you can do individual clientside callbacks for each graph.