【问题标题】:plotly dash: create multiple callbacks (with loop?)plotly dash:创建多个回调(带循环?)
【发布时间】:2019-05-23 20:46:53
【问题描述】:

假设我有一个包含 20 个参数的模型,我为每个参数创建了一个输入组件。

[dcc.Input(type = 'number', id = 'input %i'%i) for i in range(20)]

我想要一个按钮html.Button('populate parameters', id = 'button populate'),它应该为所有输入填充最佳预拟合值。

代码应该如下所示,但它不起作用。

for i in range(20):
    @app.callback(
        dash.dependencies.Output('input %i'%i, 'value'),
        [dash.dependencies.Input('button populate', 'n_clicks')]
    )
    def update(ignore):
        return np.random.uniform()

我是否必须为每个输出编写 20 个具有相同功能的回调?我找不到一次性制作它们的方法(循环?)

【问题讨论】:

    标签: plotly-dash


    【解决方案1】:

    我已经处理了同样的问题并找到了解决方案。您所做的是绕过装饰器并直接调用app.callback 函数:

    def update(ignore):
        return np.random.uniform()
    
    for i in range(20):
        app.callback(
            dash.dependencies.Output('input %i' % i, 'value'),
            [dash.dependencies.Input('button populate', 'n_clicks')]
        )(update)
    

    【讨论】:

      【解决方案2】:

      dash >= 1.11.0 中,您可以使用Pattern-Matching Callbacks。定义回调时不需要循环。

      示例

      1。导入回调选择器

      • 导入dash.dependecies.ALL:
      from dash.dependencies import Input, Output, State, ALL
      
      • 其他可用的回调选择器是MATCHALLSMALLER

      2。使用字典作为id

      • 使用id 定义您的组件,这是一个字典。您可以选择任何键,但例如typeid 是相当合理的选择。所以,而不是
      [dcc.Input(type = 'number', id = 'input %i'%i) for i in range(20)]
      

      使用

      [
          dcc.Input(type='number',
                    id={
                        'type': 'my-input-type',
                        'id': 'input %i' % i
                    }) for i in range(20)
      ]
      

      3。使用带有@app.callback 的回调选择器

      • 在定义回调时使用ALL 回调选择器:
      @app.callback(
          dash.dependencies.Output({
              'type': 'my-input-type',
              'id': ALL
          }, 'value'), [dash.dependencies.Input('button populate', 'n_clicks')])
      def update(ignore):
          return np.random.uniform()
      

      【讨论】:

        【解决方案3】:

        您可以在回调中设置任意数量的输入参数/参数。 但只有一个输出

        为我解决了类似情况的是:

        @app.callback(
            [Output('output-id', 'children')],
            [Input('button-trigger', 'n_clicks'],
            [State('input-one', 'value'),
            ...
            [State('input-twenty', 'value')]
        )
        def my_fancy_function(n_clicks, v1, ..., v20):
            return sth_awesome
        

        State()Input() 不同,不会在输入值更改时触发回调。

        n_clicks 每次点击都会更改 +1,但不需要使用。

        如果您的参数相互依赖,您将需要更多回调。 但是...有20个参数There must be a better way

        【讨论】:

        • 您好,谢谢。我编辑了我的问题,以使其更清楚我想要什么。 one output 约束是这里的问题。我有一个输入,但有 20 个输出。
        • 对此也有类似的问题:我将结果作为json 转储到隐藏的Div s children 属性中,并通过5 个回调读取特定的Div。这种方法使回调变得非常“简单”,因为所有回调都会监听Div
        【解决方案4】:

        我做了类似的事情来在页面重新加载后填充我的布局组件。

        感谢第一个回调,组件的状态存储在 dcc.Store 组件中。 第二个回调是在布局组件的状态发生变化或访问选项卡时填充布局组件(布局在 dcc.Tabs 中)

        dash_layout_components = {
        'time_slider_app2': 'value',
        'backtest_choice_app2': 'values',
        'asset_selection_app2': 'value',
        'graph_selection_app2': 'values'
        }
        
        stored_layout_value_name = [key[:key.rfind('a')] + value for key, value in 
        dash_layout_components.items()]
        
        set_back_and_display_graph_input = {
            'store_layout_data': 'modified_timestamp',
            'tabs': 'value'
        }
        
        
        @app.callback(
        Output('store_layout_data', 'data'),
        [Input(key, value) for key, value in dash_layout_components.items()])
        def store_layout(time_slider_value, backtest_choice_values, assets_selection_values, graph_selection_values):
        
            data_json = {
                'time_slider_value': time_slider_value,
                'backtest_choice_values': backtest_choice_values,
                'asset_selection_value': assets_selection_values,
                'graph_selection_values': graph_selection_values
           }
           return data_json
        
        
        for component_id, component_property in dash_layout_components.items():
        @app.callback(
            Output(component_id, component_property),
            [Input(key, value) for key, value in set_back_and_display_graph_input.items()],
            [State('store_layout_data', 'data'),
             State(component_id, 'id')]
        )
        def set_back_component(bouton_ts, tabs_value, layout_state_data, component):  # dynamiser l'arrivée des paramètres. piste, en créer une liste entre le for et le callback
        
            if tabs_value != '/app2':
                raise PreventUpdate
        
            if layout_state_data is None:
                return []
        
            else:
                store_layout_component_name = stored_layout_value_name[list(dash_layout_components.keys()).index(component)]
                return layout_state_data[store_layout_component_name]
        

        请注意,您将无法访问函数 ( set_back_component(...) ) 内的迭代值(component_id 和 component_property)

        【讨论】:

          猜你喜欢
          • 2020-03-07
          • 2021-05-06
          • 2020-03-17
          • 2021-06-07
          • 1970-01-01
          • 2022-07-06
          • 2021-05-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多