Deleting input values in dropdown breaks my dcc.graph?

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.

So I managed to “fix” my graph error, turns out it was something completely different than the red errors above. My dashboard now works great, but I would like to know why im still getting those errors. I think it has something to do with my children and callback layouts?

SOLVED: adding this conditional to callback functions that make children appear:

@app.callback(
    Output('graph', 'children'),
    [Input('dynamic-dropdown', 'value')],
    [State('graph','children')])

def tickers(symbols, children):
    if symbols == None:
        return []
    elif symbols == []:
        return []
    else:
           #do rest of function...

adding [] in the if statements made my children elements from my callback disappear after a user clears their inputs. I don’t get any error anymore. I am not using raise PreventUpdate anymore, I find it a little strange that I don’t need to implment that in my project. But oh well my dashboard works.