[Scatterpolar] Animation frame based on CSV file

import plotly.express as px
import pandas as pd


# Read the CSV file
df = pd.read_csv('./data/data.csv')

# Define the columns containing the PRX values
prx_columns = ['PRX.D0', 'PRX.D45', 'PRX.D90', 'PRX.D135', 'PRX.D180', 'PRX.D225', 'PRX.D270', 'PRX.D315']
prx_values = df[prx_columns]

# clean data
tmp = df['timestamp(ms)'][0]
df['timestamp(ms)'] = round(df['timestamp(ms)']-tmp)
for col in prx_columns:
    df[col] = df[col].round(2)

# creating frames
frames = []
for timestamp in df['timestamp(ms)']:
    frame_data = {
        'timestamp(ms)': [timestamp] * len(prx_columns),
        'PRX Column': prx_columns,
        'PRX Value': df.loc[df['timestamp(ms)'] == timestamp, prx_columns].values.flatten()
    }
    frames.append(pd.DataFrame(frame_data))

plot = px.scatter_polar(pd.concat(frames, ignore_index=True),
                        r='PRX Value',
                        theta='PRX Column',
                        animation_frame='timestamp(ms)',
                        range_r=[0, 60],
                        title='PRX Values over Time')

# Adjust the plot speed
plot.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 0  # Increase duration to slow down the animation

plot.show()

Here is my csv file header : raw file link

timestamp(ms) PRX.D0 PRX.D45 PRX.D90 PRX.D135 PRX.D180 PRX.D225 PRX.D270 PRX.D315 ATT.Roll ATT.Pitch ATT.Yaw
0 282661.675 1.88 2.93 3.05 60.0 7.27 3.48 3.44 3.08 0.02 2.76 159.89
1 282761.675 1.88 2.93 3.05 60.0 7.28 3.48 3.44 3.08 0.02 2.76 159.91
2 282861.675 1.88 2.93 3.05 60.0 7.28 3.48 3.44 3.08 0.02 2.76 159.91
3 282961.675 1.88 2.93 3.05 60.0 7.28 3.48 3.44 3.08 0.02 2.76 159.92
4 283061.675 1.88 2.93 3.05 60.0 7.28 3.48 3.44 3.08 0.02 2.76 159.92

Output :


I’m only ploting angles PRX.x and everything works as expected !

I want to do the same with plotly.graph_objects instead of plotly.express to add a subplot synchronized with the same slider to show the ATT.Roll, ATT.Pitch and ATT.Yaw next to it.

I didn’t succeed yet, here is my current code :

import plotly.graph_objects as go
import pandas as pd


# load data
df = pd.read_csv('./data/data.csv')

# Define the columns containing the PRX values
prx_columns = ['PRX.D0', 'PRX.D45', 'PRX.D90', 'PRX.D135', 'PRX.D180', 'PRX.D225', 'PRX.D270', 'PRX.D315']
prx_values = df[prx_columns]

# clean data
tmp = df['timestamp(ms)'][0]
df['timestamp(ms)'] = round(df['timestamp(ms)']-tmp)
for col in prx_columns:
    df[col] = df[col].round(2)


fig = go.Figure()

# Iterate over each angle column and create polar scatter plot
for angle in prx_columns:
    fig.add_trace(
        go.Scatterpolar(
            r=df[angle],
            theta=[angle],
            mode='markers',
            name=angle
        )
    )

fig.update_layout(
    polar=dict(
        radialaxis=dict(
            visible=True,
            range=[0, df.iloc[:, 1:].values.max()]  # Set the range based on your data
        ),
        angularaxis=dict(
            rotation=90
        )
    ),
    title='Angle Animation'
)

fig.update_layout(
    updatemenus=[
        {
            'buttons': [
                {
                    'label': 'Play',
                    'method': 'animate',
                    'args': [df['timestamp(ms)'], {
                        'frame': {'duration': 0, 'redraw': True},
                        'fromcurrent': True,
                        'transition': {'duration': 0}
                    }]
                },
                {
                    'label': 'Pause',
                    'method': 'animate',
                    'args': [df['timestamp(ms)'], {
                        'frame': {'duration': 0, 'redraw': False},
                        'mode': 'immediate',
                        'transition': {'duration': 0}
                    }]
                }
            ],
            'direction': 'left',
            'pad': {'r': 10, 't': 87},
            'showactive': False,
            'type': 'buttons',
            'x': 0.1,
            'xanchor': 'right',
            'y': 0,
            'yanchor': 'top'
        }
    ],
    sliders=[
        {
            'currentvalue': {'visible': False},
            'steps': [
                {'label': str(step), 'method': 'animate', 'args': [df['timestamp(ms)'], {'frame': {'duration': 0, 'redraw': True}, 'mode': 'immediate'}]}
                for step in df['timestamp(ms)']
            ],
        }
    ]
)

fig.show()

But I dont know how to get frames synchronized by my timestamp(ms) (in the csv) slider

If you have any example !

Have a nice day guys :wink:

Here is my solution for people who need tips : CSV file

import plotly.graph_objects as go
import pandas as pd

def frame_args(duration):
    return {
            "frame": {"duration": duration},
            "mode": "immediate",
            "fromcurrent": True,
            "transition": {"duration": duration, "easing": "linear"},
        }

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

prx_columns = ['PRX.D0', 'PRX.D45', 'PRX.D90', 'PRX.D135', 'PRX.D180', 'PRX.D225', 'PRX.D270', 'PRX.D315']
prx_values = df[prx_columns]

frames = []
for timestamp in df['timestamp(ms)']:
    frame_data = {
        'timestamp(ms)': [timestamp] * len(prx_columns),
        'PRX Column': prx_columns,
        'PRX Value': df.loc[df['timestamp(ms)'] == timestamp, prx_columns].values.flatten()
    }
    frames.append(pd.DataFrame(frame_data))

fig = go.Figure(
    data=go.Scatterpolar(
        r=[0] * len(prx_columns),
        theta=prx_columns,
        mode='markers',
        marker=dict(size=6, color='blue'),
        theta0=90
    ),
    layout=go.Layout(
        title="Proximity Values over Time",
        polar=dict(
            radialaxis=dict(range=[0, 60], showticklabels=False, ticks=''),
            angularaxis=dict(showticklabels=True, ticks='outside', linewidth=1, ticklen=8, tickcolor='gray', rotation=90,),
        ),
        updatemenus=[
            {
                "buttons":[
                    {
                        "args": [None, frame_args(50)],
                        "label": "▶", # play symbol
                        "method": "animate",
                    },
                    {
                        "args": [[None], frame_args(0)],
                        "label": "◼", # pause symbol
                        "method": "animate",
                    },
                ],
                "direction": "left",
                "pad": {"r": 10, "t": 70},
                "type": "buttons",
                "x": 0.1,
                "y": 0,
            }
        ],
        sliders=[
                {
                    "pad": {"b": 10, "t": 60},
                    "len": 0.9,
                    "x": 0.1,
                    "y": 0,
                    "steps": [
                        {
                            "args": [[f.name], frame_args(0)],
                            "label": str(f.name),
                            "method": "animate",
                        }
                        for k, f in enumerate(fig.frames)
                    ],
                }
            ],
    ),
    frames=[go.Frame(
        data=go.Scatterpolar(
            r=frame['PRX Value'].tolist(),
            theta=frame['PRX Column'].tolist(),
            mode='markers',
            marker=dict(size=6, color='blue')
        ),
        name=str(frame['timestamp(ms)'].iloc[0])
    ) for frame in frames]
)


fig.show()