Dash Table not Updating Data

I have an app which takes as input a Bloomberg ticker and outputs lots of different data (which are generated by querying Bloomberg direct using blpapi). One of the outputs is a dash table, which should show the relative performance of related securities over the years. I have encountered problems with the app because pretty much all of the functions/callbacks take a single input (the Bloomberg ticker) and they all fire simultaneously, causing the app to crash. Similarly, when the app is first loaded the callbacks are fired without an actual ticker in the input field, which creates nonsensical results from the Bloomberg calls - this also causes the app to periodically crash. To improve stability I therefore added time.sleep(x) elements to stagger each callback and some logic to suppress the initial firing of each callbacks, e.g.:

@app.callback(
    Output(component_id='whatever_output', component_property='data'),
    [Input(component_id='ticker', component_property='value')])

def function(ticker):
    if ticker is None:
        pass
    else:
        x = doWhatever(ticker)
        return x

This logic to suppress the initial callback works fine except for the callback which generates data for a dash table…after much pain I’ve found that after initially declaring the input as None and after including the aforementioned logic in the function, no matter what the value of the input the app skips over the function (I’m assuming it continues to think the value is None, even though it is definitely changing, and passes after the first logic statement).

So to elaborate, the following code works as expected:

  • the value of ‘security’ is initially None
  • but after loading the app the functions are all fired
  • because I haven’t had a chance to change the input box, the data in the table is immediately set to ‘data_AfterFiring’
  • equally, if I change the input field to ‘TEST TICKER’ the data in the table is set to ‘data_TESTTICKER’
import dash
import dash_table
import dash_table.FormatTemplate as FormatTemplate
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
  
securityComment = html.P('security', style={'fontSize':'20px', 'textAlign':'right'})

securityInput = dcc.Input(id='security', type='text', debounce=True, 
                               placeholder='ticker', value=None,
                               style={'fontSize':'20px', 'width': '200px'})
            

data_Initial = [{'ticker':'Initial Equity', 'ccy': 'EUR', '2013': 0.05, 'average': 0.05}]
data_AfterFiring = [{'ticker':'App has fired and removed the intialised data', 'ccy': 'EUR', '2013': 0.10, 'average': 0.10}]
data_TESTTICKER = [{'ticker':'UPDATED TICKER', 'ccy': 'JPY', '2013': 0.2, 'average': 0.2}]
            
forwardTable = dash_table.DataTable(id='forwardTable',
                                    columns=[
                                        {'name':'ticker', 'id':'ticker'},
                                        {'name':'ccy', 'id':'ccy'},
                                        {'name':'2013', 'id': '2013', 'type': 'numeric', 'format': FormatTemplate.percentage(2)},
                                        {'name':'average', 'id': 'average', 'type': 'numeric', 'format': FormatTemplate.percentage(2)}],
                                    filter_action='native',
                                    sort_action='native',
                                    style_header={'fontSize':'12px'},
                                    style_data={'fontSize':'12px'},
                                    data=data_Initial)
                                    
security = html.Div(
        [
                dbc.Row(
                        [
                                dbc.Col(securityComment, width=1),
                                dbc.Col(securityInput, width=1)
                        ]
                    )
            ]
        )
                
forwardAnalysis = html.Div(
        [
                dbc.Col(forwardTable, width=12)
        ]
    )

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([security, 

@app.callback(
    Output(component_id='forwardTable', component_property='data'),
    [Input(component_id='security', component_property='value')])

def fundForwardAnalysis(security):
    if security == 'TEST TICKER':
        return data_TESTTICKER
    else:  
        return data_AfterFiring

if __name__ == '__main__':
    app.run_server(debug=False)

However, now when I add the logic to suppress the initial firing I get the following behavior:

  • the app loads and correctly reads that security == None, therefore the ‘data_Initial’ continues to display
  • but no matter what value the security ticker takes afterwards, nothing is updated…
@app.callback(
    Output(component_id='forwardTable', component_property='data'),
    [Input(component_id='security', component_property='value')])

def fundForwardAnalysis(security):
    if security is None:
        pass
    elif security == 'TEST TICKER':
        return data_TESTTICKER
    else:  
        return data_AfterFiring

if __name__ == '__main__':
    app.run_server(debug=False)

I have ten other callbacks where the initial firing is suppressed with this simple logic and they all work fine after the value of ‘security’ is changed to a proper ticker…I have no idea what is going on here. Equally, I have to suppress this particular initial callback because this function is responsible for 99% of the crashes (as in, when I comment this one out of my code the app is significantly more stable…).

Any comments, suggestions would be most welcome…

Thanks