How do I implement Checklist Persistence on a layout with multiple unique graphs?

My dashboard has a 2 x 2 graph layout with one checklist overlaid on each graph.

image

Each graph requires a unique ID, to be live-updated via callback.
These IDs are generated in a loop (e.g., graph-BMW, graph-MB, etc.).
Similarly, each checklist has a unique ID generated via the same loop (e.g., checklist-BMW, checklist-MB, etc.).
These IDs are passed to the Input and Output of the callback.

Graph data is calculated and the checklist value and figure are returned.

Since the checklist needs to be contained in the same DIV as the graph, they are nested and then unpacked in the layout.

All of this works perfectly, with one exception: persistence doesn’t work.
If a checklist is clicked, I’m unable to retain the current (new) state when refreshing the page.
The checklist value always returns to unchecked, as it seems to be reset.

Do you have any ideas of how to resolve this?
Happy to provide more info.

A stripped down version of the app:

cars = ['BMW', 'MB', 'AUDI', 'FIAT']

app3 = dash.Dash(__name__)

for car in cars:
    graph = 'graph-' + car
    checklist = 'checklist-' + car

    @app3.callback(Output(checklist, 'value'),
                   Output(graph, 'figure'),
                   Input(checklist, 'value'),
                   Input('interval-component', 'n_intervals'))
    def update_charts(checklist, n_interval, c=car):
        data = get_car_data(c)
        df = calcs_on_car_data(data)

        fig = go.Figure(go.Scatter(x=df.index, y=df['A'].values))
        return checklist, fig

list_graphs = []
for car in cars:
    list_graphs.append([html.Div(className='box',
                                 children=[html.Div([
                                     dcc.Checklist(id='checklist-' + str(car),
                                                   options=[{'label': '', 'value': 'on'}], value=[],
                                                   persistence=True),
                                     dcc.Graph(id='graph-' + str(car))])
                                 ])
                        ])

app3.layout = html.Div([
    *[j for i in list_graphs for j in i],  # unpacking a nested list
    dcc.Interval(id='interval-component', interval=300000, n_intervals=0)
])

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

Hi @pepe!

The problem is that your callback has the persisted prop (“value”) as an Output, which takes precedence over the the value in memory when the page is refreshed.

From the documentation, under “Explicitly clearing saved data”:

Persistence continues (subject to persistence_type ) as long as the component id , the persistence value, and the prop provided by the server when creating or updating the entire component has the same value as it had before the user changed it. But if you have a callback whose Output is the specific persisted prop itself, that takes precedence over any saved value. This lets you reset user edits using PreventUpdate or dash.no_update until you detect the reset condition.

Just remove Output(checklist, 'value') and it should work (you don’t need it anyways…).

Hope that this helps! :smiley:

1 Like