My callback is updating only the lines of the graph but not the legend

Hi,

I have a callback to update my graph and a dropdown box where I select which IP I want to update the graph. The graph line is been updated but the legend is not. I created a “graphName=‘Sensor "’ + '” @’ + k.address" variable that I update when I change the dropdown box. The values are being updated when I check the console but the graph is not “name=graphName”. The strange thing is that when I click on the legend it gets updated.

return {'data': [plotly.graph_objs.Scatter(
            x=list(X),
            y=list(Y),
            name=graphName,
            mode= 'lines+markers')],
        'layout' : go.Layout(
            title="SENSE - Sensor readings queries",
            showlegend=True,
            legend=go.layout.Legend(x=0,y=1.0),
            xaxis=dict(range=[min(X),max(X)]),
            yaxis=dict(range=[min(Y),max(Y)]),)

#!/bin/python3

import dash
from dash.dependencies import Output, Event
import dash_core_components as dcc
import dash_html_components as html
import plotly
import random
import plotly.graph_objs as go
import os
import itertools
import zmq
import sys
import dash,requests,pandas as pd
from dash.dependencies import Output, Input
import plotly.tools as tls
from io import StringIO
import numpy as np
import datetime
import copy
import csv
from collections import deque
from backend import *

X = deque(maxlen=20)
X.append(1)
Y = deque(maxlen=20)
Y.append(1)

mx = 2*10**20
mn = -mx

load file with all RPi available

available_rpi = pd.read_csv(‘available_rpi.conf’, header=None, dtype={0: str}).set_index(0).squeeze().to_dict()
print(“Raspberry Pi’s available:”)
for key, value in available_rpi.items():
print(‘IP:{} name: {}’.format(key, value))
print()

app = dash.Dash(name)
app.layout = html.Div( [
html.H1(children=‘RESENSE’),
html.Div(children=‘’‘RESENSE: Transparent Record and Replay in the Internet of Things (IoT).’‘’),
# html.Div([‘Name : ‘, dcc.Input(id=‘input’,value=‘ACC’,type=‘text’) ]),
# dcc.Markdown(’’’ ‘’'),
html.Label(‘Raspberry Pi’),
dcc.Dropdown(
id = “input”,
options=[{‘label’: v, ‘value’: k} for k, v in available_rpi.items()],
value=‘127.0.0.1’
),
html.Div(id=‘output’),
# Graph for arriving data (static)
dcc.Graph(id=‘data’, animate=True),
dcc.Interval(id=‘graph-update’,interval=2*1000)
])

@app.callback(
dash.dependencies.Output(‘output’, ‘children’),
[dash.dependencies.Input(‘input’, ‘value’)])
def selectBackend(dropdown_value):
print(‘You've selected: “{}”’.format(dropdown_value))
global k;
if dropdown_value != “”:
k = Backend(dropdown_value)
k.startConnection()
k.start()
else:
print(‘You've selected nothing’)

update the graph ‘data’ as a ‘figure’. The interval updated by the event ‘graph-update’

@app.callback(
Output(‘data’, ‘figure’),
[Input(component_id=‘input’, component_property=‘value’)],
events=[Event(‘graph-update’, ‘interval’)])
def update_graph_scatter(value):
print(“… update_graph_scatter function start …”)
print(“input[{}]”.format(value))
print(“address[{}]”.format(k.address))
graphName=‘Sensor "’ + ‘" @’ + k.address
print(“graphName: {}”.format(graphName))

if value == "127.0.0.1":
    X.append(X[-1]+1)
    Y.append(Y[-1]+Y[-1]*random.uniform(-0.1,0.1))

elif value == "192.168.1.106":
    qst = "["
    for i, qid in enumerate(k.queries):
        qst += str(qid) + ("," if i != len(k.queries) -1 else "]")
    print("queries type[{}] qst: {}".format(type(k.queries), qst))
    print("k.X: {}".format(k.X))
    for i in k.X:
        print("k.X type[{}] [{}]: {}".format(type(k.X), i, k.X[i]))
    print("k.Y: {}".format(k.Y))
    for i in k.Y:
        print("k.Y type[{}] [{}]: {}".format(type(k.Y), i, k.Y[i]))
    print("k.Z: {}".format(k.Z))
    for i in k.Z:
        print("k.Z type[{}] [{}]: {}".format(type(k.Z), i, k.Z[i]))

    X.append(X[-1]+1)
    Y.append(Y[-1]+1)
    # Y.append(Y[-1]+Y[-1]*random.uniform(-0.1,0.1))
else:
    print("update_graph_scatter not implemented for input [{}]".format(value))



print(".............. update_graph_scatter end ..............")
# return {'data': [data],
return {'data': [plotly.graph_objs.Scatter(
            x=list(X),
            y=list(Y),
            name=graphName,
            mode= 'lines+markers')],
        'layout' : go.Layout(
            title="SENSE - Sensor readings queries",
            showlegend=True,
            legend=go.layout.Legend(x=0,y=1.0),
            xaxis=dict(range=[min(X),max(X)]),
            yaxis=dict(range=[min(Y),max(Y)]),)}

if name == ‘main’:
selectBackend(“127.0.0.1”)
app.run_server(debug=True)
# app.run_server(
# set to False, otherwise the program launches multiple times (even in the absence of changes and relaunches if changes are made)
# debug=False, port=int(os.getenv(“PORT”, 4444)))

I copy the example from Dash-Plotly multiple inputs (Part 2. Basic Callbacks | Dash for Python Documentation | Plotly) and I changed it to be updated on intervals of 2 seconds. The graph is being updated but the title on the X and Y axis are not. The original example updates the X and Y titles on the graph. I am using python 3. I realized that this is happening only because I am using dcc.Graph(id='indicator-graphic', animate=True),. If I use dcc.Graph(id='indicator-graphic'), the xaxis and yaxis are updated but the graph itself no. Here is the code:

import dash
from dash.dependencies import Output, Input, Event
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go

external_stylesheets = [‘https://codepen.io/chriddyp/pen/bWLwgP.css’]

app = dash.Dash(name, external_stylesheets=external_stylesheets)

df = pd.read_csv(
chriddyp’s gists · GitHub
‘cb5392c35661370d95f300086accea51/raw/’
‘8e0768211f6b747c0db42a9ce9a0937dafcbd8b2/’
‘indicators.csv’)

available_indicators = df[‘Indicator Name’].unique()

load file with all RPi available

available_rpi = pd.read_csv(‘available_rpi.conf’, header=None, dtype={0: str}).set_index(0).squeeze().to_dict()
print(“Raspberry Pi’s available:”)
for key, value in available_rpi.items():
print(‘IP:{} name: {}’.format(key, value))
print()

app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id=‘xaxis-column’,
options=[{‘label’: i, ‘value’: i} for i in available_indicators],
value=‘Fertility rate, total (births per woman)’
),
dcc.RadioItems(
id=‘xaxis-type’,
options=[{‘label’: i, ‘value’: i} for i in [‘Linear’, ‘Log’]],
value=‘Linear’,
labelStyle={‘display’: ‘inline-block’}
)
],
style={‘width’: ‘30%’, ‘display’: ‘inline-block’}),

    html.Div([
        dcc.Dropdown(
            id='yaxis-column',
            options=[{'label': i, 'value': i} for i in available_indicators],
            value='Life expectancy at birth, total (years)'
        ),
        dcc.RadioItems(
            id='yaxis-type',
            options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
            value='Linear',
            labelStyle={'display': 'inline-block'}
        )
    ],style={'width': '30%', 'float': 'right', 'display': 'inline-block'})
]),

