如何在具有多个唯一图形的布局上实施 Dash/Plotly 清单持久性?

How do I implement Dash/Plotly checklist persistence on a layout with multiple unique graphs?

我的仪表板有一个 2 x 2 的图表布局,每个图表上都有一个清单。

每个图表都需要一个唯一的 ID,通过回调 live-updated。 这些 ID 在循环中生成(例如 graph-BMW、graph-MB 等)。 同样,每个清单都有一个通过相同循环生成的唯一 ID(例如,checklist-BMW、checklist-MB 等)。 这些 ID 被传递给回调的 inputoutput

计算图表数据并返回核对表值和图表。

由于清单需要包含在与图表相同的DIV中,因此它们被嵌套,然后在布局中解包。

所有这些都完美无缺,只有一个例外:persistence 不起作用。 如果单击清单,我无法在刷新页面时保留当前(新)状态。 清单值总是 returns 未选中,因为它似乎已重置。

我该如何解决这个问题?

应用程序的 stripped-down 版本:

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)

您可以按照以下步骤操作

  • 利用会话变量存储清单值
  • 一旦页面刷新完成(所有页面元素都重新加载),触发调用访问会话变量并为相关清单赋值。

循环回调似乎破坏了持久化功能。通过删除清单输出来删除它,持久性按预期工作。这是一个MWE,

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


def make_car_card(car: str):
    graph_id = f'graph-{car}'
    checklist_id = f'checklist-{car}'
    card = html.Div(className='box',
                    children=html.Div([
                        dcc.Checklist(id=checklist_id,
                                      options=[{'label': '', 'value': 'on'}], value=[],
                                      persistence=True),
                        dcc.Graph(id=graph_id)])
                    )

    @app.callback(Output(graph_id, 'figure'), Input('interval-component', 'n_intervals'), Input(checklist_id, 'value'))
    def update_charts(_, value, this_car=car):
        if 'on' not in value:
            return px.scatter()
        return px.scatter(px.data.iris(), x="sepal_width", y="sepal_length", title=this_car)

    return card


# Create small example app.
app = dash.Dash(__name__)
app.layout = html.Div(
    [make_car_card(car) for car in ['BMW', 'MB', 'AUDI', 'FIAT']] +
    [dcc.Interval(id='interval-component', interval=300000, n_intervals=0)]
)

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