使用模式匹配回调在破折号中跨多个选项卡下载数据表

问题描述 投票:0回答:1

假设您有一个带有两个选项卡的仪表板。每个选项卡上都有一个下载按钮和一个数据表。如何编写一个回调函数来将数据表从该选项卡下载到 csv 文件?

这是一个最小的可重现示例:

import dash_bootstrap_components as dbc
from dash import dcc, html, State, Output, Input, Dash, ALL, MATCH
from dash.dash_table import DataTable
import pandas as pd

app = Dash(__name__)

df1 = pd.DataFrame({'name': ['John', 'Jane', 'Bob'], 'age': [1, 2, 3]})
df2 = pd.DataFrame({'colour': ['Red', 'Green', 'Blue'], 'favourite': [True, False, False]})

app.layout = dbc.Container(children=[
    dcc.Download(id="download_data"),
    dcc.Tabs([
        dcc.Tab(label='Tab 1', children=[
            html.Button("Download", id={"type": "download_data_table", "index": "tab_1"}),
            DataTable(
                data=df1.to_dict("records"),
                columns=[{"name": i, "id": i} for i in df1.columns],
                id={"type": "data_table", "index": "tab_1"},
            ),
        ]),
        dcc.Tab(label='Tab 2', children=[
            html.Button("Download", id={"type": "download_data_table", "index": "tab_2"}),
            DataTable(
                data=df2.to_dict("records"),
                columns=[{"name": i, "id": i} for i in df2.columns],
                id={"type": "data_table", "index": "tab_2"},
            ),
        ]),

    ]),
], fluid=True)


@app.callback(
    Output('download_data', 'data'),
    Input({'type': "download_data_table", "index": MATCH}, "n_clicks"),
    State({"type": "data_table", "index": MATCH}, 'data')
)
def download_table(n_clicks, data):
    if n_clicks > 0:
        return dcc.send_data_frame(data.to_csv, f"data.csv", index=False)


if __name__ == '__main__':
    app.run_server(host='0.0.0.0', port=8000)

我期望当我单击选项卡上的下载按钮时,它应该将数据从该选项卡传递到下载组件,该组件应该将数据下载为 csv。但是,当我单击“下载”按钮时,没有任何反应。

我认为这个问题与我错误地实现模式匹配回调函数有关。

我知道我可以为每个下载按钮编写一个单独的回调,但是我希望能够将此解决方案推广到具有许多选项卡,这会导致大量重复的代码。

任何帮助将不胜感激。

python plotly-dash
1个回答
0
投票

这是在 Python Plotly Dash 应用程序中使用模式匹配回调功能的示例:

注意:使用

ctx.triggered_id

需要Dash 2.4+

在这种情况下,您实际上想要使用

ALL
,因为您只有一个
dcc.Download
组件 - 选项卡中的 所有 不同的下载按钮都可以 触发。然后,ctx
 用于确定所有按钮中的哪个按钮触发回调函数的任何特定调用。

import dash from dash import ALL, Dash, Input, Output, State from dash import ctx, dcc, html from dash.dash_table import DataTable import dash_bootstrap_components as dbc import pandas as pd app = Dash(__name__) df1 = pd.DataFrame({"name": ["John", "Jane", "Bob"], "age": [1, 2, 3]}) df2 = pd.DataFrame( {"colour": ["Red", "Green", "Blue"], "favourite": [True, False, False]} ) app.layout = dbc.Container( children=[ dcc.Download(id="download_data"), dcc.Tabs( [ dcc.Tab( label="Tab 1", children=[ html.Button( "Download", id={ "type": "download_data_table", "index": "tab_1", }, n_clicks=None, ), DataTable( data=df1.to_dict("records"), columns=[ {"name": i, "id": i} for i in df1.columns ], id={"type": "data_table", "index": "tab_1"}, ), ], ), dcc.Tab( label="Tab 2", children=[ html.Button( "Download", id={ "type": "download_data_table", "index": "tab_2", }, n_clicks=None, ), DataTable( data=df2.to_dict("records"), columns=[ {"name": i, "id": i} for i in df2.columns ], id={"type": "data_table", "index": "tab_2"}, ), ], ), ] ), ], fluid=True, ) @app.callback( Output("download_data", "data"), Input({"type": "download_data_table", "index": ALL}, "n_clicks"), State({"type": "data_table", "index": ALL}, "data"), ) def download_table(n_clicks, data): if all(map(lambda x: x is None, n_clicks)): raise dash.exceptions.PreventUpdate # print(n_clicks) button_id = ctx.triggered_id.index # print(button_id) if button_id.endswith("1"): df = pd.DataFrame(data[0]) else: df = pd.DataFrame(data[1]) return dcc.send_data_frame( df.to_csv, f"data_{button_id}.csv", index=False ) if __name__ == "__main__": app.run(debug=True, dev_tools_hot_reload=True)
    
© www.soinside.com 2019 - 2024. All rights reserved.