Lazy Loading for Dynamic Graphs in Dash

Hi,

I’m trying to create graphs dynamically. Basically, I load some json data from a server and I want to make a LOT of graphs out of it (I want to split them up by dropdowns and pages later but for now we have at least 2,000 we are looking at. I’m planning to allow the user to search by name later).

I get the data from an API which gives it to me all at once, so I’m forced to wait for the data, but I want the user to see a blank graph of all the graphs that are being created/loading this data. I don’t want them all to be forced to load at once (making the user wait quite a long time). Is there a way I can break up this data over a loop and create these graphs dynamically with callbacks? The graph-creating process is slow enough that lazy loading them seems like a good idea.

So far I’m trying this:

app.config['suppress_callback_exceptions']=True

app.layout = html.Div([
    html.H1(children='Web Metrics for ArcGIS Usage at ----', style={
        'textAlign': 'center'
    }), 
    dcc.Tabs(id="tabs", value="online", children=[
        dcc.Tab(label='ArcGIS Online', value="online"), 
        dcc.Tab(label='ArcGIS Enterprise', value="enterprise"),
    ], className="four columns"), 
    html.Div([
        dcc.Dropdown(
            options=[
                {'label': 'Maps', 'value': 'maps'}, 
                {'label': 'Apps', 'value': 'apps'}, 
                {'label': 'Layers', 'value': 'layers'}, 
                {'label': 'Tools', 'value': 'tools'}, 
                {'label': 'Data Files', 'value': 'files'},
                {'label': 'All', 'value': 'all'}
            ], 
            value='maps'
        )
    ]
    ), 
    html.Div(id="loaded", children=html.H1("loaded"), style={'display':'none'}), 
    #dcc.Loading(id="loadingOnline", children=[html.Div(id="loading-output-online")], type="default"),
    html.Div(id='dataLoadedSignal', 
        style={'display':'none'}),
    html.Div(id="onlineGraphs", style={'display':'none'}), #Layout for adding online graphs later
    html.Div(id="nothing", style={'display':'none'})
])

@app.callback(Output('dataLoadedSignal', 'children'), 
    [Input('loaded', 'children')])
def load(something):
    print("data loaded")
    return getData("url", 
        getCreds('arcgisOnlineUsername'), getCreds('arcgisOnlinePassword'))

@app.callback(Output('nothing', 'children'),
    [Input('dataLoadedSignal', 'children')],
)
def drawLayout(data):
    #generate the layout graphs & their callbacks
    print('draw layout')
    count = 0 
    for i in data: 
        try: 
            @app.callback(Output(i['id'] + "_graph", 'children'),[
                Input('dataLoadedSignal', 'children'),
            ])
            def createGraph(data):
                return html.Div(html.H3("hello")) 
            #Give it another callback to populate the data 
            # @app.callback(Output(i['id'] + "_graph", 'children'), [
            #     Input(i['id'] + "_graph", 'children'), 
            # ])
            # def graph_update(i):
            #     print("calling graph usage") 
            #     return graphItemUsage(i, 'Date', 'Views', "Item Usage ArcGIS Online", "four columns")
        
        except (TypeError, RuntimeError) as e:     
            print("No usage data for: ")
            print(i)
            print(e)
        count += 1 
    print("layout complete")
    return html.Div()

I have no way to pass an index (i) so it knows what data to load from the data I’ve downloaded. Am I going about this wrong? And I keep getting this error:

An object was provided as children instead of a component, string, or number (or list of those). Check the children property that looks something like:

three reasons why you should buy plotly pro: support open source, get great support, host your plots and dashboards online