【问题标题】:Callback warning: Callback error creating dash' DataTable回调警告:回调错误创建破折号数据表
【发布时间】:2021-05-20 20:38:20
【问题描述】:

我正在尝试从回调中生成一个表,虽然该表实际上正在生成,但我收到了一个警告:

更新 priceTable.data、priceTable.columns 的回调错误

dash.exceptions.InvalidCallbackReturnValue:回调 ..priceTable.data...priceTable.columns.. 是一个多输出。 期望输出类型是列表或元组,但得到: 没有。

我知道我的问题在于我如何布置回调,但我不确定正确的格式应该是什么。我在网上找到了this 答案,这对我有很大帮助,因为我之前有'return dt.DataTable(data = data, columns=columns)'。

代码布局:

import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_table as dt
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')

app = dash.Dash(__name__)

states = df.State.unique().tolist()
numSP = df['Number of Solar Plants'].unique().tolist()

app.layout = html.Div([
    dcc.Dropdown(
            id='filter_dropdown',
            options=[{'label':st, 'value':st} for st in states],
            value = states[0]
            ),
    html.Br(),
    dcc.Dropdown(
            id='filter2',
            options=[{'label':np, 'value':np} for np in numSP]
            #value = numSP[0]
            ),
    html.Br(),
    html.Button('Submit', id='submit-button-state', n_clicks=0),
    html.Br(),
    html.Div(id='output'),
    html.Div(
        #id ='priceTable'
        dt.DataTable(id='priceTable')
        )
])

回调部分代码:

@app.callback(
    [Output('priceTable', 'data'),Output('priceTable', 'columns')],
    [Input('submit-button-state', 'n_clicks')],
    [State('filter_dropdown', 'value')],
    [State('filter2', 'value')],
    [State('submit-button-state', 'n_clicks')],
)
def update_table(n_clicks, filter_dropdown, filter2, table):
    if n_clicks:
        if filter_dropdown is None and filter2 is None:
            raise PreventUpdate
        if filter_dropdown is not None and filter2 is not None:
            table = df[df.State == filter_dropdown]
            table = table[table['Number of Solar Plants'] == filter2]
        if filter_dropdown is None and filter2 is not None:
            table = df[df['Number of Solar Plants'] == filter2]
        if filter_dropdown is not None and filter2 is None:
            table = df[df.State == filter_dropdown]
        columns = [{"name": i, "id": i,} for i in (table.columns)]    
        data = table.to_dict('records')
        return data, columns

我尝试过的事情:

  • 我尝试以不同的方式列出我的输出:[Output('priceTable', 'data')],[Output('priceTable', 'columns')],[Output( 'priceTable', 'data'),Output('priceTable', 'columns'),],
  • 将数据和列分配给返回的变量:
priceTable = (data, columns)
return priceTable 

谢谢!

【问题讨论】:

    标签: python pandas callback plotly-dash


    【解决方案1】:

    它不起作用的原因是因为您没有在回调中处理未单击按钮的情况。即使按钮没有被点击,你的回调仍然需要返回一个元组(你的datacolumns)。

    这就是这里的错误:

    期望输出类型是列表或元组,但得到:无。

    n_clicks0 (false) 时,您不会返回任何内容 (None)。

    所以你需要做的是在n_clicks0 时返回datacolumns。与现有方法的唯一区别是,如果 n_clicks0,则不对数据应用任何过滤器。

    完整示例:

    import dash
    import dash_html_components as html
    import dash_core_components as dcc
    import dash_table as dt
    from dash.dependencies import Input, Output, State
    from dash.exceptions import PreventUpdate
    import pandas as pd
    
    df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/solar.csv")
    
    app = dash.Dash(__name__)
    
    states = df.State.unique().tolist()
    numSP = df["Number of Solar Plants"].unique().tolist()
    
    app.layout = html.Div(
        [
            dcc.Dropdown(
                id="filter_dropdown",
                options=[{"label": st, "value": st} for st in states],
                value=states[0],
            ),
            html.Br(),
            dcc.Dropdown(
                id="filter2",
                options=[{"label": np, "value": np} for np in numSP]
                # value = numSP[0]
            ),
            html.Br(),
            html.Button("Submit", id="submit-button-state", n_clicks=0),
            html.Br(),
            html.Div(id="output"),
            html.Div(
                # id ='priceTable'
                dt.DataTable(id="priceTable")
            ),
        ]
    )
    
    
    def get_table_data(data):
        columns = [
            {
                "name": i,
                "id": i,
            }
            for i in (data.columns)
        ]
        data = data.to_dict("records")
        return (data, columns)
    
    
    @app.callback(
        [Output("priceTable", "data"), Output("priceTable", "columns")],
        [Input("submit-button-state", "n_clicks")],
        [State("filter_dropdown", "value")],
        [State("filter2", "value")],
        [State("submit-button-state", "n_clicks")],
    )
    def update_table(n_clicks, filter_dropdown, filter2, table):
        if n_clicks:
            if filter_dropdown is None and filter2 is None:
                raise PreventUpdate
            if filter_dropdown is not None and filter2 is not None:
                table = df[df.State == filter_dropdown]
                table = table[table["Number of Solar Plants"] == filter2]
            if filter_dropdown is None and filter2 is not None:
                table = df[df["Number of Solar Plants"] == filter2]
            if filter_dropdown is not None and filter2 is None:
                table = df[df.State == filter_dropdown]
    
            (data, columns) = get_table_data(table)
            print("columns", columns)
            print("data", columns)
    
            return data, columns
    
        return get_table_data(df)
    
    
    if __name__ == "__main__":
        app.run_server(debug=True)
    

    在上面的示例中,我还将您用于从数据框中检索数据和列的代码放在其自己的函数 get_table_data 中。为了确保始终返回您的数据元组,我使用了guard clause

    【讨论】:

    • 巴斯,非常感谢!这是完美的解决方案,我必须在 if 语句的末尾添加一个 else 和 'raise PreventUpdate()' 子句。谢谢!
    猜你喜欢
    • 2020-03-15
    • 1970-01-01
    • 2021-10-19
    • 2020-06-25
    • 1970-01-01
    • 2021-01-24
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多