Skip to content

Output and Input/State pointing at same Data Table breaks Interval update #616

@michael-ziedalski

Description

@michael-ziedalski

I previously made a series of confused forum posts here attempting to get to the bottom of this issue.

Essentially, I am trying to make a live Twitter app, which uses callbacks that need to know if the app's Data Table is already populated or not with some tweets (or is in its default empty state, where only the column names appear).

So, I have one callback sending output to the Data Table, which will be different depending on if a State input says the Data Table is already populated. This State input refers to a dcc.Store object, which in turn is controlled by a second callback, which monitors the original Data Table to see if it has any data in it/has already been populated.

Somehow, this semi-circular dynamic (which normally works) breaks the dcc.Interval component controlling the first callback. In my attempt at a MWE below, if you comment out the bottom callback, the first one successfully runs every 3 seconds as it's supposed to.

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from dash.dependencies import Input, Output, State

import datetime as dt

###### Setup ######

app = dash.Dash(dev_tools_hot_reload=True)
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True


###### Main code ######

app.layout = html.Div(children=[

    html.H3('Twitter App'),

    html.Div(children=[
                       html.Label('Twitter id(s)',
                                  style={'grid-row':'1 / 2', 'grid-column':'1 / 2'}),
                       dcc.Input('ScreenName_Input', type='text',
                                  style={'grid-row':'2 / 3', 'grid-column':'1 / 2'}),

                       html.Label('# of tweets',
                                  style={'grid-row':'1 / 2', 'grid-column':'2 / 3'}),
                       dcc.Input(id='NumberOfTweets', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'2 / 3'}),

                       html.Button(id='screenNames_submit_button', children='Submit',
                                   style={'grid-row':'2 / 3', 'grid-column':'3 / 4'}),

                       html.Button(id='time_Stream', children='Stream time',
                                   style={'grid-row':'2 / 3', 'grid-column':'4 / 5'}),

                       html.Button(id='pauseStream', children='Pause collection',
                                   style={'grid-row':'2 / 3', 'grid-column':'5 / 6'})

    ],
              style={'display':'grid', 'grid-template-rows':'25px 25px 25px 25px', 
                     'grid-auto-columns': '100px 100px 100px 100px 150px'}
            ),


    html.Div(children=[
             dash_table.DataTable(id='tweet_table', columns=[
                                                {'name': 'Date', 'id': 'Date'},
                                                {'name': 'Author', 'id': 'Author'},
                                                {'name': 'Len', 'id': 'Length'},
                                                {'name': 'Favs', 'id': 'Favorites'},
                                                {'name': "Retw", 'id': 'Retweets'},
                                                {'name': 'Text', 'id': 'Text'}]
                                 ),

            html.Div(children=[  

                html.H1(children='Analysis',
                        style={'margin-top':'-40px'}),

                dcc.Graph(id='sentiment_graph', 
                          figure={'data': [{'type':'histogram'}]}

                         )
            ])
    ],

              style={'display':'grid', 'grid-template-columns': '1fr 1fr', 'column-gap':'20px',
                     'margin-top':'-25px'}),


    html.Div(children=[
        dcc.Store(id='table_exists_or_not'),
        dcc.Interval(id='table_update', interval=3*1000, n_intervals=0)
    ])

])


###### Callbacks ######

## First callback
@app.callback(
     Output(component_id='tweet_table', component_property='data'),
    [Input(component_id='table_update', component_property='n_intervals')],
    [State(component_id='ScreenName_Input', component_property='value'),
     State(component_id='NumberOfTweets', component_property='value'),
     State(component_id='table_exists_or_not', component_property='data')]
)
def tweet_table_1(update_interval, screen_names, number_tweets, table_exists_or_not):

    print('Time is {}'.format(dt.datetime.now()))
    return None


## Second callback
@app.callback(
    Output(component_id='table_exists_or_not', component_property='data'),
    [Input(component_id='screenNames_submit_button', component_property='n_clicks_timestamp')],
    [State(component_id='tweet_table', component_property='data_timestamp')]
)
def table_exists_or_not(button_click, table_exists):

    if table_exists:
        print('Table seems to exist: {}'.format(table_exists))
        return 1

    else:
        print('Table does not exist: {}'.format(table_exists))
        return 0    


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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions