I am putting together an app that produces output that is updated hourly by a computationally expensive function. I don’t want the computationally expensive function to run when a user launches the app as it takes a long time, but rather I’d like it to run in the background on the server which would then serve up the updated data to all users of the app.
I have included code below as an example of my problem. The app is initialized with null values (999) and then every 20 seconds (instead of every hour) it updates the app components using current time/date information. Every time I reload the app it comes up with the null values and then updates the values after 20 seconds. I would prefer it to somehow used the latest data stored in the hidden div. I appreciate that the interval component runs on the client side, but is there a way to make it a server process? Am I trying to do something way different to what Dash is designed to do?
One solution would be update the data on my personal computer and redeploy the app on the remote server every hour, but it seems like an inelegant solution as I would then have to have a computer dedicated to task of updating an app on a remote server.
I’m coming at this as a scientist not a web person so apologies if this is total newbie stuff.
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
#Initial condition
d = {'time' : pd.Series(np.array([999, 999]), index=['minute', 'second'])}
dat = pd.DataFrame(d).to_json()
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)