5

I'm new in Plotly/Dash. I'm trying to build a sentiment analysis Dashboard.

I would like to represent the "sentiment" in a graph (realtime data: from a table) I reached my fist goal so far:

I choose: trump in my SQL.

@app.callback(
    Output("live-graph", "figure"),[Input('sentiment_term', 'value'), Input('graph-update', 'n_intervals')]
)
 #Output("wind-speed", "figure")
 #Input("wind-speed-update", "n_intervals")
 #Input("sentiment_term", "value")
 #Input("graph-update", "n_intervals")]

def gen_wind_speed(self, sentiment_term):



        conn = sqlite3.connect('twitter.db')
        c = conn.cursor()
        df = pd.read_sql("SELECT * FROM sentiment WHERE tweet LIKE '%trump%' ORDER BY unix DESC LIMIT 1000", conn)
        df.sort_values('unix', inplace=True)
        df['sentiment_smoothed'] = df['sentiment'].rolling(int(len(df)/5)).mean()
        df.dropna(inplace=True)

        X = df.unix.values[-100:]
        Y = df.sentiment_smoothed.values[-100:]

        data = plotly.graph_objs.Scatter(
                x=X,
                y=Y,
                name='Scatter',
                mode= 'lines+markers'
                )

        return {'data': [data],'layout' : go.Layout(xaxis=dict(range=[min(X),max(X)]),
                                                    yaxis=dict(range=[min(Y),max(Y)]),)}

First output

Now as second goal I would like to generate (just beside the graph) a table with the data (in this case twits) used in the graph. But when I add the table I got:

A nonexistent object was used in an Input of a Dash callback. The id of this object is recent-table-update and the property is n_intervals. The string ids in the current layout are: [live-graph, sentiment_term, graph-update, bin-slider, bin-auto, bin-size, wind-histogram, recent-tweets-table]

Which I don´t understand since I used the same Input/Output "logic" that before Second output

Complete code,, apologizes if it does´t look organized enough

import os
import pathlib
import numpy as np
import pandas as pd
import datetime as dt
import dash
import dash_core_components as dcc
import dash_html_components as html
import sqlite3
import plotly
import plotly.graph_objs as go
from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output, State
from scipy.stats import rayleigh



conn = sqlite3.connect('twitter.db', check_same_thread=False)


app_colors = {
    'pageBackground': '#272B30',
    'background': '#0C0F0A',
    'text': '#6699ff',
    'sentiment-plot':'#41EAD4',
    'volume-bar':'#6699ff',
    'someothercolor':'#80aaff',
    'papercolor':'#1E2022',
    'plotcolor':'#262626',
    'fillcolor':'#ff6666',
    'gridcolor': '#737373',
    'backgroundTableHeaders': '#001133',
    'backgroundTableRows': '#002266'
}

POS_NEG_NEUT = 0.1

MAX_DF_LENGTH = 100


GRAPH_INTERVAL = os.environ.get("GRAPH_INTERVAL", 5000)

app = dash.Dash(
    __name__,
    meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
)

server = app.server

app_colorsor = {"graph_bg": "#082255", "graph_line": "#007ACE"}

