Dash App doesn't stop updating

Hi All,

I have been looking around also also tried to find similar topic in google but no result. So I decided to ask here.

1- I have a dash app which plot a water fall graph with clickevent.
2- with user click on bar on waterfall chart, a table is created with selected value.
3- Selecting a cell in table on step 2 will trigger another table filtered with selected value.
4 -another table triggered with cell value selected on step 3.
5- Another table triggered with cell value selected on step 4.

I some how managed to get until step 3. However, when i add rest of the steps into code below, dash keep updating. It constantly say Updating as in picture below.

image

Since it stucks somewhere (which i couldn’t find where and what), callbacks are not fired. And app breaks even though there is no error message.

I would really appreciate if you can help me out on this since i am trying to understand and solve it since 2 days.

The code is below:

 import dash_core_components as dcc 
 import dash_html_components as html
 from dash.dependencies import Input, Output, State
 import dash_table
 import dash_daq as daq
 import plotly.graph_objs as go
 import pandas as pd
 import datetime as dt
 import os, sys
 from app import app
 import json

def layout():
    sops = ['A','B','C']
    return (
        # control panel
        html.Ul(className='col-lg-2 left-pan', style={
                                                      'margin-top': '0.6%',
                                                      'height': '97%',
                                                    #   'overflow-y': 'scroll',
                                                    }, children=[
            html.Br(),
            html.Div(className='page-header', children=[
                html.H5('Please select SOP',
                         style={'fontSize': '17', 'fontFamily': 'Times New Roman, Times, serif', 'fontWeight': 'bold',
                                'color': '#23529d', 'fontStyle': 'italic'}),
                dcc.Dropdown(
                    id='sop_dropdown',
                    options=[{'label': i, 'value': i} for i in sops],
                    value='Benelux')
            ]),
            ]),
             html.Br(),
             html.Br(),
           # bs row with page title
            html.Div(className='row', children=[
            html.Div(className='col-lg-2'),
            html.Div(className='col-lg-10', children=html.H3(className='page-header center-text',
                                                             children='Title')),
            html.Div(className='col-lg-2')]
                 ),
        # bs row with content
        html.Div(className='row', children=[
            html.Div(className='col-lg-3'),
            # graphs/tables
            html.Div(className='col-lg-8', children=[

                html.Div(className='col-lg-12', children=[dcc.Graph(id='waterfall_graph')]),
                html.Div(className='col-lg-12', children=html.H1('')),
                html.Div(className='col-lg-12', style={'display':'None'}, id='', children=dcc.Store(id='store_main_df', storage_type='session')), # COMMENT : to store data selected data to use commonly later. 

                html.Div(className='col-lg-1', children = [daq.BooleanSwitch(id='x_table_booleanswitch', on=False)]),
                html.Div(className='col-lg-12', id='x_table'),

                html.Div(className='col-lg-1', children = [daq.BooleanSwitch(id='y_table_booleanswitch', on=False)]),
                html.Div(className='col-lg-12', id='y_table'),

                html.Div(className='col-lg-1', children = [daq.BooleanSwitch(id='z_table_booleanswitch', on=False)]),
                html.Div(className='col-lg-12', id='z_table'),

                html.Div(className='col-lg-1', children = [daq.BooleanSwitch(id='a_table_booleanswitch', on=False)]),
                html.Div(className='col-lg-12', id='a_table'),

                html.Div(className='col-lg-8'),
                html.Div(className='col-lg-4', children = [
                    html.Button('1.Generate', className='btn btn-default', id='generate_button', n_clicks=0),
                    html.A('2.Download',className='btn btn-default', id='download_table', download='tabledata.csv', href='')
                    ],
                    style= {'text-align':'right', 'padding-right':'inherit'}),

            ]),

            html.Div(className='col-lg-2'),

        ]),
        html.Br(),
    )


@app.callback(Output(component_id='waterfall_graph', component_property='figure'),
        [Input(component_id='sop_dropdown', component_property='value')])

def graph(sop):
    ##### Do Some calculations 
    # Make waterfall clickable
    fig.layout.clickmode = 'event+select'

    return fig 



@app.callback(Output(component_id='store_main_df', component_property='data'),
            [Input(component_id='waterfall_graph', component_property='selectedData'),
            Input(component_id='sop_dropdown', component_property='value')])
def table(selectedData, sop):
    if selectedData is None or len(selectedData) == 0:
        bar_selection = selectedData
    else:
        bar_selection = selectedData['points'][0]['x']
    
    table_df = #do some filtering 

    # TODO rescript with IF clause
    for columns in table_df.columns:
            try:
                table_df[columns]=round(pd.to_numeric(table_df[columns]),4)
            except ValueError:
                pass
    return table_df.to_json(date_format='iso', orient='split')

# # TODO : sorting 
@app.callback(Output(component_id='x_table', component_property='children'),
            [Input(component_id='store_main_df', component_property='data'),
            Input(component_id='x_table_booleanswitch', component_property='on')])
