Greetings, I’m struggling to implement a loading icon next to my dropdown input. I can’t seem to be able to make that addition to my dashboard syntax below. I’m trying not to implement another callback in doing so.
body = html.Div(
[dbc.Jumbotron(
[
dbc.Row(dbc.Col(children=[dbc.Spinner(dcc.Dropdown(id="dynamic-dropdown", options=OPTIONS, multi=True, placeholder="Enter your SP500 Symbols"))], lg=6, md=7, sm=12, xs=12),justify='center')
], style = {'background-color': '#68d984','margin-bottom':'0px','border-radius':'50px','width':'90%', 'margin-left':'auto','margin-right':'auto'}, fluid=True )
, dbc.Row(dbc.Col([
],id='graph',lg=9, md=11, sm=12 , xs=12),style={'width':'100%'},justify="center")
])
app.layout = html.Div([body])
@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 '1 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','color':'#ABABAB'}),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')
I have only been able to replace my dropdown with a loading icon, but that can get annoying for users, also I wasn’t able to replicate the loading for more than one callback firing.
How can I implement a loading icon or spinner next to a dropdown, appearing only during callback load times?