'Rebase data to relative performance with rangeslider in Python Dash Graph update_layout
I am trying to use and adjust the rangeslider property in the update_layout of a Python Dash core component Graph. I like to rebase data to a relative performance chart whenever the rangeslider is changed such that the performance is always measured to the first element in the selected range. I was able to accomplish this by using a RangeSlider as an input for the Graph component. However, I was wondering if this is also possible only using the rangeslider property in the Graph component directly without the callback.
I am looking for something similar to this solution in R: https://mgei.github.io/post/rangeslider-plotly/.
# Libraries
import pandas as pd
import numpy as np
import datetime
from dash import Dash, html
import dash_core_components as dcc
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
import plotly.express as px
# Data
T = 100
steps = 10
base = datetime.datetime.today()
date_list = reversed([base - datetime.timedelta(days=x) for x in range(T)])
test_data = pd.DataFrame(np.random.randn(T)/100, index=date_list, columns=['Col1'])
test_data.iloc[0,:] = 0
# App
app = Dash(__name__)
app.layout = html.Div([html.H3('RangeSlider'),
dcc.RangeSlider(0, T, steps, count=1,
marks={i:test_data.index[i].strftime('%d.%m.%y') for i in range(0,T,steps)},
id='range_slider'),
html.Br(),
html.H3('Plot'),
dcc.Graph(figure={'data':[]}, id='plot_data'),
],
style={'width': '50%', 'display': 'inline-block', 'padding-left':'25%', 'padding-right':'25%'}
)
# Callbacks
@app.callback(Output('plot_data', 'figure'),
Input('range_slider', 'value'))
def plot_data(value):
if value is None:
raise PreventUpdate
else:
tmp_data = (1+test_data.iloc[value[0]:value[1],:]).cumprod() * 100
tmp_data.iloc[0,:] = 100
tmp_data = tmp_data.sort_index()
fig = px.line(tmp_data, y=['Col1'])
fig.update_layout(xaxis=dict(rangeslider=dict(visible=True), type='date'))
fig.update_layout(showlegend=True)
return fig
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
Solution 1:[1]
The reason why it did not work is probably due to the fact that the time series data of the test data does not match the time series data of the slider.
My fixes included changing the date in datetime.date.today() to a date, changing the date format of the slider to a hyphenated format (unrelated to the failure), expanding the slider to 75% of the browser width because it was too short, and adjusting the margins.
# Libraries
import pandas as pd
import numpy as np
import datetime
from dash import Dash, html, dcc
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
from jupyter_dash import JupyterDash
import plotly.express as px
# Data
T = 100
steps = 10
base = datetime.date.today()
date_list = reversed([base - datetime.timedelta(days=x) for x in range(T)])
test_data = pd.DataFrame(np.random.randn(T)/100, index=date_list, columns=['Col1'])
test_data.iloc[0,:] = 0
#fig = px.line(test_data, y=['Col1'])
# App
#app = Dash(__name__)
app = JupyterDash(__name__)
app.layout = html.Div([html.H3('RangeSlider'),
dcc.RangeSlider(0, T, steps, count=1,
marks={i:test_data.index[i].strftime('%d-%m-%y') for i in range(0,T,steps)},
id='range_slider'),
html.Br(),
html.H3('Plot'),
dcc.Graph(figure={'data':[]}, id='plot_data'),
],
style={'width': '75%', 'display': 'inline-block', 'padding-left':'10%', 'padding-right':'15%'}
)
# Callbacks
@app.callback(Output('plot_data', 'figure'),
Input('range_slider', 'value'))
def plot_data(value):
if value is None:
raise PreventUpdate
else:
tmp_data = (1+test_data.iloc[value[0]:value[1],:]).cumprod() * 100
tmp_data.iloc[0,:] = 100
tmp_data = tmp_data.sort_index()
print(tmp_data)
fig = px.line(tmp_data, y=['Col1'])
fig.update_layout(xaxis=dict(rangeslider=dict(visible=True), type='date'))
fig.update_layout(showlegend=True)
return fig
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False, mode='inline')
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | r-beginners |