app.layout = html.Div(
    [
        # header
        html.Div(
            [
                html.Div(
                    [
                        html.H4("Twitter STREAMING", className="app__header__title"),
                        html.P(
                            "This app continually queries a SQL database and displays live charts of twitter sentiment analysis.",
                            className="app__header__title--grey",
                        ),
                    ],
                    className="app__header__desc",
                ),
                html.Div(
                    [
                        html.Img(
                            src=app.get_asset_url("twitter_logo.png"),
                            className="app__menu__img",
                        )
                    ],
                    className="app__header__logo",
                ),
            ],
            className="app__header",
        ),
        html.Div(
            [
                #Plot sentiment
                html.Div(
                    [
                        html.Div(
                            [html.H6("Plot sentiment", className="graph__title")]
                        ),

                        dcc.Graph(
                            id="live-graph",
                            animate=False


                         ),


                         dcc.Input(
                            id="sentiment_term",
                            value="twitter",
                            type="text"
                        ),

                        dcc.Interval(
                        id="graph-update",
                        interval=1*1000,
                        n_intervals=0


                        ),
                    ],
                    className="two-thirds column container",
                ),
                html.Div(
                    [
                        # Recent tweets table
                        html.Div(
                            [
                                html.Div(
                                    [
                                        html.H6(
                                            "Recent tweets table",
                                            className="graph__title",
                                        )
                                    ]
                                ),
                                html.Div(
                                    [
                                        dcc.Slider(
                                            id="bin-slider",
                                            min=1,
                                            max=60,
                                            step=1,
                                            value=20,
                                            updatemode="drag",
                                            marks={
                                                20: {"label": "20"},
                                                40: {"label": "40"},
                                                60: {"label": "60"},
                                            },
                                        )
                                    ],
                                    className="slider",
                                ),
                                html.Div(
                                    [
                                        dcc.Checklist(
                                            id="bin-auto",
                                            options=[
                                                {"label": "Auto", "value": "Auto"}
                                            ],
                                            value=["Auto"],
                                            inputClassName="auto__checkbox",
                                            labelClassName="auto__label",
                                        ),
                                        html.P(
                                            "# of Bins: Auto",
                                            id="bin-size",
                                            className="auto__p",
                                        ),
                                    ],
                                    className="auto__container",
                                ),
                              #it says wind because I got it from a wind direction Dash template
                                dcc.Graph(
                                    id="wind-histogram",
                                    figure=dict(
                                        layout=dict(
                                            plot_bgcolor=app_colorsor["graph_bg"],
                                            paper_bgcolor=app_colorsor["graph_bg"],
                                        )
                                    ),
                                ),
                            ],
                            className="graph__container first",
                        ),
                        # Table that I would like to add
                         html.Div(
                                    [
                                        html.H6(
                                            "Recent tweets table",
                                            className="graph__title",
                                        )
                                    ]
                                ),


                         html.Div(id="recent-tweets-table", children=[
                                      html.Thead(html.Tr( children=[], style={'color': app_colorsors['text']})),
                                      html.Tbody([html.Tr(children=[], style={'color': app_colorsors['text'],
                                                            'background-color': app_colors['backgroundTableRows'],
                                                            'border':'0.2px', 'font - size':'0.7rem'}
                                      ],

                               className='col s12 m6 l6', style={'width':'98%', 'margin-top':30, 'margin-left':15,
                                                       'margin-right':15,'max-width':500000}

                        ),
                    ],
                    className="one-third column histogram__direction",
                ),
            ],
            className="app__content",
        ),
    ],
    className="app__container",
)





dcc.Interval(
id='recent-table-update',
interval=2*1000,
n_intervals=0),




#def get_current_time():


    #now = dt.datetime.now()
    #total_time = (now.hour * 3600) + (now.minute * 60) + (now.second)
    #return total_time

def df_resample_sizes(df, maxlen=MAX_DF_LENGTH):
    df_len = len(df)
    resample_amt = 100
    vol_df = df.copy()
    vol_df['volume'] = 1

    ms_span = (df.index[-1] - df.index[0]).seconds * 1000
    rs = int(ms_span / maxlen)

    df = df.resample('{}ms'.format(int(rs))).mean()
    df.dropna(inplace=True)

    vol_df = vol_df.resample('{}ms'.format(int(rs))).sum()
    vol_df.dropna(inplace=True)

    df = df.join(vol_df['volume'])

    return df

@app.callback(
    Output("live-graph", "figure"),[Input('sentiment_term', 'value'), Input('graph-update', 'n_intervals')]
)
 #Output("wind-speed", "figure")
 #Input("wind-speed-update", "n_intervals")
 #Input("sentiment_term", "value")
 #Input("graph-update", "n_intervals")]

def gen_wind_speed(self, sentiment_term):



        conn = sqlite3.connect('twitter.db')
        c = conn.cursor()
        df = pd.read_sql("SELECT * FROM sentiment WHERE tweet LIKE '%trump%' ORDER BY unix DESC LIMIT 1000", conn)
        df.sort_values('unix', inplace=True)
        df['sentiment_smoothed'] = df['sentiment'].rolling(int(len(df)/5)).mean()
        df.dropna(inplace=True)

        X = df.unix.values[-100:]
        Y = df.sentiment_smoothed.values[-100:]

        data = plotly.graph_objs.Scatter(
                x=X,
                y=Y,
                name='Scatter',
                mode= 'lines+markers'
                )

        return {'data': [data],'layout' : go.Layout(xaxis=dict(range=[min(X),max(X)]),
                                                    yaxis=dict(range=[min(Y),max(Y)]),)}


def generate_table(df, max_rows=20):
    return html.Table(className="responsive-table",
                      children=[
                          html.Thead(
                              html.Tr(
                                  children=[
                                      html.Th(col.title()) for col in df.columns.values],
                                  style={'color': app_colorsors['text'],
                                         'background-color': app_colorsors['backgroundTableHeaders']}
                              )
                          ),
                          html.Tbody(
                              [
                                  html.Tr(
                                      children=[
                                          html.Td(data) for data in d
                                      ], style={'color': app_colorsors['text'],
                                                'background-color': quick_color(d[2]),
                                                'border':'0.2px', 'font - size':'0.7rem'}
                                  )
                                  for d in df.values.tolist()])
                      ]
                      )



@app.callback(Output("recent-tweets-table", "children"),[Input('sentiment_term','value'), Input('recent-table-update', 'n_intervals')]
 )

def update_recent_tweets(self, sentiment_term):
    genTable = html.Table()
    try:
        conn = sqlite3.connect('twitter.db')
        df = pd.read_sql("SELECT UnixTime, Tweet, Polarity FROM %s ORDER BY UnixTime DESC LIMIT 20" % (RunConfig.tableName), conn)
        if len(df)>0:
            df['Date'] = pd.to_datetime(df['UnixTime'], unit='ms')

            df = df.drop(['UnixTime'], axis=1)
            df = df[['Date', 'Tweet', 'Polarity']]
            df.Polarity = df.Polarity.round(3)

            genTable = generate_table(df, max_rows=10)

    except Exception as e:
        with open('errors.txt','a') as f:
            f.write("update_recent_tweets: " + str(e))
            f.write('\n')

    return genTable






if __name__ == "__main__":
    app.run_server(debug=True)
1
  • 2
    In your code above the dcc.Interval component withid='recent-table-update' is outside the html.Div which contains the app layout. Commented Jun 16, 2020 at 21:31

2 Answers 2

3

I think the problem is that you are introducing a non-existing (not yet) element in the callback as input. The element is the 'recent-table-update' which doesn't exist until you update the table. To avoid this you should introduce it in the callback as a State (it doesn't trigger the callback and the code will not break). More info: link

Here is your code:

@app.callback(
Output("recent-tweets-table", "children"),
[Input('sentiment_term','value'), 
Input('recent-table-update', 'n_intervals')]
 )

Here is my suggested code:

@app.callback(
Output("recent-tweets-table", "children"),
Input('sentiment_term','value'), 
State('recent-table-update', 'n_intervals')
 )
Sign up to request clarification or add additional context in comments.

1 Comment

Switching from Input to State doesn't solve the problem.
2

In case it helps others more than the solution above, check whether you are calling the problematic id inside the layout. In some cases such as when app calls are connected (for instance when using the output of a drop-down as input for an Input) you may need to have an explicit call somewhere hidden in your layout.

To solve this you may specify html.Div(id='recent-table-update') somewhere inside the layout, which will output nothing but will activate the app call. Here, the id is the same as your problematic id.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.