dcc.Graph(id='indicator-graphic', animate=True),
dcc.Interval(id='graph-update',interval=2*1000),

dcc.Slider(
    id='year--slider',
    min=df['Year'].min(),
    max=df['Year'].max(),
    value=df['Year'].max(),
    marks={str(year): str(year) for year in df['Year'].unique()}
)

])

@app.callback(
dash.dependencies.Output(‘indicator-graphic’, ‘figure’),
[dash.dependencies.Input(‘xaxis-column’, ‘value’),
dash.dependencies.Input(‘yaxis-column’, ‘value’),
dash.dependencies.Input(‘xaxis-type’, ‘value’),
dash.dependencies.Input(‘yaxis-type’, ‘value’),
dash.dependencies.Input(‘year–slider’, ‘value’)],
events=[Event(‘graph-update’, ‘interval’)])
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df[‘Year’] == year_value]

return {
    'data': [go.Scatter(
        x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
        y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
        text=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],
        mode='markers',
        marker={
            'size': 15,
            'opacity': 0.5,
            'line': {'width': 0.5, 'color': 'white'}
        }
    )],
    'layout': go.Layout(
        xaxis={
            'title': xaxis_column_name,
            'type': 'linear' if xaxis_type == 'Linear' else 'log'
        },
        yaxis={
            'title': yaxis_column_name,
            'type': 'linear' if yaxis_type == 'Linear' else 'log'
        },
        margin={'l': 40, 'b': 40, 't': 10, 'r': 0},
        hovermode='closest'
    )
}

if name == ‘main’:
app.run_server(debug=True)

Yeah, lots of issues with animate=True. We will be deprecating it in favor of 📣 Exploring a "Transitions" API for dcc.Graph

1 Like

thanks. I will check this other way to implement it.

I have the same issue. My workaround is to just put a html.H3 component above the graph for the title. Lol