Allow users to zoom into live graphs and maintain zoom for new data

Hi guys,

I am following sentdex’s dash tutorial: Vehicle Data App Example - Data Visualization GUIs with Dash and Python p.5 . I want to let the users to be able to zoom into any of the graphs and maintain that zoom for the new data coming in. The purpose is for the users to monitor one or more variables more closely if they wanted to. I looked at State and relayout data but i’m not able to implement it. Using this as reference: How to save current zoom and position after filtering? - #2 by chriddyp
Any help is appreciated! :smiley:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input, State
import time
from collections import deque
import plotly.graph_objs as go
import random

app = dash.Dash(‘vehicle-data’)

max_length = 5000
times = deque(maxlen=max_length)
oil_temps = deque(maxlen=max_length)
intake_temps = deque(maxlen=max_length)
coolant_temps = deque(maxlen=max_length)
rpms = deque(maxlen=max_length)
speeds = deque(maxlen=max_length)
throttle_pos = deque(maxlen=max_length)

data_dict = {“Oil Temperature”:oil_temps,
“Intake Temperature”: intake_temps,
“Coolant Temperature”: coolant_temps,
“RPM”:rpms,
“Speed”:speeds,
“Throttle Position”:throttle_pos}

def update_obd_values(times, oil_temps, intake_temps, coolant_temps, rpms, speeds, throttle_pos):

times.append(time.time())
if len(times) == 1:
    #starting relevant values
    oil_temps.append(random.randrange(180,230))
    intake_temps.append(random.randrange(95,115))
    coolant_temps.append(random.randrange(170,220))
    rpms.append(random.randrange(1000,9500))
    speeds.append(random.randrange(30,140))
    throttle_pos.append(random.randrange(10,90))
else:
    for data_of_interest in [oil_temps, intake_temps, coolant_temps, rpms, speeds, throttle_pos]:
        data_of_interest.append(data_of_interest[-1]+data_of_interest[-1]*random.uniform(-0.0001,0.0001))

return times, oil_temps, intake_temps, coolant_temps, rpms, speeds, throttle_pos

times, oil_temps, intake_temps, coolant_temps, rpms, speeds, throttle_pos = update_obd_values(times, oil_temps, intake_temps, coolant_temps, rpms, speeds, throttle_pos)

app.layout = html.Div([
html.Div([
html.H2(‘Vehicle Data’,
style={‘float’: ‘left’,
}),
]),
dcc.Dropdown(id=‘vehicle-data-name’,
options=[{‘label’: s, ‘value’: s}
for s in data_dict.keys()],
value=[‘Coolant Temperature’,‘Oil Temperature’,‘Intake Temperature’],
multi=True
),
dcc.RadioItems(id=‘lock-zoom’,
options=[{‘label’: i, ‘value’: i} for i in [‘Lock View’, ‘Refresh View’]],
value=‘Lock View’
),
html.Div(children=html.Div(id=‘graphs’), className=‘row’),
dcc.Interval(
id=‘graph-update’,
interval=1000,
n_intervals=0),
], className=“container”,style={‘width’:‘98%’,‘margin-left’:10,‘margin-right’:10,‘max-width’:50000})

@app.callback(
Output(‘graphs’,‘children’),
[Input(‘vehicle-data-name’, ‘value’),
Input(‘lock-zoom’, ‘value’)],
[Input(‘graph-update’, ‘n_intervals’)],
[State(‘graphs’, ‘relayoutData’)]
)
def update_graph(data_names,lock_zoom, relayout_data, intervals):
graphs =
update_obd_values(times, oil_temps, intake_temps, coolant_temps, rpms, speeds, throttle_pos)
if len(data_names)>2:
class_choice = ‘col s12 m6 l4’
elif len(data_names) == 2:
class_choice = ‘col s12 m6 l6’
else:
class_choice = ‘col s12’

for data_name in data_names:

    data = go.Scatter(
        x=list(times),
        y=list(data_dict[data_name]),
        name='Scatter',
        fill="tozeroy",
        fillcolor="#6897bb"
        )

    graphs.append(html.Div(dcc.Graph(
        id=data_name,
        animate=False,
        figure={'data': [data],'layout' : go.Layout(xaxis=dict(range=[min(times),max(times)]),
                                                    yaxis=dict(range=[min(data_dict[data_name]),max(data_dict[data_name])]),
                                                    margin={'l':50,'r':1,'t':45,'b':1},
                                                    title='{}'.format(data_name))}
        ), className=class_choice))
    
    print(relayout_data)
    if relayout_data and lock_zoom == 'Lock View':
        if 'xaxis.range[0]' in relayout_data:
            graphs['layout']['xaxis']['range'] = [
                relayout_data['xaxis.range[0]'],
                relayout_data['xaxis.range[1]']
                ]
            if 'yaxis.range[0]' in relayout_data:
                graphs['layout']['yaxis']['range'] = [
                    relayout_data['yaxis.range[0]'],
                    relayout_data['yaxis.range[1]']
                    ]

return graphs

external_css = [“https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css”]
for css in external_css:
app.css.append_css({“external_url”: css})

external_js = [‘https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js’]
for js in external_css:
app.scripts.append_script({‘external_url’: js})

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