plotly Dash clickのタイミングのみで2つのinputの値を読み込む

2 min read読了の目安(約2400字

課題


送信ボタンをトリガーとして2つの入力を読み込もうとプログラムを書いたところ、inputの変化もトリガーとなってしまった

app.layout = html.Div([
    html.Div(
        [
            dbc.Form(
                [
                    dbc.FormGroup(
                        [
                            dbc.Label("Column Name", className="mr-2"),
                            dcc.Input(
                                id = "input-col-name",
                                type = "text",
                                placeholder="Item Name",
                            ),
                        ],
                        className="mr-3",
                    ),
                    dbc.FormGroup(
                        [
                            dbc.Label("Record Count", className="mr-2"),
                            dcc.Input(
                                id = "input-row-count",
                                type = "text",
                                placeholder="Record Count",
                            ),
                        ],
                        className="mr-3",
                    ),
                    dbc.Button("Submit", id='submit-val', n_clicks=0, color="primary"),
                ],
                inline=True
            )
        ]
    ),
    html.Div(id="table1")
])

@app.callback(
    Output('table1', 'children'),
    [Input('submit-val', 'n_clicks'),
    Input('input-col-name', 'value'),
    Input('input-row-count', 'value')]
)
def update_output(n_clicks, col_name:str, row_count:int):
    if col_name and row_count:
        df.create_numeric(col_name, int(row_count))
        result = df.publish()
        data = result.to_dict('rows')
        columns =  [{"name": i, "id": i,} for i in (result.columns)]
        return dt.DataTable(data=data, columns=columns)
    else:
        return

解決の糸口

Inputの考え方が間違っていた

Inputは、Callback関数の入力になるが、Javascriptなどにもあるwatcherの役割があるため、valueに変化があり次第それをトリガーに関数を発動させてしまう。どちらも入力されていないと発動しないようにいくらチェックを入れても、本来の動作である、ボタンでの動作の前に動作してしまう

解決方法

Stateを使う

DashのStateをCallbackの引数にすると、変化によっては発動しないものの、関数の入力にすることができる(Stateが変わったら検知するもの ではないことに注意)
Dashのドキュメントにも、そのような使い方をすると記述してある
Dash App With Stateを参照

https://dash.plotly.com/basic-callbacks
# 訂正前
Input('input-col-name', 'value')
Input('input-row-count', 'value')

#訂正後
State('input-col-name', 'value')
State('input-row-count', 'value')