Datasets behave differently with interactive scatter3d

I would like to make a plotly graph that would update itself on click and also it might be in two states, Type1 and Type2, which might be chosen from a dropdown menu. I’ve created a toy dataset of 200 rows and my plotly graph behaves as intended. However when I use the dataset that I need to use, it suddenly stops working. Can someone please tell me what is the difference and what can I do to make it work?

So this is my toy dataset generation process:

import pandas as pd
from sklearn.datasets import make_blobs

df = make_blobs(n_samples=200, n_features=3, centers=6)
df = pd.DataFrame(df[0], index=df[1])
df = df.reset_index()
df.columns = ['c_1', 'x_1', 'y_1', 'z_1']
df['x_2'] = np.sin(df['x_1']) + 1
df['y_2'] = np.tan(df['y_1'])
df['z_2'] = df['z_1'] + 5

The actual data I need to plot consists of 200 rows and basically has the same structure - 7 columns, one of them is for cluster, and 3 to Type1 and Type2. I know that it is usually frowned upon sharing links (at least on stackoverflow it is the case), but here is my 200 row sample (GDrive) and I just load it up as follows:

import pandas as pd
df = pd.read_csv('fumble.csv')

And here is my plotly visualization:

import plotly.graph_objects as go

data = [
    go.Scatter3d(
        x=df['x_1'],
        y=df['y_1'],
        z=df['z_1'],
        text = ['Cluster: {}'.format(item) for item in df['c_1']],
        mode='markers',
        marker=dict(size=[5]*len(df),
                    color=df['c_1'],
                    colorscale=[
                        'rgb(149, 165, 166)',
                        'rgb(155, 89, 182)',
                        'rgb(36, 113, 163)',
                        'rgb(20, 90, 50)',
                        'rgb(183, 149, 11)',
                        'rgb(211, 84, 0)',
                        'rgb(115, 198, 182)',
                        'rgb(245, 183, 177)'
                    ],
                    opacity=0.5,
                    line=dict(width=0)),
    )
]

# dropdown
updatemenus=[
        dict(
            buttons=list([
                dict(
                    args=[
                        {"x": [df['x_1'].tolist()]},
                        {"y": [df['y_1'].tolist()]},
                        {"z": [df['z_1'].tolist()]}
                    ],
                    label="Type 1",
                    method="restyle"
                ),
                dict(
                    args=[
                        {"x": [df['x_2'].tolist()]},
                        {"y": [df['y_2'].tolist()]},
                        {"z": [df['z_2'].tolist()]}
                    ],
                    label="Type 2",
                    method="restyle"
                )
            ]),
            direction="down",
            pad={"r": -5, "t": 15},
            showactive=True,
            x=0,
            xanchor="left",
            y=1,
            yanchor="top"
        ),
    ]


layout = go.Layout(
    title='Clusters',
    scene=dict(xaxis={'title': 'X'},
               yaxis={'title': 'Y'},
               zaxis={'title': 'Z'}),
    margin={'l': 60, 'b': 40, 't': 30, 'r': 10},
    legend={'x': 0, 'y': 1},
    height=800, 
    width=1000,
    hovermode='closest',
    updatemenus=updatemenus
)

# change color and size on click
def update_point(trace, points, state):
    c = list(scatter.marker.color)
    s = list(scatter.marker.size)
    for i in points.point_inds:
        c[i] = '#ff0000'
        s[i] = 5
        with fig.batch_update():
            scatter.marker.color = c
            scatter.marker.size = s

            
fig = go.FigureWidget(data=data, layout=layout)
scatter = fig.data[0]
scatter.on_click(update_point)

fig

When I load my actual data the plot does not change when I switch between Type1 and Type2. The points do not change their position in space, the hover labels do not change. I’ve checked several times that each data point in my dataset is actually different in at least one axis. What might be the problem?

Thanks in advance.

@sepremento
Your button args do not have the right definition.
Replace them with:


buttons=[
                dict(
                    args=[
                        {"x": [df['x_1']],
                         "y": [df['y_1']],
                         "z": [df['z_1']]}
                    ],
                    label="Type 1",
                    method="restyle"
                ),
                dict(
                    args=[
                        {"x": [df['x_2']],
                          "y": [df['y_2']],
                          "z": [df['z_2']]}
                    ],
                    label="Type 2",
                    method="restyle"
                )
            ]

More precisely you must define a single dict for all updates, or in your original code you defined a dict for each updated parameter.

1 Like

Thank you very much!