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:
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