Greetings, I have a dropdown where users can input multiple or single value items, for my case stock market symbols.
My dash app is a blank input bar using dcc.dropdown(), until symbols are entered from the available options, this triggers all of my callbacks to fire , which return tables and graphs using html.div and children format.
Things start getting really weird when a user deletes all of their inputs from the dropdown bar. My dcc.graph
wont update anymore after a user deletes their inputs, it just gets stuck and hangs. But, the rest of my datatables will keep updating like everything is working fine.
here is my code:
The first callback is my graph, the rest are my tables.
from django_plotly_dash import DjangoDash
import dash
import dash_table as dt
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.express as px
import plotly.graph_objs as go
from dash.exceptions import PreventUpdate
import pandas as pd
import psycopg2
from psycopg2 import sql
from .connect import *
from .dash_tables import *
from .dash_tooltips import *
from collections import defaultdict
# app_colors = {
# 'background': '#0C0F0A',
# 'text': '#FFFFFF',
# 'sentiment-plot':'#41EAD4',
# 'volume-bar':'#FBFC74',
# 'someothercolor':'#FF206E',
# }
stock_ids = execute_query(conn, "SELECT DISTINCT symbol FROM security_price;")
stock_ids = [i[0] for i in stock_ids]
options = [{'label': i, 'value': i} for i in stock_ids]
app = DjangoDash('StockBuckets', add_bootstrap_links=True, external_stylesheets=[dbc.themes.LUX], suppress_callback_exceptions = True,
meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1.0"}])
body = html.Div(
[dbc.Jumbotron(
[
dbc.Container(dcc.Dropdown(id="dynamic-dropdown", options=options, multi=True, placeholder="Enter Symbols of Interest"),
fluid=True
)
],
style = {'background-color': '#68d984'}, fluid=True,
)
, dbc.Row(dbc.Col(html.Div([
],id='output-graph'),lg=8, md=11, sm=12 , xs=12),style = {'width': '100%'},justify="center")
, html.Div(style={"width":"100%", "height":'25px'})
, dbc.Row([
dbc.Col(children=[
],id='quickfacts',lg=4, md=11, sm=12 ,xs=12)
, dbc.Col(children=[
], id='returnrates',lg=7, md=11, sm=12 ,xs=12)
],style = {'width': '100%'}, justify="center", align="center")
, html.Div(style={"width":"100%", "height":'25px'})
, dbc.Row(dbc.Col(children=[
], id='advancedstats', lg=11, md=11, sm=12 , xs=12),style = {'width': '100%'}, justify="center", align="center")
, html.Div(style={"width":"100%", "height":'25px'})
, dbc.Row([dbc.Col(children=[
],id= 'nextreport',lg=4, md=4, sm=12 , xs=12)
, dbc.Col(children=[
],id='nextdividend',lg=4, md=4, sm=12 , xs=12)
],style = {'width': '100%'}, justify="center", align='center'),
])
app.layout = html.Div([body])
@app.callback(
Output('output-graph', 'children'),
[Input('dynamic-dropdown', 'value')],
[State('output-graph','children')])
def tickers(symbols, children):
conn.rollback()
if symbols == None:
conn.rollback()
raise PreventUpdate
elif symbols == 0:
conn.rollback()
raise PreventUpdate
elif symbols == []:
conn.rollback()
raise PreventUpdate
elif not symbols:
conn.rollback()
raise PreventUpdate
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, close FROM security_price WHERE security_price.symbol IN %s;", [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['close'] for rec in stock_data_by_symbol[stock]]
trace.append(go.Scattergl(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=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'],
paper_bgcolor='rgba(0, 0, 0, 0)',
plot_bgcolor='rgba(0, 0, 0, 0)',
margin={'b': 15},
hovermode='x',
autosize=True,
title={'text': 'Historical Price Graph', 'font': {'color': 'black'}, 'x': 0.5},
),
}
children = html.Div([dcc.Graph(id='graph', figure=figure ,config={'displayModeBar': False}, animate=True)])
return children
@app.callback(
dash.dependencies.Output('quickfacts', 'children'),
[dash.dependencies.Input('dynamic-dropdown', 'value')])
def statsTable(symbols):
conn.rollback()
if symbols == None:
conn.rollback()
raise PreventUpdate
placeholders = ", ".join(['%s' for _ in symbols])
# PREPARED STATEMENT WITH PARAM PLACEHOLDERS
sql = f"""SELECT DISTINCT ON (id) id, cast(marketcap as money), cast(week52high as money), cast(week52low as money)
, to_char(dividend_yield * 100, '99D99%%')
, pe_ratio, ROUND(beta,2)
FROM security_stats
WHERE security_stats.id IN ({placeholders}) ORDER BY id, date desc;
"""
df = postgresql_to_dataframe_v1(conn, sql, symbols, stats_col)
columns =[{"name": i, "id": i} for i in df.columns]
data_dict = df.to_dict('records')
children = html.Div([
html.H4('Quick Facts:', style={'color':'#474747','margin-left':'10px'}),
html.P('General information', style={'color': '#A2A2A2','margin-left':'10px'}),
html.Div(dt.DataTable(data=data_dict, columns=columns, style_as_list_view=True,
tooltip_data=[quickFacts],
tooltip_duration = 10000,
style_cell={'padding': '15px', 'font_family': 'Segoe UI','font_size': '10px'},
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
},
style_data_conditional=[
{
'if': {'row_index': 'even'},
'backgroundColor': 'rgb(248, 248, 248)'
}
],
style_data = {'border': 'none'},
style_table={'overflowX': 'scroll'},
style_cell_conditional=[
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Symbol']
]
), style={'width': '100%','padding': '16px'})],style = {'margin-left':'15px','width':'100%'})
return children
@app.callback(
dash.dependencies.Output('returnrates', 'children'),
[dash.dependencies.Input('dynamic-dropdown', 'value')])
def changeTable(symbols):
print(symbols)
if symbols == None:
conn.rollback()
raise PreventUpdate
conn.rollback()
placeholders = ", ".join(['%s' for _ in symbols])
# PREPARED STATEMENT WITH PARAM PLACEHOLDERS
sql = f"""SELECT DISTINCT ON (id) id, to_char(100.0*ytd_changepercent,'999D99%%'), to_char(100.0*day5_changepercent,'999D99%%'), to_char(100.0*day30_changepercent,'999D99%%')
, to_char(100.0*month3_changepercent,'999D99%%'), to_char(100.0*month6_changepercent,'999D99%%'), to_char(100.0*year1_changepercent,'999D99%%')
, to_char(100.0*year2_changepercent,'999D99%%'),to_char(100.0*year5_changepercent,'9999D99%%'),to_char(100.0*max_changepercent,'99999D99%%')
FROM security_stats
WHERE security_stats.id IN ({placeholders}) ORDER BY id, date desc;
"""
df = postgresql_to_dataframe_v1(conn, sql, symbols, change_col)
columns =[{"name": i, "id": i} for i in df.columns]
data_dict = df.to_dict('records')
children = html.Div([html.H4('Historical Return-rates:', style={'color':'#474747','margin-left':'10px'}),
html.P('Equity growth based on time periods', style={'color':'#A2A2A2','margin-left':'10px'}),
html.Div(dt.DataTable(data=data_dict, columns=columns, style_as_list_view=True,
style_cell={'padding': '15px', 'font_family': 'Segoe UI','font_size': '10px'},
fixed_columns={'headers': True, 'data': 1},
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
},style_data_conditional=[
{
'if': {'row_index': 'even'},
'backgroundColor': 'rgb(248, 248, 248)'
}
],
style_data = {'border': 'none'},
style_table={'overflowX': 'scroll'},
style_cell_conditional=[
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Symbol']
]
), style={'width': '100%','padding': '16px'})],style = {'margin-left':'15px','width':'100%'})
return children
@app.callback(
dash.dependencies.Output('advancedstats', 'children'),
[dash.dependencies.Input('dynamic-dropdown', 'value')])
def advancedstatsTable(symbols):
conn.rollback()
if symbols == None:
conn.rollback()
raise PreventUpdate
placeholders = ", ".join(['%s' for _ in symbols])
# PREPARED STATEMENT WITH PARAM PLACEHOLDERS
sql = f"""SELECT DISTINCT ON (id) id, cast(enterprisevalue as money), ROUND(enterprise_value_revenue, 2),ROUND(revenuepershare,2)
, ROUND(debt_to_equity, 2), ROUND(profitmargin, 2), ROUND(price_to_sales, 2), ROUND(price_to_book, 2)
, ROUND(put_call_ratio, 2), cast(ROUND(revenue_per_employee, 2) as money)
FROM security_advanced_stats
WHERE security_advanced_stats.id IN ({placeholders}) ORDER BY id, date desc;
"""
df = postgresql_to_dataframe_v1(conn, sql, symbols, adv_stats_col)
columns =[{"name": i, "id": i} for i in df.columns]
data_dict = df.to_dict('rows')
children = html.Div([html.H4('Advanced Stats:', style={'color':'#474747','margin-left':'10px'}),
html.P('"Behind-the-scene" metrics that measures company preformance', style={'color': '#A2A2A2','margin-left':'10px'}),
html.Div(dt.DataTable(data=data_dict, columns=columns, style_as_list_view=True,
tooltip_data=[advancedStats],
tooltip_duration = 10000,
style_cell={'padding': '15px', 'font_family': 'Segoe UI','font_size': '10px'},
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
},
style_data_conditional=[
{
'if': {'row_index': 'even'},
'backgroundColor': 'rgb(248, 248, 248)'
}
],
style_data = {'border': 'none'},
style_table={'overflowX': 'scroll'},
style_cell_conditional=[
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Symbol']
]
), style={'width': '100%','padding': '16px'})],style = {'margin-left':'15px','width':'100%'})
return children
@app.callback(
dash.dependencies.Output('nextreport', 'children'),
[dash.dependencies.Input('dynamic-dropdown', 'value')])
def earningsTable(symbols):
conn.rollback()
if symbols == None:
conn.rollback()
raise PreventUpdate
placeholders = ", ".join(['%s' for _ in symbols])
# PREPARED STATEMENT WITH PARAM PLACEHOLDERS
sql = f"""SELECT DISTINCT ON (id) id, next_earnings_date
FROM security_stats
WHERE security_stats.id IN ({placeholders}) ORDER BY id, date desc;
"""
df = postgresql_to_dataframe_v1(conn, sql, symbols, ['Symbol','Report Date'])
columns =[{"name": i, "id": i} for i in df.columns]
data_dict = df.to_dict('rows')
children = html.Div([html.H4('Next Financial Report:', style={'color':'#474747','margin-left':'10px','margin-top':'40px'}),
html.P('Quarterly or Yearly reports that influence the prices of equities', style={'color': '#A2A2A2','margin-left':'10px'}),
html.Div(dt.DataTable(data=data_dict, columns=columns, style_as_list_view=True,
style_cell={'padding': '15px', 'font_family': 'Segoe UI','font_size': '10px','width': '10%','min-width': 'unset'},
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
},
style_data_conditional=[
{
'if': {'row_index': 'even'},
'backgroundColor': 'rgb(248, 248, 248)'
}
],
style_data = {'border': 'none'},
style_cell_conditional=[
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Symbol']
]
),style={'margin':'auto','padding': '16px', 'width':'100%', 'min-width': 'unset'})],style = {'margin-left':'15px','width':'100%'})
return children
@app.callback(
dash.dependencies.Output('nextdividend', 'children'),
[dash.dependencies.Input('dynamic-dropdown', 'value')])
def dividendTable(symbols):
conn.rollback()
if symbols == None:
conn.rollback()
raise PreventUpdate
placeholders = ", ".join(['%s' for _ in symbols])
# PREPARED STATEMENT WITH PARAM PLACEHOLDERS
sql = f"""SELECT DISTINCT ON (id) id, next_dividend_date, ex_dividend_date
FROM security_stats
WHERE security_stats.id IN ({placeholders}) ORDER BY id, date desc;
"""
df = postgresql_to_dataframe_v1(conn, sql, symbols, ['Symbol','Next Dividend Date','Ex-Dividend Date'])
columns =[{"name": i, "id": i} for i in df.columns]
data_dict = df.to_dict('rows')
children = html.Div([html.H4('Dividend Periods:', style={'color':'#474747','margin-left':'10px', 'margin-top':'40px'}),
html.P("Check for dividend eligibility", style={'color': '#A2A2A2','margin-left':'10px'}),
html.Div(dt.DataTable(data=data_dict, columns=columns, style_as_list_view=True,
tooltip_data=[dividendPeriods],
tooltip_duration = 10000,
tooltip_conditional = {'tooltip_duration':'10000ms'},
style_cell={'padding': '15px', 'font_family': 'Segoe UI','font_size': '10px','width': '10%','min-width': 'unset'},
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
},
style_data_conditional=[
{
'if': {'row_index': 'even'},
'backgroundColor': 'rgb(248, 248, 248)'
}
],
style_data = {'border': 'none'},
style_cell_conditional=[
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Symbol']
]
),style={'margin':'auto','padding': '16px', 'width':'100%', 'min-width': 'unset'})],style = {'margin-left':'15px','width':'100%'})
return children
Here are the errors I’m getting:
Can anyone locate why this is happening? I’m trying to play around with raise PreventUpdate
as you see, but I’m not successful.