def x_table(main_df, switch_button):
    if not switch_button:
        pass
    else:
        x_table_df = pd.read_json(main_df, orient='split')
        

        x_table_df = # do some filtering 

        x_selected_table= dash_table.DataTable(
            id='x_table',
            data=x_table_df.to_dict('records'),
            columns = [{'name': c, 'id': c, 'hideable': True, 'deletable':True} for c in x_table_df.columns if not x_table_df.empty])

        if x_table_df.empty:
            return None
        else:
            return [html.Div(className='col-lg-12', children=[
                html.H3(className='page-header center-text',children=f'List of items'),
                html.Div(children=x_selected_table)])]


@app.callback(Output(component_id='y_table',component_property='children'),
            [Input(component_id='store_main_df', component_property='data'),
            Input(component_id='x_table',component_property='data'),
            Input(component_id='x_table',component_property='active_cell'),
            Input(component_id='y_table_booleanswitch', component_property='on')])
def y_table(main_df, data, active_cell, switch_button):
    if not switch_button:
        pass
    else:
        y_df = pd.DataFrame.from_records(data)
        try:
            selected_cell = y_df.iloc[active_cell['row'],active_cell['column']]
        except TypeError:
            selected_cell = ''
        
        y_table_df = pd.read_json(main_df, orient='split')

        y_table_df = # do some calculations 

        


        y_selected_table= dash_table.DataTable(
            id='y_dash_table',
            data=y_table_df.to_dict('records'),
            columns = [{'name': c, 'id': c, 'hideable': True, 'deletable':True} for c in y_table_df.columns if not y_table_df.empty])

        if y_table_df.empty:
            return None
        else:
            return [html.Div(className='col-lg-12', children=[
                html.H3(className='page-header center-text',children=f'List of items'),
                html.Div(children=y_selected_table)])]



@app.callback(Output(component_id='z_table',component_property='children'),
            [Input(component_id='store_main_df', component_property='data'),
            Input(component_id='y_dash_table',component_property='data'),
            Input(component_id='y_dash_table',component_property='active_cell'),
            Input(component_id='z_table_booleanswitch', component_property='on')])
def z_table(main_df,data, active_cell, switch_button):
    if not switch_button:
        pass
    else:
        z_df = pd.DataFrame.from_records(data)
        try:
            selected_cell = z_df.iloc[active_cell['row'],active_cell['column']]
        except TypeError:
            selected_cell = ''
        
        z_table_df = pd.read_json(main_df, orient='split')

        z_table_df = # do some calculations 

        


        z_selected_table= dash_table.DataTable(
            id='z_dash_table',
            data=z_table_df.to_dict('records'),
            columns = [{'name': c, 'id': c, 'hideable': True, 'deletable':True} for c in z_table_df.columns if not z_table_df.empty])
        if z_table_df.empty:
            return None
        else:
            return [html.Div(className='col-lg-12 btn btn-default', children=[
                html.H3(className='page-header center-text',children=f'List of items'),
                html.Div(children=z_selected_table)])]
    

@app.callback(Output(component_id='a_table',component_property='children'),
            [Input(component_id='store_main_df', component_property='data'),
            Input(component_id='z_dash_table',component_property='data'),
            Input(component_id='z_dash_table',component_property='active_cell'),
            Input(component_id='a_table_booleanswitch', component_property='on')])
def a_table(main_df,data, active_cell, switch_button):
    if not switch_button:
        pass
    else:
        a_df = pd.DataFrame.from_records(data)
        try:
            selected_cell = a_df.iloc[active_cell['row'],active_cell['column']]
        except TypeError:
            selected_cell = ''
        
        a_table_df = pd.read_json(main_df, orient='split')

        a_table_df = # do some filtering 

        a_selected_table= dash_table.DataTable(
            id='sa_dash_table',
            data=a_table_df.to_dict('records'),
            columns = [{'name': c, 'id': c, 'hideable': True, 'deletable':True} for c in a_table_df.columns if not a_table_df.empty])
        if a_table_df.empty:
            return 'Table is Empty'
        else:
            return [html.Div(className='col-lg-12', children=[
                html.H3(className='page-header center-text',children=f'List of as'),
                html.Div(children=a_selected_table)])]

Hi Kabbe,

I had the same issue last week. I did not looked at your code at detailed level, but maybe it helps if I share my experience. I fixed my issue, so hopefully your can too!

I’ve followed the following routine:

  • I wasn’t sure where the update loop came from so I tried to isolate the problem.
  • I deleted (commented) most of my dashboards and tried to run all the parts independently.
  • When I found the function / callback which caused the updating I tried to fix it.
  • In my case I was updating a .div with a callback. After the .div was updated the callback was fired again because the div was changed (by the same callback).
  • I managed to change the callback from updating the div to actually updating a specific component.

Some advice:
Try to make the code as small as possible to isolate the problem. This is only needed when you have no clue where the find the problem.

Tip:
Perhaps this url https://dash.plot.ly/faqs will help you. You can add some code to see which input has changed. Add it to the functions which you suspect.

Good luck.

Hey Sampah,
thanks for comment and help.

I believe i found the issue.

On step 3, I am calling ‘selected_cell’ of data_table of step 2.
However, since there is no table before clicking on bar in waterfall graph. I believe callback is not able to find any active_cell.

So, i added

x_dash_table(
.....
active_cell = {'row':0, 'columns':0},
...
)

I am gonna go step by step and be sure that there is always active cell and data available for callbacks.