Cumulative Lines Animation in Python

Hi all,

Does anyone know how to implement the Cumulative Lines Animation from the R library in Python?

I have tried to follow the Python Intro to Animations offline example, but the slider doesn’t seem to be responding to the play button, and moving the slider does not change the frame of the plot.

Also, does anyone know a solution to plotting missing data in such a graph? Some of my traces are shorter than others due to missing time points.

Any help would be greatly appreciated.
Thank you,
Will

@will.zhao09

Here is an example to see how you can imitate the R animation, above.

import numpy as np
import pandas as pd
import plotly.graph_objects as go  #plotly 4.0.0rc1


df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
low = df['AAPL.Low'].tolist()
high = np.array(df['AAPL.High'])+20 # artificially added 20 to get the second graph above the first one

trace1 = go.Scatter(x=df.Date[:2],
                    y=low[:2],
                    mode='lines',
                    line=dict(width=1.5))

trace2 = go.Scatter(x = df.Date[:2],
                    y = high[:2],
                    mode='lines',
                    line=dict(width=1.5))

frames = [dict(data= [dict(type='scatter',
                           x=df.Date[:k+1],
                           y=low[:k+1]),
                      dict(type='scatter',
                           x=df.Date[:k+1],
                           y=high[:k+1])],
               traces= [0, 1],  #this means that  frames[k]['data'][0]  updates trace1, and   frames[k]['data'][1], trace2 
              )for k  in  range(1, len(low)-1)] 

layout = go.Layout(width=650,
                   height=400,
                   showlegend=False,
                   hovermode='closest',
                   updatemenus=[dict(type='buttons', showactive=False,
                                y=1.05,
                                x=1.15,
                                xanchor='right',
                                yanchor='top',
                                pad=dict(t=0, r=10),
                                buttons=[dict(label='Play',
                                              method='animate',
                                              args=[None, 
                                                    dict(frame=dict(duration=3, 
                                                                    redraw=False),
                                                         transition=dict(duration=0),
                                                         fromcurrent=True,
                                                         mode='immediate')])])])


layout.update(xaxis =dict(range=[df.Date[0], df.Date[len(df)-1]], autorange=False),
              yaxis =dict(range=[min(low)-0.5, high.max()+0.5], autorange=False));
fig = go.Figure(data=[trace1, trace2], frames=frames, layout=layout)
fig.show()

If you are interested in animating only a single line, then remove trace2 and frames[k]['data'][1], i.e. the second data dict from each frame. In this case frames[k][‘traces’]=[0], because each frame updates the first trace (the unique one).

Is there a way to do this in plotly express?

px gets me almost all the way there, I just wish there was a way to specify cumulative=True in px - that would make it a breeze to show growing trend lines, or a animated scatter plot which hows how more points appear.

The current plotly express animation_frame stuff is designed to only show one frame at a time. The way described above works but is so much more verbose than plotly express that I really don’t want to use the old way of plotly anymore, only express!

Also, using frames like with this code, doesn’t this end up repeating the data for each frame essentially? Seems to produce very large outputs.

I just want to declare one data, then each animation image just uses a sliding range of frames to show the plot, e.g frame 10 shows [1:10] and frame 100 shows [1:100]

2 Likes

I don’t think express can cover your need right now. You have to define each frame as @empet mentioned.

What do I need to change to draw 3 lines?