在动态生成组件时,Plotly Dash 应用程序似乎没有更新 app.layout 属性

Plotly Dash app doesen't seem to update the app.layout property when generating components on the fly

Dash 在从回调动态创建组件时似乎不会更新 app.layout 属性。下面是一个重现不良行为的简单示例:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div(children=[
    html.H1(children='Hello Dash'),
    html.Button(id="display_graph",children="Show graph"),
    html.Div(children='''
        Dash: A web application framework for Python.
    '''),
    html.Div(id="graph_div", children=[]),
    html.Div(id="detiles", children=[])
])


@app.callback(
    Output('detiles', 'children'),
    [Input('graph', 'hoverData')])
def debug_hover(hover_data):
    children = []
    print(hover_data)
    if hover_data["points"] is not None:
        points = hover_data["points"]
        for p in points:
            print(p["curveNumber"])
            trace_name = app.layout['graph'].figure['data'][p["curveNumber"]]['name']
            # trace_name = "placeholder"
            children.append(html.Div(
                [html.P(f"Estimated Turnover:{trace_name}: {p['value']}", style={"display": "inline-block"})]))
        return children



@app.callback(
    Output(component_id='graph_div', component_property='children'),
    [Input(component_id='display_graph', component_property='value')]
)
def update_output_div(input_country):
    x = [1,2,3,4,5,6,7,8]
    y1 = [i*2 for i in x]
    y2 = [i * 3 for i in x]
    y3 = [i * 4 for i in x]
    fig = {
        'data': [
            {'x': x, 'y': y1, 'type': 'bar', 'name': 'Basic model',
             "marker_color": 'rgb(55, 83, 109)'},
            {'x': x, 'y': y2, 'type': 'bar', 'name': 'New model',
             "marker_color": 'rgb(185, 83, 109)'},
            {'x': x, 'y': y3, 'type': 'bar', 'name': 'Model V2',
             "marker_color": 'rgb(32, 201, 52)'}
        ],
        'layout': {
            'title': f"{input_country}",
            'xaxis': {'rangeslider': {"visible": True},
                      'range': [0, 20]},
            'height': 700,
            'width': 1200,
            'margin': {'b': 400}
        }
    }
    graph = dcc.Graph(id="graph", figure=fig)

    return graph


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

我在破折号调试器中遇到的错误如下所示: 这意味着 app.layout 中没有“graph”元素,但显然“graph_div”组件中的 children 下应该有一个“graph”。该图是通过回调创建的并且清晰可见。

即使我检查 PyCharm 中的调试器并检查 app.layout,我发现“graph_div”子项中没有预期的 dcc.Graph 组件

这是预期的行为还是需要调查的错误?如果是预期的,是否有任何解决方法来访问动态生成的组件的属性,例如现有图形中的跟踪名称?

我发现我应该将 State 传递给回调。如下所示修改 debug_hover 解决了我的问题:

@app.callback(
    Output('detiles', 'children'),
    [Input('graph', 'hoverData')],
    [State("graph","figure")] # This was modified
)
def debug_hover(hover_data,figure): # This was modified
    children = []
    print(hover_data)
    if hover_data["points"] is not None:
        points = hover_data["points"]
        for p in points:
            print(p["curveNumber"])
            trace_name = figure['data'][p["curveNumber"]]['name'] # This was modified
            # trace_name = "placeholder"
            children.append(html.Div(
                [html.P(f"Estimated Turnover:{trace_name}: {p['value']}", style={"display": "inline-block"})]))
        return children