Starting with the finance tutorial https://dash-gallery.plotly.host/dash-stock-tickers-demo-app/ I was able to create a proof of concept that provided an example of
- Dynamic Plots
- Linked Zoom on the x axis.
I hope that this example can serve others if they are looking for a Linked Zoom example with dynamic plots. Unfortunately there is a bit of a bug when you zoom on the first graph - so it is best to avoid using the first plot for zooming.
The dynamic callbacks created quite a bit of complexity. I am looking forward when this can be done on the browser side and have been watching https://github.com/plotly/plotly.js/pull/3506 which should take care of it.
Next I would like to implement the ability to move and resize figures as mentioned in Figure Resizing and Moving Options, but I do not know where to start for the time being.
Anyhow, thanks for the great documentation, and I hope this example helps get someone started, albeit knowing that it is not perfect.
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import colorlover as cl
import datetime as dt
import pandas as pd
import numpy as np
import random
import requests
app = dash.Dash(
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
)
server = app.server
colorscale = cl.scales['9']['qual']['Paired']
######
# Generate some random time series data
######
word_site = "http://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain"
response = requests.get(word_site)
WORDS = response.content.splitlines()
WORDS = [x.decode('utf-8') for x in WORDS]
random.shuffle(WORDS)
n=3600 # Points
N=100 # Channels
data = np.random.randn(n,N)
df = pd.DataFrame(np.random.randn(n, N), columns=WORDS[0:N])
app.layout = html.Div([
html.Div(id='hidden-div', style={'display':'none'}),
html.Div([
html.H2('Time History Plotter',
style={'display': 'inline',
'float': 'left',
'font-size': '2.65em',
'margin-left': '7px',
'font-weight': 'bolder',
'font-family': 'Product Sans',
'color': "rgba(117, 117, 117, 0.95)",
'margin-top': '20px',
'margin-bottom': '0'
}),
html.Img(src="https://s3-us-west-1.amazonaws.com/plotly-tutorials/logo/new-branding/dash-logo-by-plotly-stripe.png",
style={
'height': '100px',
'float': 'right'
},
),
]),
dcc.Dropdown(
id='Signals',
options=[{'label': s, 'value': str(s)}
for s in df],
value=[WORDS[0]],
multi=True
),
html.Div(id='container'),
html.Div(dcc.Graph(id='empty', figure={'data': []}), style={'display': 'none'}),
])
app.config['suppress_callback_exceptions']=True
# Dynamically generate all of the callbacks
for i in range(N):
@app.callback(Output('graph_{}'.format(i), 'children'), [
Input('Signals', 'value'),
Input('igraph_{}'.format(i), 'relayoutData'),
])
def graph_update(Sigs,relayoutData):
if relayoutData is None:
return
elif 'xaxis.range[0]' in relayoutData:
XR0=relayoutData['xaxis.range[0]']
XR1=relayoutData['xaxis.range[1]']
return replot(Sigs,[XR0,XR1])
elif 'xaxis.autorange' in relayoutData:
return replot(Sigs,'autoX')
else:
return
def replot(Sigs,X):
graphs = []
for i, Sig in enumerate(Sigs):
dff = df[Sig]
time = pd.date_range('2016-07-01', periods=len(dff), freq='S')
trace = [{
'x': time, 'y': dff,
'type': 'scatter', 'mode': 'lines',
'line': {'width': 1, 'color': colorscale[(i*2) % len(colorscale)]},
#'hoverinfo': 'none',
#'legendgroup': Sig,
'showlegend': True,
'name': '{}'.format(Sig)
}]
graphs.append(html.Div(
children=[
dcc.Graph(
id='igraph_{}'.format(i),
figure={
'data': trace,
'layout': {
'legend': {'x': 0},
'margin': {'l': 40, 'r': 20, 't': 20, 'b': 40},
'xaxis': {
'title': 'Time [s]',
'autorange': True if X == 'autoX' else False,
'range': False if X == 'autoX' else X
},
'yaxis': {
'title': 'Time [s]'
},
}
}, className="four columns",
),
html.Div(id="graph_{}".format(i)),
]))
return html.Div(graphs)
# Requried to ADD plots
@app.callback(Output('container', 'children'), [Input('Signals', 'value')])
def display_graphs(Sigs):
return replot(Sigs,'autoX')
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0')