This was previously asked by someone else here: How to Get Current Frame in an Animated Plot, but wasn’t answered, and I wanted to make another attempt for this year.
Basically, I have a plotly animation which uses a slider and pause/play buttons to go through a dataset. I want to extract the number of the current frame (i.e., the current index in the ‘steps’/‘frames’ lists which the slider is on) in a Dash callback, so that I can update a table based on the main graph.
For example, in this situation:
I would like to be able to get ‘6’, the current step number, from the figure.
Here is some example code with a toy dataset, but the same basic UI and structure (from above):
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Dataset
x = [10, 1, 3, 4, 5, 6, 7, 8, 9, 10]
y = [10, 1, 3, 4, 5, 6, 7, 8, 9, 10]
df = pd.DataFrame(list(zip(x, y)), columns = ['x', 'y'])
# Adding a trace
trace = go.Scatter(x=df.x[0:2], y=df.y[0:2],
name='Location',
mode='markers',
marker=dict(color="white",
size=10,
line=dict(
color='DarkSlateGrey',
width=2)
)
)
# Adding frames
frames = [dict(name=k,data= [dict(type='scatter',
x=df.x[k:k + 1],
y=df.y[k:k + 1],
),
],
traces = [0],
) for k in range(len(df) - 1)]
layout = go.Layout(width=650,
height=650,
showlegend=False,
hovermode='closest',
updatemenus=[dict(type='buttons', showactive=False,
y=-.1,
x=0,
xanchor='left',
yanchor='top',
pad=dict(t=0, r=10),
buttons=[dict(label='Play',
method='animate',
args=[None,
dict(frame=dict(duration=200, redraw=False),
transition=dict(duration=0),
fromcurrent=True,
mode='immediate'
)
]),
dict(label='Pause', # https://github.com/plotly/plotly.js/issues/1221 / https://plotly.com/python/animations/#adding-control-buttons-to-animations
method='animate',
args=[[None],
dict(frame=dict(duration=0, redraw=False),
transition=dict(duration=0),
fromcurrent=True,
mode='immediate' )
])
])
])
fig = go.Figure(data=[trace], frames=frames, layout=layout)
# Adding a slider
sliders = [{
'yanchor': 'top',
'xanchor': 'left',
'active': 1,
'currentvalue': {'font': {'size': 16}, 'prefix': 'Steps: ', 'visible': True, 'xanchor': 'right'},
'transition': {'duration': 200, 'easing': 'linear'},
'pad': {'b': 10, 't': 50},
'len': 0.9, 'x': 0.15, 'y': 0,
'steps': [{'args': [[k], {'frame': {'duration': 200, 'easing': 'linear', 'redraw': False},
'transition': {'duration': 0, 'easing': 'linear'}}],
'label': k, 'method': 'animate'} for k in range(len(df) - 1)
]}]
fig['layout'].update(sliders=sliders)
app.layout = html.Div(children=[
html.Div([
dcc.Graph(
id= 'my-graph',
figure=fig
),
html.Br(),
html.Div(id='my-output'),
])
])
@app.callback(
Output(component_id='my-output', component_property='children'),
Input(component_id='my-graph', component_property='figure')
)
# How to get the current frame index here?
def update_output_div(figure):
return 'Output: {}'.format(figure['layout']['sliders'][0])
if __name__ == '__main__':
app.run_server(debug=True)
Basically, in that callback, I just want to get the current index of the slider, i.e. the current frame that the animation is on in order to index into the dataframe and display that info in a table. I just want to be able to access the ‘Steps’ that is displaying above the slider, the current value. It clearly exists somewhere, but I can’t find it for the life of me (tried going through the Github source code, but couldn’t locate it).
I would really appreciate any help with this! My dataset is fairly large (20 mb) and doesn’t fit into browser memory, so I haven’t had much luck with a Dash solution using dcc.Slider and dcc.Graph that is still performant.