Hello all,
I’m trying to set up a plot that displays an image, and the contents of this image should be updated fairly often (some 10 frames per second or so). At the moment I have this minimum working example, which uses only serverside callbacks:
from dash import Dash, dcc, html
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
app = Dash(__name__)
figsize = 100
buffersize = 5
buffer = np.random.random(size=(buffersize, figsize, figsize)) # some random image, quite literally
fig = px.imshow(buffer[0])
colors = {
'background': '#111111',
'text': '#7FDBFF'
}
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
html.H1(
children='Example dashboard',
style={
'textAlign': 'center',
'color': colors['text']
}
),
html.Div(
id='div-test',
children='subtitle, i guess',
style={
'textAlign': 'center',
'color': colors['text']
}
),
# trigger data updates
dcc.Interval(
id='server-interval',
interval=1000,
n_intervals=0
),
# trigger plot updates
dcc.Interval(
id='client-interval',
interval=200,
n_intervals=0
),
# we'll store the plot data here from the server side
dcc.Store(
id='buffer',
data=buffer
),
# our plot
dcc.Graph(
id='example-graph',
figure=fig
)
])
# now we update the buffer from the server side at a modestly slow speed
@app.callback(Output('buffer', 'data'),
Input('server-interval', 'n_intervals'))
def update_data(n_intervals):
data = np.random.random(size=(buffersize, figsize, figsize))
return data
# and finally we use the buffer to update the plot at a higher frequency.
# this is what I'd like to turn into a clientside callback. it works for now, but
#only up to a certain interval size.
@app.callback(Output('example-graph', 'figure'),
Input('client-interval', 'n_intervals'),
State('buffer', 'data'),
State('example-graph', 'figure'))
def update_figure(n_intervals, data, figure):
figure['data'][0]['z'] = data[n_intervals]
return figure
# this is what I've tried, but it doesn't work.
'''
app.clientside_callback(
"""
function(n_intervals, figure, data){
if (figure === undefined){
return window.dash_clientside.no_update
}
console.log('hello');
figure['data'][0]['z'] = data[n_intervals];
return figure;
}
""",
Output('example-graph', 'figure'),
Input('client-interval', 'n_intervals'),
State('example-graph', 'figure'),
State('buffer', 'data')
)
'''
At the end of the code block, I wrote what I’ve tried so far. However, writing the clientside callback as shown there results in a “cannot read properties of undefined (reading ‘figure’)” error. What would be the right way of doing this? If the approach is wrong altogether, feel free to give suggestions on how to approach the problem instead. For extra context, the function that generated data at random will in the future be replaced by something else that obtains actual data, either through a socket or grpc or something of the sort.
Any comments are welcome. Thanks!