Having Trouble With Live Updating and Labeling Legend

I’m pulling a json array from a server and I’m trying to feed it into a live graph.
The array takes the format of: [{“t”:“2020-01-05T22:27:53.000Z”,“v”:0.022,“ch”:1},{“t”:“2020-01-05T22:28:36.000Z”,“v”:0.022,“ch”:2}, etc]

I’m having two problems though, first the user can use a set of rangeselector buttons to switch from looking at a day from the last post, a month, or a year, but when the callback updates the graph it resets to showing all the data and not what the user chose.

The second problem is that line_group is set to be “ch” but this just lists them in the legend as 1, 2, 3, and 4 I have tried to change them through setting labels={“ch”:“Sensors”, “1”:“Sensor Name”} but that will change the Legend title and not the names of the lines.

Here’s the code from the callback:

@app.callback(Output('graph', 'figure'),
            [Input('interval-component', 'n_intervals')])
def update_graph(n):

    with open("file.json", "r") as read_file:
        data = json.load(read_file)

    return px.line(data, x="t", y="v", line_group="ch", color="ch", labels= "ch":"Sensors"}).update(layout=nlayout)

And here’s how I have the layout setup:

nlayout = { "title": "Sensor Data",
                "xaxis":{
                    "title":"Time",
                    "type" : "date",
                    "autorange":True,
                    "rangeselector":{"buttons":[
                        {
                            "count": .01,
                            "label": "day",
                            "step" : "day",
                            "stepmode": "backward"
                        },
                        {
                            "count": 1,
                            "label": "1m",
                            "step": "month",
                            "stepmode" : "backward",
                        },
                        {
                            "count": 6,
                            "label": "6m",
                            "step" : "month",
                            "stepmode": "backward"
                        },
                        {
                            "count": 1,
                            "label": "year",
                            "step" : "year",
                            "stepmode": "todate"
                        },
                        {
                            "step":"all",
                            "label":"all"
                        },
                        
                    ]}
                    },
               "yaxis":{
                   "title":"Volts",
                   "type":"linear"
                },
                    "transition":{'duration': 300, 'easing': 'cubic-in-out'},
}

Hi @colbyschexnayder welcome to the forum! Could you please share a standalone example here? Regarding the sensor labels, you could just add a column to the dataframe using a mapping as in the code below

import plotly.express as px
data = [{"t":"2020-01-05T22:27:53.000Z","v":0.022,"ch":1}, 
        {"t":"2020-01-05T22:29:53.000Z","v":0.025,"ch":1},
        {"t":"2020-01-05T22:27:53.000Z","v":0.022,"ch":2},
        {"t":"2020-01-05T22:28:36.000Z","v":0.027,"ch":2}]
import pandas as pd
df = pd.DataFrame.from_dict(data)
df['sensor_labels'] = ['Sensor 1', 'Sensor 1', 'Sensor 2', 'Sensor 2']
fig = px.line(df, x="t", y="v", line_group="ch", color="sensor_labels")
fig.show()

As for the updates, I suggest that you print the values of the filtered data within the callback to be sure that you made the correct selection. If you need more help, please post a standalone example using dummy data (as I did above, but with a whole minimal Dash app) so that we can execute the code.

Hi @Emmanuelle thanks for the help, I tried using pandas to add like you said but I got ValueError: Length of values does not match length of index.

I’m not sure what you mean by printing the values of the filtered data as all the data updates appropriately, it’s just the formatting that’s giving me a problem.

Here’s the stand alone dash app I have so far:


import json, urllib.request

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

import plotly.express as px

data = [{"t":"2020-01-05T22:27:53.000Z","v":0.022,"ch":1},
        {"t":"2020-01-05T22:28:36.000Z","v":0.022,"ch":1},
        {"t":"2020-01-05T22:29:36.000Z","v":0.023,"ch":1},
        {"t":"2020-01-05T22:30:36.000Z","v":0.022,"ch":1},
        {"t":"2020-01-05T22:31:36.000Z","v":0.022,"ch":1},
        {"t":"2020-01-05T22:32:37.000Z","v":0.021,"ch":1},
        {"t":"2020-01-05T22:27:53.000Z","v":0.081,"ch":2},
        {"t":"2020-01-05T22:28:36.000Z","v":0.081,"ch":2},
        {"t":"2020-01-05T22:29:36.000Z","v":0.081,"ch":2},
        {"t":"2020-01-05T22:30:36.000Z","v":0.081,"ch":2},
        {"t":"2020-01-05T22:31:36.000Z","v":0.081,"ch":2},
        {"t":"2020-01-05T22:32:37.000Z","v":0.08,"ch":2}]



external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

nlayout = { "title": "Sensor Data",
                "xaxis":{
                    "title":"Time",
                    "type" : "date",
                    "autorange":True,
                    "rangeselector":{"buttons":[
                        {
                            "count": .01,
                            "label": "day",
                            "step" : "day",
                            "stepmode": "backward"
                        },
                        {
                            "count": 1,
                            "label": "1m",
                            "step": "month",
                            "stepmode" : "backward",
                        },
                        {
                            "count": 6,
                            "label": "6m",
                            "step" : "month",
                            "stepmode": "backward"
                        },
                        {
                            "count": 1,
                            "label": "year",
                            "step" : "year",
                            "stepmode": "todate"
                        },
                        {
                            "step":"all",
                            "label":"all"
                        },
                        
                    ]}
                    },
               "yaxis":{
                   "title":"Volts",
                   "type":"linear"
                },
                    "transition":{'duration': 300, 'easing': 'cubic-in-out'},
}

app.layout = html.Div(
    html.Div([
    dcc.Graph(
        id = "graph", 
    ),
    dcc.Interval(
        id = 'interval-component',
        interval=10000,
        n_intervals = 0
    )
    ]),
    
)

@app.callback(Output('graph', 'figure'),
            [Input('interval-component', 'n_intervals')])
def update_graph(n):

    return px.line(data, x="t", y="v", line_group="ch", color="ch", labels={"ch":"Sensors"}).update(layout=nlayout)

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


Slight update, I was able to change the labels using pandas after all instead of

df = pd.DataFrame.from_dict(data)
df['sensor_labels'] = ['Sensor 1', 'Sensor 1', 'Sensor 2', 'Sensor 2']

I used this

df = pd.DataFrame.from_dict(data)
df['ch'] = df['ch'].map({1:"Sensor 1", 2:"Sensor 2"})