Help on storing data as hidden JSONs for sharing between callbacks

Hi Dash world,

I am working on an app that allows the user to select a customer, click a button to download a bunch of data from our internal DB, and then produce some graphs on the data. I believe I have the workflow correct and the app works as expected however I get a bunch of errors/warnings in the background.

Two questions here:

  1. Is there a way to stop callbacks given input conditions to mitigate these errors?
  2. Is having ~15 hidden JSON data frames actually the most efficient way to share data between callbacks?

Here’s a pseudo code example of my app:

app.layout = html.Div([
    dcc.Dropdown(id='custDropDown', Select Customer, ...)
    html.button(id='dl-button', ...)
    dcc.Graph(id='graph-1',...)
    .....
    html.Div(id='dataset-1', style={'display': 'none'})
])

#download the data
@app.callback(
    Output('dataset-1', 'children'),
    [Input('dl-button', 'n_clicks')],
    [State('custDropDown', 'value')])
def dl_the_date(n_clicks, cust):
    DF = download the data to data frame
    return DF.to_json(date_format='iso', orient='split')

#make the graph
@app.callback(
    Output('graph-1', 'figure'),
    [Input('dataset-1', 'children')],
    [State('custDropDown', 'value')])
def make_the_graph(data, cust):
    df = pd.read_json(data, orient='split)
    make the graph
    return (plotly graph....)

I have many modules set up like this and I get the error below on the read_json line before the data is downloaded:
raise ValueError(msg.format(_type=type(filepath_or_buffer)))

Any help is much appreciated.

1 Like

I think an easier more efficient way is to load the DataFrame once, and in the callback functions you can do the filtering you need to return a subset of the df and / or to return a plot based on the dropdown.

Here is my suggested modification to your code with some comments:

app = dash.Dash()

data_df = pd.read_csv('my_df.csv') # or read_sql, read_json etc.

app.layout = html.Div([
    dcc.Dropdown('custDropDown'),
    # no need for a button here, but you can add one if it makes sense based on the business logic
    dcc.Graph('graph-1'),
    # no need for the hidden div here, since you alway have the data in `data_df`
])

# no need for the first callback function, having loaded the data, the DataFrame will be available as a
# variable in memory, and you can filter / slice / dice in the next function based on needs

@app.callback(Output('graph-1', 'figure'),
                     [Input('custDropDown', 'value')])
# since you have a variable with the dataframe, there is no need to load every time
def make_the_graph(value):
    df = data_df[some_filter_based_on_value] # you are simply filtering an available DataFrame
    return  {'data': [go.Scatter(x=df[var1], y=df[var2])]} # or whatever type of graph you want to produce

My suggested approach is NOT a good idea if your data is constantly changing (users need live data that gets updated daily for example). In this case you might need to move the read_csv call inside the callback function, so it loads a fresh copy of the data every time, or some other solution.

Hope this makes sense!

Not sure what these errors are…

No:) I think as mentioned above, with this approach you wouldn’t need to have hidden divs.

Good luck!