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)]),)}
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

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)

dcc.Intervalcomponent withid='recent-table-update'is outside thehtml.Divwhich contains the app layout.