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

**URL:** <https://community.plotly.com/t/allow-users-to-zoom-into-live-graphs-and-maintain-zoom-for-new-data/50261>\
**Category:** Dash Python\
**Created:** [February 21, 2021, 12:21am UTC](https://community.plotly.com/t/allow-users-to-zoom-into-live-graphs-and-maintain-zoom-for-new-data/50261 "2021-02-21T00:21:02Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![dasher007](https://avatars.discourse-cdn.com/v4/letter/d/c57346/32.png) [@dasher007](https://community.plotly.com/u/dasher007)\
**Post date:** [February 21, 2021, 12:21am UTC](https://community.plotly.com/t/allow-users-to-zoom-into-live-graphs-and-maintain-zoom-for-new-data/50261/1 "2021-02-21T00:21:02Z")

</div>

Hi guys,

I am following sentdex’s dash tutorial: [Vehicle Data App Example - Data Visualization GUIs with Dash and Python p.5](https://pythonprogramming.net/vehicle-data-visualization-application-dash-python-tutorial/) . 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](https://community.plotly.com/t/how-to-save-current-zoom-and-position-after-filtering/5310/2)  
Any help is appreciated! 😃

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](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](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)
