Chrollo
September 5, 2022, 1:54am
1
I have this existing code that can update and extend the data in a scatter graph, looks like this.
I want to relayout the xaxis of the graph with range of maximum of 9 data so that the lines will not be crowded, like this.
app.layout = html.Div([
html.Div(style={'display': 'flex'}, children=[
dcc.Graph(
id='graph-ph',
figure={
'data': [
{'x': [],
'y': [0, random.random()],
'mode':'lines+markers',
}],
'layout': {
'title': 'pH (pH)'
}},
),
]),
dcc.Interval(
id='interval-graph-update',
interval=1000,
n_intervals=0),
])
@app.callback(Output('graph-ph', 'extendData'),
[Input('interval-graph-update', 'n_intervals')],
[State('graph-ph', 'figure'),
])
def update_extend_traces_traceselect(n_intervals, existing):
trace_selection = 0
x_new = datetime.datetime.now()
y_new = random.random()
return dict(x=[[x_new]], y=[[y_new]]), [trace_selection]
celia
September 5, 2022, 1:19pm
2
Hi @Chrollo !
You just have to include in the output of your callback the maximum number of points that you want to see displayed on the plot at the same moment (9 in this example):
return dict(x=[[x_new]], y=[[y_new]]), [trace_selection], 9
I hope this helps!
Chrollo
September 5, 2022, 1:34pm
3
It’s not working ma’am @celia
x_new = datetime.datetime.now()
y_new = random.random()
return dict(x=[[x_new]], y=[[y_new]]), 9
celia
September 5, 2022, 1:37pm
4
Did you try it without removing [trace_selection]
?
Chrollo
September 5, 2022, 1:46pm
6
@celia it’s working right now. It’s display only the recent 9 data but the previous data is being deleted.
celia
September 5, 2022, 3:40pm
7
Then I think the best option is to change the approach to update the data and re-render the whole figure. Try this:
from dash import Dash, dash_table, dcc, html, callback, Input, Output, State
from dash.dependencies import Input, Output
import pandas as pd
import random
import datetime
import plotly.graph_objects as go
app = Dash(__name__)
app.layout = html.Div([
html.Div(style={'display': 'flex'}, children=[
dcc.Graph(
id='graph-ph',
figure={
'data': [
{'x': [],
'y': [0, random.random()],
'mode':'lines+markers',
}],
'layout': {
'title': 'pH (pH)'
}},
),
]),
dcc.Interval(
id='interval-graph-update',
interval=1000,
n_intervals=0),
])
@callback(
Output('graph-ph', 'figure'),
Input('interval-graph-update', 'n_intervals'),
State('graph-ph', 'figure')
)
def update_extend_traces_traceselect(n_intervals, fig_raw):
x_new = datetime.datetime.now()
y_new = random.random()
fig_raw['data'][0]['x'] = fig_raw['data'][0]['x'] + [x_new]
fig_raw['data'][0]['y'] = fig_raw['data'][0]['y'] + [y_new]
fig = go.Figure(fig_raw)
if len(fig_raw['data'][0]['x']) > 9 :
fig.update_xaxes(range=[fig_raw['data'][0]['x'][-9], x_new+datetime.timedelta(seconds=1)], autorange=False)
return go.Figure(fig)
if __name__ == '__main__':
app.run_server(debug=True)
1 Like
Chrollo
September 6, 2022, 12:54am
8
Thank you it worked! I have last question how can I add a range slider? I tried adding fig.update_layout(xaxis={“rangeslider”: {“visible”: True}}) but I’m having an error says ‘Invalid property specified for object of type plotly.graph_objs.layout.xaxis.rangeslider.YAxis: ‘_template’’
celia
September 6, 2022, 2:45pm
9
The problem seems to come from the step where we recreate the figure from in fig = go.Figure(fig_raw)
, if the figure already has a range slider.
@alexcjohnson helped me solve this and already created a bug report : rangeslider template bug · Issue #6310 · plotly/plotly.js · GitHub
The workaround is to add this bit of code:
# add these lines before fig = go.Figure(fig_raw)
if 'rangeslider' in fig_raw['layout']['xaxis']:
del fig_raw['layout']['xaxis']['rangeslider']['yaxis']