PyShiny Express中Plotly动画3D散点图无法播放求助
问题:Plotly动画3D散点图在PyShiny中无法播放
尝试使用Plotly生成动画3D散点图,并在PyShiny Express创建的仪表板中展示。该代码在Jupyter Notebook中运行时动画完全正常,但在Shiny中点击播放按钮后无动画效果,仅工具提示(tooltip)可正常显示数据。动画仅用于改变散点标记的大小,已排查异步函数问题但仍未解决。
问题原因分析
核心问题是Shiny渲染Plotly部件时,动画帧的trace必须与初始图的trace严格匹配。原代码中初始图通过px.scatter_3d生成,而动画帧直接创建了全新的go.Scatter3d对象,导致Shiny无法将帧中的trace与初始trace关联,进而无法触发视觉上的动画更新(仅tooltip数据更新是因为数据本身存在,但视觉元素未被正确映射)。
解决方案及修改后的代码
修改思路:确保动画帧仅更新需要变化的属性(标记大小、颜色),而非重新创建整个trace,保持帧与初始trace的结构一致性。
import io from pathlib import Path from shiny import reactive from shiny.express import input, ui, render from shiny.types import FileInfo import pandas as pd import plotly.graph_objects as go import plotly.express as px from shinywidgets import render_widget ui.page_opts( title="Visualisation", fillable=True, id="page", ) with ui.card(full_screen=True): @render_widget def coordinate_space(): try: with ui.Progress(min=1, max=5) as p: data = { 'X': [1, 2, 3, 4, 5], 'Y': [5, 4, 3, 2, 1], 'Z': [2, 3, 4, 5, 6], 'FZ_new': [10, 20, 30, 40, 50], 'FZ': [5, 10, 15, 20, 25] } scaled_coordinate_system = pd.DataFrame(data) p.set(2, message="Data loaded, preparing plot...") # 初始trace:保留结构,后续帧基于此更新属性 fig = go.Figure() fig.add_trace(go.Scatter3d( x=scaled_coordinate_system['X'], y=scaled_coordinate_system['Y'], z=scaled_coordinate_system['Z'], mode='markers', marker=dict(size=scaled_coordinate_system['FZ_new'], color=scaled_coordinate_system['FZ_new']), opacity=0.7, name='Scatter Trace' )) p.set(3, message="Creating animation frames...") # 帧仅更新需要变化的属性,不重新创建trace frames = [ go.Frame( data=[go.Scatter3d( marker=dict(size=scaled_coordinate_system['FZ_new'] * 10, color="Red"), opacity=0.9 )], name='Frame 1' ), go.Frame( data=[go.Scatter3d( marker=dict(size=scaled_coordinate_system['FZ'], color=scaled_coordinate_system['FZ']), opacity=0.7 )], name='Frame 2' ) ] fig.frames = frames p.set(4, message="Updating layout...") fig.update_layout( scene=dict( xaxis_title='X AXIS', yaxis_title='Y AXIS', zaxis_title='Z AXIS' ), updatemenus=[dict( type='buttons', direction="down", showactive=True, buttons=[ dict( label='Play', method='animate', args=[None, dict( frame=dict(duration=500, redraw=True), fromcurrent=True, transition=dict(duration=0) )] ), dict( label='Pause', method='animate', args=[[None], dict( frame=dict(duration=0, redraw=False), mode='immediate' )] ) ] )] ) fig.update_layout(margin=dict(l=0, r=0, b=0, t=0)) camera = dict( eye=dict(x=2, y=2, z=0.5) ) fig.update_layout(scene_camera=camera) p.set(5, message="Rendering plot...") return fig except Exception as e: ui.notification_show(f"{e}", duration=20, type="error") return None
关键修改点说明
- 初始图直接用
go.Figure()+add_trace()创建,避免px.scatter_3d生成的隐藏结构导致trace不匹配 - 动画帧仅更新
marker和opacity属性,不重新定义整个Scatter3d对象,确保与初始trace的索引、name等结构一致 - 保持
updatemenus的配置不变,确保播放/暂停逻辑正常触发
内容的提问来源于stack exchange,提问作者Secret Ambush
相关产品推荐
相关产品推荐

