全局变量由和间隔组件更新
Global variable Updated by and Interval Componant
当我的 dash 应用程序启动时,一个全局变量由一个计算量大的函数创建 (dat)。我希望 dat 定期更新,但不通过任何用户操作更新。我知道由于共享内存的方式,普通的 python 全局变量不适合在破折号中使用,所以我使用隐藏的 div 来存储定期更新的数据。
我不希望在每个用户启动应用程序时更新数据,而是希望更新在后台发生,最好使用更新后的数据更新所有用户的应用程序。如果必须使用页面刷新来更新应用程序,那也没关系,但更新后的数据将对所有用户可用。
我在下面包含了一个执行我想要执行的任务的示例,问题是如果数据是字符串或 numpy 数组,则将数据存储在 div 中是可以的,但是如果数据结构更复杂,如 pandas 数据框(参见注释代码行)或 pandas 数据框的字典,则应用程序将 运行,但页面不会在浏览器中加载(加载布局时出错)。也许 memoizing 是解决方案,尽管我看到的所有示例似乎都与此略有不同,以至于我看不出如何使用它。使用隐藏的 div 对我来说似乎有点麻烦,但 plotly 帮助页面推荐
所以我的问题是如何使用比字符串或数组更复杂的数据结构在 dash 中创建和更新全局变量?
import dash
from dash.dependencies import Input, Output, Event
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
import numpy as np
import pandas as pd
app = dash.Dash(__name__)
def compute_expensive_data():
t=datetime.now()
dat = np.array([t.minute, t.second])
#d = {'time' : pd.Series(np.array([t.minute, t.second]), index=['minute', 'second'])}
#dat = pd.DataFrame(d)
return dat
dat = compute_expensive_data()
print(dat)
app.layout = html.Div([
html.H3('Original Time: Minute = ' + str(dat[0]) + ': Second = ' + str(dat[1])),
#html.H3('Original Time: Minute = ' + str(dat['time']['minute']) + ': Second = ' + str(dat['time']['second'])),
html.Div(id='title-line-children'),
dcc.RadioItems(
id='time-dropdown',
options=[
{'label': 'Minute', 'value': 'minute'}, {'label': 'Second', 'value': 'second'},
],
value='minute'
),
# Hidden div inside the app that stores the intermediate value
html.Div(id='intermediate-value', style={'display': 'none'}, children = dat),
dcc.Interval(
id='interval-component',
interval=20*1000 # 20 seconds in milliseconds
)
])
@app.callback(
Output('title-line-children', 'children'),
[Input('time-dropdown', 'value'), Input('intermediate-value', 'children')])
def render(value,dat1):
if value == 'minute':
printStr = str(dat1[0])
#printStr = str(dat1['time']['minute'])
outStr = 'Minute = ' + printStr
elif value == 'second':
printStr = str(dat1[1])
#printStr = str(dat1['time']['second'])
outStr = 'Second = ' + str(dat1[1])
return outStr
@app.callback(Output('intermediate-value', 'children'),
events=[Event('interval-component', 'interval')])
def update_global_var():
return compute_expensive_data()
if __name__ == '__main__':
app.run_server(debug=True)
好的,答案很简单。我只需要 jsonify 我的数据框。那么它基本上只是一个可以保存在隐藏div中的字符串。
import dash
from dash.dependencies import Input, Output, Event
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
import numpy as np
import pandas as pd
app = dash.Dash(__name__)
def compute_expensive_data():
t=datetime.now()
d = {'time' : pd.Series(np.array([t.minute, t.second]), index=['minute', 'second'])}
dat = pd.DataFrame(d).to_json()
return dat
dat = compute_expensive_data()
print(dat)
app.layout = html.Div([
html.H3('Original Time: Minute = ' + str(pd.read_json(dat)['time']['minute']) + ': Second = ' + str(pd.read_json(dat)['time']['second'])),
html.Div(id='title-line-children'),
dcc.RadioItems(
id='time-dropdown',
options=[
{'label': 'Minute', 'value': 'minute'}, {'label': 'Second', 'value': 'second'},
],
value='minute'
),
# Hidden div inside the app that stores the intermediate value
html.Div(id='intermediate-value', style={'display': 'none'}, children = dat),
dcc.Interval(
id='interval-component',
interval=20*1000 # 20 seconds in milliseconds
)
])
@app.callback(
Output('title-line-children', 'children'),
[Input('time-dropdown', 'value'), Input('intermediate-value', 'children')])
def render(value,dat1):
if value == 'minute':
printStr = str(pd.read_json(dat1)['time']['minute'])
outStr = 'Minute = ' + printStr
elif value == 'second':
printStr = str(pd.read_json(dat1)['time']['second'])
outStr = 'Second = ' + printStr
return outStr
@app.callback(Output('intermediate-value', 'children'),
events=[Event('interval-component', 'interval')])
def update_global_var():
return compute_expensive_data()
if __name__ == '__main__':
app.run_server(debug=True)
答案已更新至 Dash 1.8:
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
import numpy as np
import pandas as pd
app = dash.Dash(__name__)
def compute_expensive_data():
t=datetime.now()
d = {'time' : pd.Series(np.array([t.minute, t.second]), index=['minute', 'second'])}
dat = pd.DataFrame(d).to_json()
return dat
dat = compute_expensive_data()
print(dat)
app.layout = html.Div([
html.H3('Original Time: Minute = ' + str(pd.read_json(dat)['time']['minute']) + ': Second = ' + str(pd.read_json(dat)['time']['second'])),
html.Div(id='title-line-children'),
dcc.RadioItems(
id='time-dropdown',
options=[
{'label': 'Minute', 'value': 'minute'}, {'label': 'Second', 'value': 'second'},
],
value='minute'
),
# Hidden div inside the app that stores the intermediate value
html.Div(id='intermediate-value', style={'display': 'none'}, children = dat),
dcc.Interval(
id='interval-component',
interval=2*1000, # 20 seconds in milliseconds
n_intervals=0
)
])
@app.callback(
Output('title-line-children', 'children'),
[Input('time-dropdown', 'value'), Input('intermediate-value', 'children')])
def render(value,dat1):
if value == 'minute':
printStr = str(pd.read_json(dat1)['time']['minute'])
outStr = 'Minute = ' + printStr
elif value == 'second':
printStr = str(pd.read_json(dat1)['time']['second'])
outStr = 'Second = ' + printStr
return outStr
@app.callback(Output('intermediate-value', 'children'),
[Input('interval-component', 'n_intervals')])
def update_global_var(n):
return compute_expensive_data()
if __name__ == '__main__':
app.run_server(debug=False)
当我的 dash 应用程序启动时,一个全局变量由一个计算量大的函数创建 (dat)。我希望 dat 定期更新,但不通过任何用户操作更新。我知道由于共享内存的方式,普通的 python 全局变量不适合在破折号中使用,所以我使用隐藏的 div 来存储定期更新的数据。
我不希望在每个用户启动应用程序时更新数据,而是希望更新在后台发生,最好使用更新后的数据更新所有用户的应用程序。如果必须使用页面刷新来更新应用程序,那也没关系,但更新后的数据将对所有用户可用。
我在下面包含了一个执行我想要执行的任务的示例,问题是如果数据是字符串或 numpy 数组,则将数据存储在 div 中是可以的,但是如果数据结构更复杂,如 pandas 数据框(参见注释代码行)或 pandas 数据框的字典,则应用程序将 运行,但页面不会在浏览器中加载(加载布局时出错)。也许 memoizing 是解决方案,尽管我看到的所有示例似乎都与此略有不同,以至于我看不出如何使用它。使用隐藏的 div 对我来说似乎有点麻烦,但 plotly 帮助页面推荐
所以我的问题是如何使用比字符串或数组更复杂的数据结构在 dash 中创建和更新全局变量?
import dash
from dash.dependencies import Input, Output, Event
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
import numpy as np
import pandas as pd
app = dash.Dash(__name__)
def compute_expensive_data():
t=datetime.now()
dat = np.array([t.minute, t.second])
#d = {'time' : pd.Series(np.array([t.minute, t.second]), index=['minute', 'second'])}
#dat = pd.DataFrame(d)
return dat
dat = compute_expensive_data()
print(dat)
app.layout = html.Div([
html.H3('Original Time: Minute = ' + str(dat[0]) + ': Second = ' + str(dat[1])),
#html.H3('Original Time: Minute = ' + str(dat['time']['minute']) + ': Second = ' + str(dat['time']['second'])),
html.Div(id='title-line-children'),
dcc.RadioItems(
id='time-dropdown',
options=[
{'label': 'Minute', 'value': 'minute'}, {'label': 'Second', 'value': 'second'},
],
value='minute'
),
# Hidden div inside the app that stores the intermediate value
html.Div(id='intermediate-value', style={'display': 'none'}, children = dat),
dcc.Interval(
id='interval-component',
interval=20*1000 # 20 seconds in milliseconds
)
])
@app.callback(
Output('title-line-children', 'children'),
[Input('time-dropdown', 'value'), Input('intermediate-value', 'children')])
def render(value,dat1):
if value == 'minute':
printStr = str(dat1[0])
#printStr = str(dat1['time']['minute'])
outStr = 'Minute = ' + printStr
elif value == 'second':
printStr = str(dat1[1])
#printStr = str(dat1['time']['second'])
outStr = 'Second = ' + str(dat1[1])
return outStr
@app.callback(Output('intermediate-value', 'children'),
events=[Event('interval-component', 'interval')])
def update_global_var():
return compute_expensive_data()
if __name__ == '__main__':
app.run_server(debug=True)
好的,答案很简单。我只需要 jsonify 我的数据框。那么它基本上只是一个可以保存在隐藏div中的字符串。
import dash
from dash.dependencies import Input, Output, Event
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
import numpy as np
import pandas as pd
app = dash.Dash(__name__)
def compute_expensive_data():
t=datetime.now()
d = {'time' : pd.Series(np.array([t.minute, t.second]), index=['minute', 'second'])}
dat = pd.DataFrame(d).to_json()
return dat
dat = compute_expensive_data()
print(dat)
app.layout = html.Div([
html.H3('Original Time: Minute = ' + str(pd.read_json(dat)['time']['minute']) + ': Second = ' + str(pd.read_json(dat)['time']['second'])),
html.Div(id='title-line-children'),
dcc.RadioItems(
id='time-dropdown',
options=[
{'label': 'Minute', 'value': 'minute'}, {'label': 'Second', 'value': 'second'},
],
value='minute'
),
# Hidden div inside the app that stores the intermediate value
html.Div(id='intermediate-value', style={'display': 'none'}, children = dat),
dcc.Interval(
id='interval-component',
interval=20*1000 # 20 seconds in milliseconds
)
])
@app.callback(
Output('title-line-children', 'children'),
[Input('time-dropdown', 'value'), Input('intermediate-value', 'children')])
def render(value,dat1):
if value == 'minute':
printStr = str(pd.read_json(dat1)['time']['minute'])
outStr = 'Minute = ' + printStr
elif value == 'second':
printStr = str(pd.read_json(dat1)['time']['second'])
outStr = 'Second = ' + printStr
return outStr
@app.callback(Output('intermediate-value', 'children'),
events=[Event('interval-component', 'interval')])
def update_global_var():
return compute_expensive_data()
if __name__ == '__main__':
app.run_server(debug=True)
答案已更新至 Dash 1.8:
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
import numpy as np
import pandas as pd
app = dash.Dash(__name__)
def compute_expensive_data():
t=datetime.now()
d = {'time' : pd.Series(np.array([t.minute, t.second]), index=['minute', 'second'])}
dat = pd.DataFrame(d).to_json()
return dat
dat = compute_expensive_data()
print(dat)
app.layout = html.Div([
html.H3('Original Time: Minute = ' + str(pd.read_json(dat)['time']['minute']) + ': Second = ' + str(pd.read_json(dat)['time']['second'])),
html.Div(id='title-line-children'),
dcc.RadioItems(
id='time-dropdown',
options=[
{'label': 'Minute', 'value': 'minute'}, {'label': 'Second', 'value': 'second'},
],
value='minute'
),
# Hidden div inside the app that stores the intermediate value
html.Div(id='intermediate-value', style={'display': 'none'}, children = dat),
dcc.Interval(
id='interval-component',
interval=2*1000, # 20 seconds in milliseconds
n_intervals=0
)
])
@app.callback(
Output('title-line-children', 'children'),
[Input('time-dropdown', 'value'), Input('intermediate-value', 'children')])
def render(value,dat1):
if value == 'minute':
printStr = str(pd.read_json(dat1)['time']['minute'])
outStr = 'Minute = ' + printStr
elif value == 'second':
printStr = str(pd.read_json(dat1)['time']['second'])
outStr = 'Second = ' + printStr
return outStr
@app.callback(Output('intermediate-value', 'children'),
[Input('interval-component', 'n_intervals')])
def update_global_var(n):
return compute_expensive_data()
if __name__ == '__main__':
app.run_server(debug=False)