Greetings,
I’m trying to see if it’s possible to implement my callback using client side javascript. I noticed on the https://dash.plotly.com/clientside-callbacks documentation, at the bottom, it says: Clientside callbacks are not possible if you need to refer to global variables on the server or a DB call is required.
My callback gets data from my SQL dB, I was wondering if this would be an issue?
I have an interactive multi-dropdown that feeds inputted values into my graph callback, which pulls required parameters from my dB using SQL to provide X and Y data for my graph. The return generates my graph and some additional surrounding HTML.
@app.callback(
dash.dependencies.Output("dynamic-dropdown", "options"),
[dash.dependencies.Input("dynamic-dropdown", "search_value")],
[dash.dependencies.State("dynamic-dropdown", "value")],
)
def update_multi_options(search_value, value):
if not search_value:
raise PreventUpdate
# Make sure that the set values are in the option list, else they will disappear
# from the shown select list, but still part of the `value`.
return [
o for o in OPTIONS if search_value in o["label"] or o["value"] in (value or [])
]
@app.callback(
Output('graph', 'children'),
[Input('dynamic-dropdown', 'value')],
[State('graph','children')])
def tickers(symbols, children):
conn.rollback()
if symbols == None:
conn.rollback()
return []
elif symbols == []:
conn.rollback()
return []
else:
stock_info = {}
d = {} #dates
p = {} #prices
sym_ids = tuple([id for id in symbols])
stock_info = {}
stock_info = get_dict_resultset("SELECT symbol, date, adj_close FROM api.security_price WHERE security_price.symbol IN %s AND date > (SELECT MAX(date) FROM api.security_price) - interval '5 years' ORDER by date;", [sym_ids])
stock_data_by_symbol = defaultdict(list)
for entry in stock_info:
symbol = entry['symbol']
stock_data_by_symbol[symbol].append(entry)
trace = []
for stock in symbols:
d[stock] = [rec['date'] for rec in stock_data_by_symbol[stock]]
p[stock] = [rec['adj_close'] for rec in stock_data_by_symbol[stock]]
trace.append(go.Scatter(x=d[stock],
y=p[stock],
mode='lines',
text = d[stock],
opacity=0.7,
name=stock,
textposition='bottom center'))
traces = [trace]
data = [val for sublist in traces for val in sublist]
figure = {'data': data,
'layout': go.Layout(
colorway=["#9b5de5", '#00f5d4', '#FFD23F', '#f15bb5', '#f71735', '#d08c60'],
paper_bgcolor='rgba(0, 0, 0, 0)',
plot_bgcolor='rgba(0, 0, 0, 0)',
margin={
'l': 40, # left margin, in px
'r': 10, # right margin, in px
't': 16, # top margin, in px
'b': 30,}, # bottom margin, in px
hovermode='x',
legend={"x" : 0, "y" : 1, 'font': {'size': 10}},
xaxis={'rangeselector': {'buttons': list([
{'count': 1, 'label': '1M',
'step': 'month',
'stepmode': 'backward'},
{'count': 3, 'label': '3M',
'step': 'month',
'stepmode': 'backward'},
{'count': 6, 'label': '6M',
'step': 'month',
'stepmode': 'backward'},
{'count': 1, 'label': '1Y',
'step': 'year',
'stepmode': 'backward'},
{'count': 3, 'label': '3Y',
'step': 'year',
'stepmode': 'backward'},
{'count': 1, 'label': 'YTD',
'step': 'year',
'stepmode': 'todate'},
{'step': 'all','label':'MAX'},
])},
'rangeslider': {'visible': True}, 'type': 'date'},
),
}
children = [
dbc.Row(dbc.Col(html.P("As of {}, {}".format(d[stock][-1].strftime('%A'),d[stock][-1].strftime('%d %m-%Y')),style={'font-size':'12px','font_family':'Helvetica Neue', 'margin-top':'10px'}),style={'position':'relative','float':'right'}, width={"offset": 3}), justify='end'),
html.Div(style={"width":"100%", "height":'30px'}),
html.H4('Historical Price Chart:', style={'color':'#474747','margin-left':'30px'}),
html.P('Interactive graph for end-of-day prices', style={'color':'#A2A2A2','margin-left':'30px'}),
dcc.Graph(id='output-graph', figure=figure ,config={'displayModeBar': False}, animate=True,style = {'width': '100%', 'touch-action':'none'}),
html.P('* Drag sliders to create your own custom date range', style={'font-size':'12px','color':'#A2A2A2','margin-left':'40px'}),
html.P('** Double-tap or double-click the main graph to reset axis', style={'font-size':'12px','color':'#A2A2A2','margin-left':'40px'}),
html.Div(style={"width":"100%", "height":'10px'}),
]
return dcc.Loading(id='graph',children=children,type='graph')
Because users can input multiple values in my dropdown, things can get really slow really fast. Having to re-download all the data for each callback fire makes no sense. Is there any way to fix this issue a callback design? The disclaimer at the bottom of the documentation has given me doubts.