破折号回调防止其他回调
Posted
技术标签:
【中文标题】破折号回调防止其他回调【英文标题】:Dash callback preventing other callbacks 【发布时间】:2021-10-19 13:22:08 【问题描述】:我对 Dash 比较陌生,并且认为我对回调非常了解。但是,我现在处于一种情况,似乎我需要在一个回调中包含所有回调,因为我的程序在调用该回调时工作正常。
当我有多个回调时,它们单独工作正常;这意味着如果我注释掉一个回调,则回调将按需要工作。我可以使用 context.triggered 获得正确的功能,但我不想在一个大规模回调中包含所有内容,我觉得这是我理解的一个问题。我尝试在回调中限制一个输入,但这仍然不起作用。我是否将整个应用布局传递给回调?
如果我是,我如何限制在 id 之外传递的内容?如何 可以回调吗?
一个改编的工作示例如下:
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import dash_table
from dash.dependencies import Input, Output, State
import plotly.express as px
from dash import callback_context, no_update
import webbrowser
from flask import request
chrome_path = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s'
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/Mining-BTC-180.csv").drop('Unnamed: 0',axis=1)
selected_cols = ['Number-transactions', 'Output-volume(BTC)',
'Market-price', 'Hash-rate', 'Cost-per-trans-USD', 'Mining-revenue-USD',
'Transaction-fees-BTC']
class Parameter_Viewer():
def __init__(self, df, **kwargs):
revenue_plot = px.scatter(df, x="Date", y="Mining-revenue-USD",title='Mining-revenue-USD')
Hash_plot = px.scatter(df, x="Date", y="Hash-rate",title='Hash-rate')
parameter_table = dash_table.DataTable(
id='db-table',
columns=["name": i, "id": i for i in selected_cols],
data=df.to_dict('records'),
#page_action="native",
page_action='none',
style_table='height': '300px', 'overflowY': 'auto',
editable=True
)
app = dash.Dash()
app.layout = html.Div(
children=[
#first row
html.Div(
children=[
html.Div(children=[
html.H1("Parameter", className="menu-title"),
dcc.Dropdown(
id="parameter-filter",
options=[
"label": parameter, "value": parameter for parameter in df.columns
],
value="Mining-revenue-USD",
clearable=False,
className="dropdown",
),]),
html.Div(children=[
html.H1("Data Type", className="menu-title"),
dcc.Dropdown(
id="data-selector",
options=[
"label": data_col, "value": data_col for data_col in selected_cols
],
value="Hash-rate",
clearable=False,
className="dropdown",
),]),
html.Button("Close Viewer", id="Close_Btn")
]
),
html.Div(children=[
html.H1(children="Database Analytics",),
parameter_table]),
html.Div(children=[
html.Div(
dcc.Graph(id='param-plot',figure=revenue_plot),
style="width":'50%', "margin": 0, 'display': 'inline-block',className="six columns"),
html.Div(
dcc.Graph(id='param-plot2',figure=Hash_plot),
style="width":'50%', "margin": 0, 'display': 'inline-block',className="six columns")],className="row")
])
@app.callback(
[Output("db-table", "data"), Output("param-plot", "figure"), Output("param-plot2", "figure")],
[Input("parameter-filter", "value"),Input("data-selector", "value"),Input('db-table', 'data')])#,prevent_initial_call=True)
def update_charts(parameter,data_type,table_data):
changed_inputs = [x["prop_id"]for x in callback_context.triggered]
if changed_inputs[0] == 'parameter-filter.value':
df = pd.DataFrame.from_dict(table_data)
ua_plot = px.scatter(df, x="Date", y=data_type)
aa_plot = px.scatter(df, x="Date", y=parameter)
return table_data, ua_plot, aa_plot
elif changed_inputs[0] == 'db-table.data':
df = pd.DataFrame.from_dict(table_data)
ua_plot = px.scatter(df, x="Date", y=data_type)
aa_plot = px.scatter(df, x="Date", y=parameter)
return no_update, ua_plot, aa_plot
else:
return no_update,no_update,no_update
@app.callback(Output("db-table", "data"),Input("Close_Btn", "n_clicks"),prevent_initial_call=True)
def close_browser(n_clicks):
print('In close callback\n')
if n_clicks>0:
self.shutdown()
return no_update
host='127.0.0.1'
port='8050'
url = 'http://:/'.format(host,port)
webbrowser.get(chrome_path).open(url)
app.run_server(debug=False)
def shutdown(self):
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
Parameter_Viewer(df)```
【问题讨论】:
将第一个回调分解为以下也不起作用:``` @app.callback( [Output("db-table", "data"), Output("param-plot" , "figure"), Output("param-plot2", "figure")], [Input("db-table", "value")],[State("data-selector", "value"),State ('参数过滤器', '数据')],prevent_initial_call=True) ''' 【参考方案1】:考虑你的回调可能是什么样子的基本情况然后扩展它们会更容易。根据我的经验,我通常构造回调的主要原因是处理由特定输入引起的特定输出。
例如
如果输出 O1 是输入 I1 的效果,那么我会进行回调 C1(I1 → O1)。
如果输出 O1 是输入 I1 和 I2 的影响,那么我进行回调 C1([I1, I2] → O1)
如果您碰巧有多个输出是输入的效果,那么您可以将这些输出合并到同一个回调中。
例如
输出O1是输入I1的效果输出O2是输入I1的效果,然后我做一个回调C1(I1→[O1,O2])
另外,请记住,Dash 不允许多个回调具有相同的输出组件(例如,特定组件属性可以与一个且只有一个回调关联)。在这种情况下,如果您有一个特定的输出需要与另一个同时更新,但不一定是同一输入的效果,那么您仍然应该将输出组合到单个回调中。
例如
如果输出O1是输入I1的效果并且输出O2必须用O1更新,那么我做一个回调C1(I1 → [O1, O2])
我不确定为什么在评论中您尝试使用 State() 而不是 Input(),因为 State() 用于在仍必须将属性读取为输入的情况下,但不一定必须是触发。
所以使用上面的逻辑,例如,
如果输出 O1 是输入 I1 的效果并且不是输入(我们现在称为状态)S1 的效果,但是 仍然需要 S1,然后我做一个回调 C1([I1, S1] → [O1])
只要回调不试图一次做太多不连贯的事情,有很多输入和输出的大回调是正常的(否则当你回去查看你的代码时,你会花费很多时间试图记住你确实相信我的事情:))。
【讨论】:
【参考方案2】:如果你像我一样是初学者。您可能正在寻找最有价值的信息,就我而言,Daniel Al Mouiee 的回答:
Dash 不允许多个回调具有相同的输出组件
【讨论】:
以上是关于破折号回调防止其他回调的主要内容,如果未能解决你的问题,请参考以下文章