Python随着时间的推移在Scatter3d中绘制动画标记样式或点

Posted

技术标签:

【中文标题】Python随着时间的推移在Scatter3d中绘制动画标记样式或点【英文标题】:Python plotly animate marker styles or points in Scatter3d over time 【发布时间】:2021-08-10 20:28:36 【问题描述】:

我有一个带有 3D 散点图的基于 plotly & Dash 的应用程序。数据头长这样:

'Classname'    'Date'     '0'     '1'     '2'
 B              1542       0.95   0.98     0.80
 B              1725       1.00   1.00     0.75
 C              1620       0.74   0.36     0.85

我有 26 节课。不是每个班级每年都有代表。现在我想通过它们的Date 变量为数据点设置动画,但其余数据应该始终可见,因此我可以看到数据点在点云中的位置。 示例:所有数据点都是灰色的,只有当前数据框的点用颜色突出显示。 由于我不知道这是否可能,我只是尝试将动画帧添加为具有不同样式的附加点。但是动画不起作用,我不知道为什么。我可以看到“数据”、滑块和按钮,但没有动画帧。如果我点击 PLAY 什么都不会发生。 有时,如果我在图表中单击周围,会突然出现一些额外的“钻石”点,但这非常有问题,动画仍然不起作用。看起来像这样:

我坚持使用this 文档,并尝试了this 问题中的建议。

这是我创建图形的代码:

def animate_time_tsne(dff):
    # make figure
    fig_dict = 
        "data": [],
        "layout": ,
        "frames": []
    

    years = np.unique(dff['Date'])
    styles = np.unique(dff['Classname'])

    fig_dict["layout"]["hovermode"] = "closest"
    fig_dict["layout"]["updatemenus"] = [
        
            "buttons": [
                
                    "args": [None, "frame": "duration": 500, "redraw": False,
                                    "fromcurrent": True, "transition": "duration": 300,
                                                                        "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"
        
    ]

    sliders_dict = 
        "active": 0,
        "yanchor": "top",
        "xanchor": "left",
        "currentvalue": 
            "font": "size": 20,
            "prefix": "Year:",
            "visible": True,
            "xanchor": "right"
        ,
        "transition": "duration": 300, "easing": "cubic-in-out",
        "pad": "b": 10, "t": 50,
        "len": 0.9,
        "x": 0.1,
        "y": 0,
        "steps": []
    

    # create data
    colors = px.colors.qualitative.Dark24 + px.colors.qualitative.Light24,
    for i, style in enumerate(styles):
        data_by_style = dff[dff['Classname'] == style]
        data_dict = go.Scatter3d(
            x=data_by_style['0'], y=data_by_style['1'], z=data_by_style['2'],
            mode='markers', marker='color': colors[0][i], 'size':5,
            name=style,
            #customdata=[data_by_style['Filename'], data_by_style['Classname']]
        )
        fig_dict['data'].append(data_dict)
    fig_dict['data'] = fig_dict['data']*2

    # create frames
    for year in years:
        if not np.isnan(year):
            frame = "data": [], "name": str(year), "traces":[1]
            data_by_year = dff[dff['Date'] == year]
            for style in styles:
                data_by_year_style = data_by_year[data_by_year['Classname'] == style]
                data_dict = go.Scatter3d(
                    x=data_by_year_style['0'], y=data_by_year_style['1'],
                    z=data_by_year_style['2'],
                    mode='markers',
                    marker='size': 15, 'symbol': 'diamond', 'color':colors[0][-1],
                    name=style
                )
                frame['data'].append(data_dict)

            fig_dict['frames'].append(frame)
            slider_step = "args": [
                [year],
                "frame": "duration": 300, "redraw": False,
                 "mode": "immediate",
                 "transition": "duration": 300
            ],
                "label": year,
                "method": "animate"
            sliders_dict["steps"].append(slider_step)

    fig_dict["layout"]["sliders"] = [sliders_dict]

    return go.Figure(fig_dict)

【问题讨论】:

【参考方案1】:

我无法通过 go.figure 找到它,但我通过 plotly express 找到了一个可行的解决方案。

dff.dropna(subset=['Date'], inplace=True)  # drop nan values
    dff = dff.sort_values('Date', ascending=True)
    x_range = [dff['0'].min(), dff['0'].max()]
    y_range = [dff['1'].min(), dff['1'].max()]
    z_range = [dff['2'].min(), dff['2'].max()]
    colors = px.colors.qualitative.Dark24 + px.colors.qualitative.Light24

    fig = px.scatter_3d(
        dff, x='0', y='1', z='2',
        animation_frame='Date',
        range_x=x_range, range_y=y_range, range_z=z_range,
        height=900, width=1200
    )

    fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 300
    fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 100
    for x in fig.frames:
        x.data[0]['marker']['color'] = '#ff00c2'
        x.data[0]['marker']['symbol'] = 'diamond'
        x.data[0]['marker']['size'] = 20

    styles = np.unique(dff['Classname'])

    for i, style in enumerate(styles):
        data_by_style = dff[dff['Classname'] == style]
        fig.add_trace(go.Scatter3d(
            x=data_by_style['0'], y=data_by_style['1'], z=data_by_style['2'],
            mode='markers',
            marker='color': colors[i], 'size': 5,
            name=style,
            opacity=0.1
        ))

    return fig

【讨论】:

以上是关于Python随着时间的推移在Scatter3d中绘制动画标记样式或点的主要内容,如果未能解决你的问题,请参考以下文章

swift spritekit 随着游戏时间的推移增加重力?

jquery ajax 链接工作/不工作它随着时间的推移而工作

Tkinter — 随着时间的推移执行函数

随着时间的推移跟踪文件

随着时间的推移重复条目计数不同

当计算相同时,为啥 R 会随着时间的推移而减慢?