Dash 客户端回调
Dash Clientside Callbacks
我正在努力处理 Dash 客户端回调。我希望创建一个流畅的动画,所以我需要客户端回调具有快速更新率。我有一个似乎可以复制问题的例子;我有一个正常的回调,并且按预期工作。当我将相同的回调转换为客户端时,它不再有效。但是,当我对客户端 return 执行 JSON.stringify 时,我看到数据字段正在更新。我不明白这个问题,但我认为这是我的 js 的问题。我不知道如何在客户端调试,所以任何错误记录的建议也将不胜感激。
这是有效的 'normal' 回调:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input,Output,State
fig_test={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button("Button 1", id="btn1"),
dcc.Graph(id="graph", figure=fig_test),
dcc.Slider(
id='interval-component',
min=0,
max=36,
step=1,
value=10,
),
html.Div(id="log"),
html.Pre(
id='structure',
style={
'border': 'thin lightgrey solid',
'overflowY': 'scroll',
'height': '275px'
}
)
])
@app.callback(
Output("graph", "figure"),
Input('interval-component','value'),Input("graph", "figure"),Input("btn1", "n_clicks"))
def display_structure(value, figure, btn1):
figure['data'][0]['y'][1] = value
return {'data': figure['data'], 'layout':figure['layout']}
app.run_server(debug=False)
这是通过客户端实现的相同回调:
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input,Output,State
fig_test={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button("Button 1", id="btn1"),
dcc.Graph(id="graph", figure=fig_test),
dcc.Slider(
id='interval-component',
min=0,
max=36,
step=1,
value=10,
),
html.Div(id="log"),
html.Pre(
id='structure',
style={
'border': 'thin lightgrey solid',
'overflowY': 'scroll',
'height': '275px'
}
)
])
app.clientside_callback(
"""
function(value, figure, btn1){
figure['data'][0]['y'][1] = value
return {'data': figure['data'], 'layout':figure['layout']};
}
""", Output("graph", "figure"), [Input('interval-component','value'),Input("graph", "figure"),Input("btn1", "n_clicks")])
app.run_server(debug=False)
如果我实现客户端以像这样对输出进行 jsonify:
app.clientside_callback(
"""
function(value, figure, btn1){
figure['data'][0]['y'][1] = value
return JSON.stringify({'data': figure['data'], 'layout':figure['layout']});
}
""", Output("log", "children"), [Input('interval-component','value'),Input("graph", "figure"),Input("btn1", "n_clicks")])
我可以看到正在更新的值,所以我不知道是什么问题。
所以我想出了 'smooth animation' 用于布局更新,其中 'extend data' 是不可能的,所以这个答案中的解决方案:
不适用。此外,它允许实时更新数据的平滑动画,而不依赖于 'animate' api。这不是我提出的问题的确切答案,而是解决了这个概念。
如果您不熟悉框架,或者不确定如何设置图形,请在此处查看 plotly 的示例:https://plotly.com/python/animations/
设置伪代码:
## setup figure,
for data in some_data:
##do something
fig['frames'].append(frame)
fig1 = go.Figure(fig)
为您的框架设置存储,并为要传递给客户端回调的框架设置存储。当我设置一个模拟实时数据采集的过程时,我有一个用于 'polling' 的计时器和一个用于动画的辅助计时器。如果您不希望计时器作为触发器,主要概念仍然相同;有一些 'animate' 触发器,在本例中为 'interval-component',以启动快速刷新辅助计时器。
app.layout = html.Div([
dcc.Store(id='frames-stored', data=fig1['frames']),
dcc.Store(id='frames'),
dcc.Interval(
id='interval-component',
interval=1*500, # in milliseconds
n_intervals=0
),
dcc.Interval(id='graph-refresher',
interval=1*25,
n_intervals=0,
max_intervals=50,
disabled=True),
dcc.Graph(id="graph", figure=fig1),
])
现在一个回调来捕获您的 'animation' 触发器并将帧传递给您的客户端回调:
@app.callback(
Output("frames", "data"),Output("graph-refresher", "disabled"),
Output("graph-refresher", "max_intervals"),Output('graph-refresher','n_intervals'),
Input("interval-component", "n_intervals"),State("frames-stored", "data"))
def data_smoother(n_intervals,frames):
## can do whatever here as long as a list of frames are passed to the store
selected_frames = frames[n_intervals]
return selected_frames,False,'some_max',0
此回调打开客户端回调的计时器,并用 'some_max' 重置 max_intervals。这将取决于你在做什么。
现在处理 'animation'.
的客户端回调
app.clientside_callback(
"""
function(n_intervals, frames){
return {'data':frames[parseInt(n_intervals)]['data'], 'layout':frames[parseInt(n_intervals)]['layout']};
}
""",Output("graph", "figure"),Input('graph-refresher','n_intervals'), State("frames", "data"))
我希望这对某人有用!
我正在努力处理 Dash 客户端回调。我希望创建一个流畅的动画,所以我需要客户端回调具有快速更新率。我有一个似乎可以复制问题的例子;我有一个正常的回调,并且按预期工作。当我将相同的回调转换为客户端时,它不再有效。但是,当我对客户端 return 执行 JSON.stringify 时,我看到数据字段正在更新。我不明白这个问题,但我认为这是我的 js 的问题。我不知道如何在客户端调试,所以任何错误记录的建议也将不胜感激。
这是有效的 'normal' 回调:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input,Output,State
fig_test={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button("Button 1", id="btn1"),
dcc.Graph(id="graph", figure=fig_test),
dcc.Slider(
id='interval-component',
min=0,
max=36,
step=1,
value=10,
),
html.Div(id="log"),
html.Pre(
id='structure',
style={
'border': 'thin lightgrey solid',
'overflowY': 'scroll',
'height': '275px'
}
)
])
@app.callback(
Output("graph", "figure"),
Input('interval-component','value'),Input("graph", "figure"),Input("btn1", "n_clicks"))
def display_structure(value, figure, btn1):
figure['data'][0]['y'][1] = value
return {'data': figure['data'], 'layout':figure['layout']}
app.run_server(debug=False)
这是通过客户端实现的相同回调:
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input,Output,State
fig_test={
'data': [
{'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button("Button 1", id="btn1"),
dcc.Graph(id="graph", figure=fig_test),
dcc.Slider(
id='interval-component',
min=0,
max=36,
step=1,
value=10,
),
html.Div(id="log"),
html.Pre(
id='structure',
style={
'border': 'thin lightgrey solid',
'overflowY': 'scroll',
'height': '275px'
}
)
])
app.clientside_callback(
"""
function(value, figure, btn1){
figure['data'][0]['y'][1] = value
return {'data': figure['data'], 'layout':figure['layout']};
}
""", Output("graph", "figure"), [Input('interval-component','value'),Input("graph", "figure"),Input("btn1", "n_clicks")])
app.run_server(debug=False)
如果我实现客户端以像这样对输出进行 jsonify:
app.clientside_callback(
"""
function(value, figure, btn1){
figure['data'][0]['y'][1] = value
return JSON.stringify({'data': figure['data'], 'layout':figure['layout']});
}
""", Output("log", "children"), [Input('interval-component','value'),Input("graph", "figure"),Input("btn1", "n_clicks")])
我可以看到正在更新的值,所以我不知道是什么问题。
所以我想出了 'smooth animation' 用于布局更新,其中 'extend data' 是不可能的,所以这个答案中的解决方案:
## setup figure,
for data in some_data:
##do something
fig['frames'].append(frame)
fig1 = go.Figure(fig)
为您的框架设置存储,并为要传递给客户端回调的框架设置存储。当我设置一个模拟实时数据采集的过程时,我有一个用于 'polling' 的计时器和一个用于动画的辅助计时器。如果您不希望计时器作为触发器,主要概念仍然相同;有一些 'animate' 触发器,在本例中为 'interval-component',以启动快速刷新辅助计时器。
app.layout = html.Div([
dcc.Store(id='frames-stored', data=fig1['frames']),
dcc.Store(id='frames'),
dcc.Interval(
id='interval-component',
interval=1*500, # in milliseconds
n_intervals=0
),
dcc.Interval(id='graph-refresher',
interval=1*25,
n_intervals=0,
max_intervals=50,
disabled=True),
dcc.Graph(id="graph", figure=fig1),
])
现在一个回调来捕获您的 'animation' 触发器并将帧传递给您的客户端回调:
@app.callback(
Output("frames", "data"),Output("graph-refresher", "disabled"),
Output("graph-refresher", "max_intervals"),Output('graph-refresher','n_intervals'),
Input("interval-component", "n_intervals"),State("frames-stored", "data"))
def data_smoother(n_intervals,frames):
## can do whatever here as long as a list of frames are passed to the store
selected_frames = frames[n_intervals]
return selected_frames,False,'some_max',0
此回调打开客户端回调的计时器,并用 'some_max' 重置 max_intervals。这将取决于你在做什么。 现在处理 'animation'.
的客户端回调app.clientside_callback(
"""
function(n_intervals, frames){
return {'data':frames[parseInt(n_intervals)]['data'], 'layout':frames[parseInt(n_intervals)]['layout']};
}
""",Output("graph", "figure"),Input('graph-refresher','n_intervals'), State("frames", "data"))
我希望这对某人有用!