Sankey + Dash + Animation

Hello everyone, I’m having some difficulties with creating animation with Dash + Plotly for Sankey graphs

I have followed the guides on how to create slider-based animation with frames.

Guides used:

> Blockquote

> Blockquote

> Blockquote

My Dataframe has the following columns:
source - the source node name
target - the target node name
weight - the value
update_tik - timeline - this is the property I use to construct the frames.

Basically, for each update_tik I will have weight for all the source <-> target pairs.

Here is a link to an example data - sample csv

Here is my code (a bit messy). I would appreciate any help

    cols = ["source", "target"]
    labels = []
    for col in cols:
        labels += list(set(df[col].values))
    labels = list(set(labels))

    node_colors = ['#808B96'] * len(labels)
    for idx, label in enumerate(labels):
        if "product" in label:
            node_colors[idx] = '#808B96'
        if "review" in label:
            node_colors[idx] = '#EC7063'
        if "details" in label:
            node_colors[idx] = '#F7DC6F'
        if "rating" in label:
            node_colors[idx] = '#48C9B0'
    connection_groups = df.groupby(["source", "target"])
    # "{} -> {}".format(name[0], name[1])
    connection_names = [name for name, _ in connection_groups ]
    link_colors = ['#CBB4D5'] * len(connection_names)
    color_map = {}
    for idx, name in enumerate(connection_names):
        source = name[0]
        dest = name[1]
        if source not in color_map: # if we have seen this combination
            color_map[source] = {"base": random_color() }
        if dest not in color_map[source]:
            color_map[source][dest] = color_map[source]["base"] + random.choice(["FF", "E6", "CC", "B3", "99", "80", "66", "40"])
            
        link_colors[idx] = color_map[source][dest]

    sliders_dict = {
        "active": 0,
        "yanchor": "top",
        "xanchor": "left",
        "currentvalue": {
            "font": {"size": 20},
            "prefix": "Weights Update tik (min):",
            "visible": True,
            "xanchor": "right"
        },
        "transition": {"duration": animation_duration, "easing": "cubic-in-out"},
        "pad": {"b": 10, "t": 50},
        # "len": 0.9,
        "x": 0.1,
        "y": 0,
        "steps": []
    }


    frames = []
    value_cols = "weight"
    for tik_value, group_df in df.groupby("update_tik"):
        
        for i in range(len(cols)-1):
            if i==0:
                sourceTargetDf = group_df[[cols[i],cols[i+1],value_cols]]
                sourceTargetDf.columns = ['source','target',value_cols]
            else:
                tempDf = group_df[[cols[i],cols[i+1],value_cols]]
                tempDf.columns = ['source','target',value_cols]
                sourceTargetDf = pd.concat([sourceTargetDf,tempDf])
            # sourceTargetDf = sourceTargetDf.groupby(['source','target']).agg({value_cols:'mean'}).reset_index()
            
        # add index for source-target pair
        sourceTargetDf['sourceID'] = sourceTargetDf['source'].apply(lambda x: labels.index(x))
        sourceTargetDf['targetID'] = sourceTargetDf['target'].apply(lambda x: labels.index(x))
        print("tik = ", tik_value)
        print(sourceTargetDf)
        # print(sourceTargetDf)
        data = dict(
            type='sankey',
            node = dict(
                pad = 15,
                thickness = 20,
                line = dict(
                    color = "black",
                    width = 0.5
                ),
                label = labels,
                color = node_colors,
            ),
            link = dict(
                source = sourceTargetDf['sourceID'],
                target = sourceTargetDf['targetID'],
                value = sourceTargetDf['weight'],
                color = link_colors,
            )
        )
        frames.append({"data": [data], "name": "{}".format(tik_value)})

        slider_step = {"args": [
            [tik_value],
            {"frame": {"duration": animation_duration, "redraw": False},
            "mode": "immediate",
            "transition": {"duration": animation_duration}}
        ],
            "label": tik_value,
            "value": tik_value,
            "method": "animate"
        }
        sliders_dict["steps"].append(slider_step)

    
    layout =  dict(
        # title = "title",
        height = 800,  # px,
        font = dict(
          size = 10
        ),
        sliders=[sliders_dict],
        updatemenus=[{
        "buttons": [
            {
                "args": [None, {"frame": {"duration": animation_duration, "redraw": False},
                                "fromcurrent": True, "transition": {"duration": animation_duration,
                                                                    "easing": "quadratic-in-out"}}],
                "label": "Play",
                "method": "animate"
            },
            {
                "args": [[None], {"frame": {"duration": 0, "redraw": False},
                                  "mode": "immediate",
                                  "transition": {"duration": 0}}],
                "label": "Pause",
                "method": "animate"
            }
        ],
        "direction": "left",
        "pad": {"r": 10, "t": 87},
        "showactive": False,
        "type": "buttons",
        "x": 0.1,
        "xanchor": "right",
        "y": 0,
        "yanchor": "top"
    }]
    )
    print("frames count = ",len(frames))
    fig = dict(data=[frames[0]["data"][0]], layout=layout, frames=frames)
    return fig

OK I think I found a possible solution, though I would like to understand why in certain conditions redraw can be set to False

The solution was to make the button animation redraw: True, which will ree-draw the graph