Quantcast
Channel: 🎛️ Dash - Plotly Community Forum
Viewing all articles
Browse latest Browse all 6271

Graph Lines Disappear in Certain Frames of Animation

$
0
0

I’ve got a Dash graph “animation” (multiple frames, which show different days) whose lines don’t show up when the frame changes. I’ve been using Dash for a few years now and I’ve never run into this problem before, but I have a reproducible example below.

Here’s what all of the frames are supposed to look like (note the orange lines on top and blue lines on the bottom):
enter image description here

That was the first frame, above. The second frame from the right looks like this, with no orange lines above the blue lines. I can assure you there’s data there; it’s just not showing up!
enter image description here

To get set up to answer this question, install the following libraries:

pip install dash plotly pandas colour

The dataframe I’m using can be downloaded from here, as a CSV file called “dataframe.csv”:
http://www.wikiupload.com/WML4A6FKXHPPLA1

Here’s a backup link, in case the above link doesn’t work for some reason:
https://www.filehosting.org/file/details/919052/dataframe.csv


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


external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

df = pd.read_csv("./dataframe.csv")

x_min = df["inches"].min()
x_max = df["inches"].max()
y_min = df["load"].min()
y_max = df["load"].max()

frames = []
slider_steps = []
slider_distinct_days_set = set()

mode = "lines"
marker = dict(
    size=5,
    opacity=0.5,
)
line = dict(
    shape="spline",
    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 = "exp-in-out"
ordering = "layout first"  # default
mode_animate = "immediate"  # default

bootstrap_blue_base = Color("#5bc0de")
bootstrap_blue_lum = Color("#5bc0de")
bootstrap_blue_lum.luminance = 0.9

bootstrap_red_base = Color("#f0ad4e")
bootstrap_red_lum = Color("#f0ad4e")
bootstrap_red_lum.luminance = 0.9

# Add scatters to the animation by day
for gname_day, gdf_day in df.groupby("timestamp_local_day"):
    frame = {
        "data": [],
        "name": gname_day,
        "layout": {}
    }

    hours_in_day = gdf_day["timestamp_local"].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("up_down"):
        i = 0
        colors = down_colors if gname_isup == "Downstroke" else up_colors
        for label, gdf_ts in gdf_isup.groupby("timestamp_local"):
            print(f"{gname_day} {gname_isup} {label} color: {colors[i].hex}")
            frame["data"].append(
                go.Scatter(
                    name=label,
                    mode=mode,  # lines or markers
                    x=gdf_ts["inches"],
                    y=gdf_ts["load"],
                    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(
            {
                "method": "animate",
                "label": gname_day,  # text label to appear on the slider
                "args": [
                    [gname_day],
                    {
                        "mode": mode_animate,
                        "frame": {"duration": duration_frame, "redraw": redraw},
                        "transition": {
                            "duration": duration_transition_slider,
                            "easing": easing,
                        },
                        "ordering": ordering,
                    },
                ],
            }
        )

most_recent_day_available_index = max(0, len(slider_distinct_days_set) - 1)
sliders = [
    {
        # IMPORTANT: this is the "active" step in the slider, which shows up on load
        "active": most_recent_day_available_index,
        "pad": {"b": 10, "t": 60},
        "len": 0.9,
        "x": 0.1,
        "xanchor": "left",
        "y": 0,
        "yanchor": "top",
        "steps": slider_steps,
        "transition": {"duration": duration_transition_slider},
    }
]

updatemenus = [
    {
        "type": "buttons",
        "direction": "left",
        "pad": {"r": 10, "t": 70},
        "showactive": False,
        "x": 0.1,
        "xanchor": "right",
        "y": 0,
        "yanchor": "top",
        "buttons": [
            {
                "label": "Play",
                "method": "animate",
                "args": [
                    None,
                    {
                        "mode": mode_animate,
                        "direction": "reverse",  # forward or reverse
                        "fromcurrent": True,
                        "frame": {"duration": duration_frame, "redraw": redraw},
                        "transition": {
                            "duration": duration_transition,
                            "easing": easing,
                        },
                        "ordering": ordering,
                    },
                ],
            },
            {
                "label": "Pause",
                "method": "animate",
                "args": [
                    [None],
                    {
                        "mode": "immediate",
                        "frame": {"duration": 0, "redraw": redraw},
                        "transition": {
                            "duration": 0,
                        },
                    },
                ],
            },
        ],
    }
]

fig = go.Figure(
    # Make the initial data, before the animation frames start
    data=frames[-1]["data"],
    frames=frames,
    layout=go.Layout(
        hovermode="closest",
        height=500,
        plot_bgcolor="white",
        showlegend=False,
        font={"family": "Segoe UI", "color": "#717174"},
        xaxis=dict(
            gridcolor="rgb(238,238,238)",
            range=[x_min - 5, x_max + 5],
            title="position",
        ),
        yaxis=dict(
            gridcolor="rgb(238,238,238)",
            range=[y_min - 5, y_max + 5],
            title="Weight",
        ),
        margin=go.layout.Margin(l=0, r=10, b=0, t=0),
        sliders=sliders,
        updatemenus=updatemenus,
    ),
)

app.layout = html.Div(
    [
        dcc.Graph(
            figure=fig,
        )
    ]
)


if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0', port=5000)

FYI, I’ve posted the same question on StackOverflow here

1 post - 1 participant

Read full topic


Viewing all articles
Browse latest Browse all 6271

Latest Images

Trending Articles



Latest Images