extendData and update annotations for a live streaming multi channel data

Hi, I need to monitor a live streaming data from +20 sensors and update the graph and show last measured values on corresponding subplot. My simplified code is below. When I tried one callback function I could not draw data, but update last values. When you slide it two callback functions, it behaves weirdly in terms of graph updating. Could you have a look ? :innocent: :worried:

from dash import Dash, dcc, html, Input, Output, State, dash_table
from plotly.subplots import make_subplots
import numpy as np

app = Dash(__name__)

grid_row = 2
grid_col = 2
grid_num = grid_row * grid_col
multip_x, multip_y = 1/grid_col, 1/grid_row
size = 30
x_data = [0,]
data = [[], ]*grid_num

fig = make_subplots(rows=grid_row, cols=grid_col)

for ids in range(grid_num):
    data[ids] = [(ids*10) + abs(np.random.normal()), ]
    fig.add_scatter(x=x_data, y=data[ids], col=ids % grid_col + 1, row=ids // grid_col + 1)

app.layout = html.Div([
    dcc.Interval(id="interval_comp", interval=1000, n_intervals=1),
    dcc.Graph(id="graph", figure=fig),
    ])


@app.callback(Output("graph", "extendData"),
              Output('graph', 'figure'),
              Input("interval_comp", "n_intervals"), )
def update(n_intervals):
    global x_data, data
    if len(x_data) < size:
        x_data.append(x_data[-1] + 1)
        data_size = len(x_data)
        for ids in range(grid_num):
            data[ids] = np.append(data[ids], (ids*10) + abs(np.random.normal()))
    else:
        x_data.append(x_data[-1] + 1)
        x_data = x_data[-size:]
        data_size = size
        for ids in range(grid_num):
            data[ids] = np.append(data[ids], (ids*10) + abs(np.random.normal()))
            data[ids] = data[ids][-size:]

    fig_data = [{"x": [[], ], "y": [[], ] },  [*range(grid_num)],  data_size]
    fig_data[0]['x'] = [x_data, ] * grid_num
    fig_data[0]['y'] = data

    last_cap = []
    for i in range(grid_num):
        last_value = data[i][-1]
        last_cap.append({
            'text': str(f'data_{i}: {last_value:.2f}'),
            'xref': "paper",
            'yref': "paper",
            'x': 0 + (multip_x*(i % grid_col))*1.1,
            'y': 1.06 - (multip_y*(i // grid_col))*1.15,
            'xanchor': 'left',
            'yanchor': 'top',
            'showarrow': False,
            'font': {'color': 'red', 'size': 18, 'family': 'Arial'},
        })

    fig.update_layout({'annotations': last_cap})
    return fig_data, fig


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

I figure out solution with update fig with new dataset and later annotations then return just fig to graph :ok_hand: :ok::

@app.callback(Output("graph", "figure"),
              Input("interval_comp", "n_intervals"))
def update(n_intervals):
................... "this section as above"

    for i in range(grid_num):
        fig.data[i]['x'] = x_data
        fig.data[i]['y'] = data[I]

 ...................... "this section as above"
    fig.update_layout({'annotations': last_cap})
    return fig

1 Like

Glad you were able to figure it out, and thank you for posting your solution!

1 Like