ダッシュ アプリを起動すると、計算コストの高い関数によってグローバル変数 (dat) が作成されます。データを定期的に更新したいのですが、ユーザーの操作によっては更新したくありません。メモリの共有方法が原因で、通常の Python グローバル変数はダッシュでの使用に適していないことを理解しているため、非表示の div を使用して定期的に更新されるデータを保存しています。
各ユーザーがアプリを起動したときにデータを更新するのではなく、バックグラウンドで更新を行い、更新されたデータですべてのユーザーのアプリを更新することをお勧めします。ページを更新してアプリを更新する必要がある場合も問題ありませんが、更新されたデータはすべてのユーザーが利用できます。
私がやりたいタスクを実行する例を以下に含めました。問題は、データが文字列またはnumpy配列の場合はdivにデータを格納しても問題ないことですが、データ構造がpandasデータフレームのように複雑な場合(コードのコメント行を参照してください) または pandas データフレームの辞書を使用すると、アプリは実行されますが、ページはブラウザーに読み込まれません (レイアウトの読み込みエラー)。メモ化が解決策かもしれませんが、私が見たすべての例は、これとは微妙に異なっているように見えるため、どのように使用できるかわかりません。非表示の div の使用は、私にはちょっとしたハックのように思えますが、plotly ヘルプ ページで推奨されています。
私の質問は、文字列や配列よりも複雑なデータ構造を使用してダッシュでグローバル変数を作成および更新するにはどうすればよいですか?
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)