title: Dash Plotly Graph Lines Disappear in Certain Frames of Animation
body: <p>I've got a Python-based Dash graph &quot;animation&quot; (multiple frames, which show different days) whose lines don't show up when the frame changes. I've been using Plotly-Dash for a few years now and I've never run into this problem before, but I have a reproducible example below.</p>
  <p>Here's what <em>all</em> of the frames are <em>supposed</em> to look like (note the red lines on top and purple lines on the bottom):
  <a href="https://i.stack.imgur.com/ddRYh.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ddRYh.png" alt="enter image description here" /></a></p>
  <p>That was the first frame, above. The second frame from the right looks like this, with no red lines above the purple lines. I can assure you there's data there; it's just not showing up! Check for yourself with the output from print(tabulate()).
  <a href="https://i.stack.imgur.com/gl7Bv.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/gl7Bv.png" alt="enter image description here" /></a></p>
  <p>To get set up to answer this question, install the following libraries:</p>
  <pre class="lang-sh prettyprint-override"><code>pip install dash flask plotly pandas colour tabulate
  </code></pre>
  <p>There's no <em>perfect</em> way to share a rather large DataFrame, but sharing text is preferable to providing a download link (thanks @vestland for the tip from his answer <a href="https://stackoverflow.com/questions/63163251/pandas-how-to-easily-share-a-sample-dataframe-using-df-to-dict/63163254?r=SearchResults&amp;s=2%7C50.6607#63163254">here</a>).</p>
  <p>Here's the full code, ready for you to copy and paste, and see the &quot;bug&quot;:</p>
  <pre class="lang-py prettyprint-override"><code>from flask import Flask
  import dash
  import dash_core_components as dcc
  import dash_html_components as html
  import plotly.graph_objects as go
  import pandas as pd
  from colour import Color
  from tabulate import tabulate
  
  
  # Create the &quot;list_of_dicts&quot; for Pandas
  list_of_dicts = [
      {
          &quot;Unnamed: 0&quot;: 1499,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.33,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: -241.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21615,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.33,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: 165.9,
      },
      {
          &quot;Unnamed: 0&quot;: 1687,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.73,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: -239.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21803,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.73,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: 147.76,
      },
      {
          &quot;Unnamed: 0&quot;: 1875,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.13,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: -242.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21991,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.13,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: 128.0,
      },
      {
          &quot;Unnamed: 0&quot;: 2063,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.53,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: -244.0,
      },
      {
          &quot;Unnamed: 0&quot;: 22179,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.53,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: 109.25,
      },
      {
          &quot;Unnamed: 0&quot;: 2251,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.94,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: -243.0,
      },
      {
          &quot;Unnamed: 0&quot;: 22367,
          &quot;timestamp_local&quot;: &quot;2021-01-19 20:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.94,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 20,
          &quot;load&quot;: 92.6206896551724,
      },
      {
          &quot;Unnamed: 0&quot;: 1500,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.33,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: -245.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21616,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.33,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: 183.84615384615384,
      },
      {
          &quot;Unnamed: 0&quot;: 1688,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.73,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: -244.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21804,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.73,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: 163.5,
      },
      {
          &quot;Unnamed: 0&quot;: 1876,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.13,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: -244.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21992,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.13,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: 145.44444444444446,
      },
      {
          &quot;Unnamed: 0&quot;: 2064,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.53,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: -246.0,
      },
      {
          &quot;Unnamed: 0&quot;: 22180,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.53,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: 128.21052631578948,
      },
      {
          &quot;Unnamed: 0&quot;: 2252,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.94,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: -246.0,
      },
      {
          &quot;Unnamed: 0&quot;: 22368,
          &quot;timestamp_local&quot;: &quot;2021-01-19 21:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-19 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.94,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 21,
          &quot;load&quot;: 110.55555555555556,
      },
      {
          &quot;Unnamed: 0&quot;: 1315,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.05,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: -202.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21431,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.05,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: 176.0,
      },
      {
          &quot;Unnamed: 0&quot;: 1503,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.45,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: -204.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21619,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.45,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: 166.0,
      },
      {
          &quot;Unnamed: 0&quot;: 1691,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.85,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: -202.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21807,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 6.85,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: 154.0,
      },
      {
          &quot;Unnamed: 0&quot;: 1879,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.25,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: -202.0,
      },
      {
          &quot;Unnamed: 0&quot;: 21995,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.25,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: 142.0,
      },
      {
          &quot;Unnamed: 0&quot;: 2067,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.66,
          &quot;up_down&quot;: &quot;Downstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: -202.0,
      },
      {
          &quot;Unnamed: 0&quot;: 22183,
          &quot;timestamp_local&quot;: &quot;2021-01-20 16:00:00-07:00&quot;,
          &quot;timestamp_local_day&quot;: &quot;2021-01-20 00:00:00-07:00&quot;,
          &quot;inches&quot;: 7.66,
          &quot;up_down&quot;: &quot;Upstroke&quot;,
          &quot;hour&quot;: 16,
          &quot;load&quot;: 130.0,
      },
  ]
  
  # Create the DataFrame from the list_of_dicts
  df = pd.DataFrame(list_of_dicts)
  df = df.sort_values([&quot;timestamp_local&quot;, &quot;inches&quot;, &quot;up_down&quot;])
  
  # For viewing and verifying DataFrame contents in VS Code:
  print(df[&quot;timestamp_local&quot;].unique())
  print(
      tabulate(
          df[[&quot;timestamp_local&quot;, &quot;inches&quot;, &quot;up_down&quot;, &quot;hour&quot;, &quot;load&quot;]],
          headers=&quot;keys&quot;,
          tablefmt=&quot;psql&quot;,
      )
  )
  
  #############################################################################
  # Create the animation in Plotly-Dash
  frames = []
  slider_steps = []
  slider_distinct_days_set = set()
  
  mode = &quot;lines&quot;
  marker = dict(
      size=5,
      opacity=0.5,
  )
  line = dict(
      shape=&quot;spline&quot;,
      smoothing=0.4,
  )
  
  # Transition in milliseconds for the animation (default 500)
  duration_frame = 1000
  duration_transition = 0
  duration_transition_slider = 1000
  
  # Docs say redraw not needed for scatterplots, but if it doesn't redraw,
  # the annotations stay the same as for the first frame...
  redraw = True
  
  easing = &quot;exp-in-out&quot;
  ordering = &quot;layout first&quot;  # default
  mode_animate = &quot;immediate&quot;  # default
  
  bootstrap_blue_base = Color(&quot;blue&quot;)
  bootstrap_blue_lum = Color(&quot;blue&quot;)
  bootstrap_blue_lum.luminance = 0.8
  
  bootstrap_red_base = Color(&quot;red&quot;)
  bootstrap_red_lum = Color(&quot;red&quot;)
  bootstrap_red_lum.luminance = 0.8
  
  # Add scatters to the animation by day
  for gname_day, gdf_day in df.groupby(&quot;timestamp_local_day&quot;):
      frame = {&quot;data&quot;: [], &quot;name&quot;: gname_day, &quot;layout&quot;: {}}
  
      hours_in_day = gdf_day[&quot;timestamp_local&quot;].nunique()
      up_colors = list(bootstrap_red_lum.range_to(bootstrap_red_base, hours_in_day))
      down_colors = list(bootstrap_blue_lum.range_to(bootstrap_blue_base, hours_in_day))
  
      for gname_isup, gdf_isup in gdf_day.groupby(&quot;up_down&quot;):
          i = 0
          colors = down_colors if gname_isup == &quot;Downstroke&quot; else up_colors
          for label, gdf_ts in gdf_isup.groupby(&quot;timestamp_local&quot;):
              print(f&quot;{gname_day} {gname_isup} {label} color: {colors[i].hex}&quot;)
              frame[&quot;data&quot;].append(
                  go.Scatter(
                      name=label,
                      mode=mode,  # lines or markers
                      x=gdf_ts[&quot;inches&quot;],
                      y=gdf_ts[&quot;load&quot;],
                      marker=dict(
                          color=colors[i].hex,
                      ),
                      line=line,
                  )
              )
              i += 1
  
      frames.append(frame)
  
      if gname_day not in slider_distinct_days_set:
          slider_distinct_days_set.add(gname_day)
          slider_steps.append(
              {
                  &quot;method&quot;: &quot;animate&quot;,
                  &quot;label&quot;: gname_day,  # text label to appear on the slider
                  &quot;args&quot;: [
                      [gname_day],
                      {
                          &quot;mode&quot;: mode_animate,
                          &quot;frame&quot;: {&quot;duration&quot;: duration_frame, &quot;redraw&quot;: redraw},
                          &quot;transition&quot;: {
                              &quot;duration&quot;: duration_transition_slider,
                              &quot;easing&quot;: easing,
                          },
                          &quot;ordering&quot;: ordering,
                      },
                  ],
              }
          )
  
  most_recent_day_available_index = max(0, len(slider_distinct_days_set) - 1)
  sliders = [
      {
          # IMPORTANT: this is the &quot;active&quot; step in the slider, which shows up on load
          &quot;active&quot;: most_recent_day_available_index,
          &quot;pad&quot;: {&quot;b&quot;: 10, &quot;t&quot;: 60},
          &quot;len&quot;: 0.9,
          &quot;x&quot;: 0.1,
          &quot;xanchor&quot;: &quot;left&quot;,
          &quot;y&quot;: 0,
          &quot;yanchor&quot;: &quot;top&quot;,
          &quot;steps&quot;: slider_steps,
          &quot;transition&quot;: {&quot;duration&quot;: duration_transition_slider},
      }
  ]
  
  updatemenus = [
      {
          &quot;type&quot;: &quot;buttons&quot;,
          &quot;direction&quot;: &quot;left&quot;,
          &quot;pad&quot;: {&quot;r&quot;: 10, &quot;t&quot;: 70},
          &quot;showactive&quot;: False,
          &quot;x&quot;: 0.1,
          &quot;xanchor&quot;: &quot;right&quot;,
          &quot;y&quot;: 0,
          &quot;yanchor&quot;: &quot;top&quot;,
          &quot;buttons&quot;: [
              {
                  &quot;label&quot;: &quot;Play&quot;,
                  &quot;method&quot;: &quot;animate&quot;,
                  &quot;args&quot;: [
                      None,
                      {
                          &quot;mode&quot;: mode_animate,
                          &quot;direction&quot;: &quot;reverse&quot;,  # forward or reverse
                          &quot;fromcurrent&quot;: True,
                          &quot;frame&quot;: {&quot;duration&quot;: duration_frame, &quot;redraw&quot;: redraw},
                          &quot;transition&quot;: {
                              &quot;duration&quot;: duration_transition,
                              &quot;easing&quot;: easing,
                          },
                          &quot;ordering&quot;: ordering,
                      },
                  ],
              },
              {
                  &quot;label&quot;: &quot;Pause&quot;,
                  &quot;method&quot;: &quot;animate&quot;,
                  &quot;args&quot;: [
                      [None],
                      {
                          &quot;mode&quot;: &quot;immediate&quot;,
                          &quot;frame&quot;: {&quot;duration&quot;: 0, &quot;redraw&quot;: redraw},
                          &quot;transition&quot;: {
                              &quot;duration&quot;: 0,
                          },
                      },
                  ],
              },
          ],
      }
  ]
  
  fig = go.Figure(
      # Make the initial data, before the animation frames start
      data=frames[-1][&quot;data&quot;],
      frames=frames,
      layout=go.Layout(
          hovermode=&quot;closest&quot;,
          height=500,
          plot_bgcolor=&quot;white&quot;,
          showlegend=False,
          font={&quot;family&quot;: &quot;Segoe UI&quot;, &quot;color&quot;: &quot;#717174&quot;},
          xaxis=dict(
              gridcolor=&quot;rgb(238,238,238)&quot;,
              range=[6, 8],
              title=&quot;position&quot;,
          ),
          yaxis=dict(
              gridcolor=&quot;rgb(238,238,238)&quot;,
              range=[-350, 350],
              title=&quot;Weight&quot;,
          ),
          margin=go.layout.Margin(l=0, r=10, b=0, t=0),
          sliders=sliders,
          updatemenus=updatemenus,
      ),
  )
  
  external_stylesheets = [&quot;https://codepen.io/chriddyp/pen/bWLwgP.css&quot;]
  
  
  def create_app():
      app = Flask(__name__)
      dashapp = dash.Dash(__name__, server=app, external_stylesheets=external_stylesheets)
  
      dashapp.layout = html.Div(
          [
              dcc.Graph(
                  figure=fig,
              )
          ]
      )
  
      return app
  
  
  app = create_app()
  
  if __name__ == &quot;__main__&quot;:
      app.run(debug=True, host=&quot;0.0.0.0&quot;, port=5000)
  
  </code></pre>