点击Sunburst Chart扇段无响应,如何触发on_click/on_hover回调?
问题:Plotly Sunburst图表无法触发on_click/on_hover回调实现筛选
我之前实现了点击柱状图扇段筛选表格的功能,现在想给Sunburst Chart做同样的筛选,但绑定的on_hover和on_click回调完全没反应。
现象
- 初始化时
trace.on_hover()和trace.on_click()会触发一次,但后续交互(点击/悬停)完全没响应 setHoverValues()和setClickValues()内部的断点从未触发- 实现逻辑和之前的柱状图完全一致,但Sunburst就是不响应
当前实现步骤
- 在server函数中创建
sunburst_chart(),遍历图表的trace(Sunburst只有一个trace) - 为trace绑定
on_hover和on_click回调,分别调用setHoverValues和setClickValues - 回调函数把
points属性存入响应式变量 - 用文本组件显示响应式变量的值
完整代码
from shiny import App, reactive, render, ui from shinywidgets import output_widget, render_widget import plotly.graph_objects as go import plotly.express as px import pandas as pd df=pd.DataFrame({'Category':['Utilities','Rent','Insurance','Gas','Parking','Maintenance','Groceries','Restaurants'], 'Category_L2':['Home','Home','Home','Car','Car','Car','Food','Food']}) app_ui = ui.page_fluid( ui.output_text_verbatim('hoverInfoOutput'), ui.output_text_verbatim('clickInfoOutput'), output_widget('sunburst_chart'), ) def server(input, output, session): hoverInfo = reactive.value({}) clickInfo = reactive.value({}) def setHoverValues(trace, points, selector): if not points.point_inds: return hoverInfo.set(points.copy()) @render.text def hoverInfoOutput(): return hoverInfo.get() def setClickValues(trace, points, selector): if not points.point_inds: return clickInfo.set(points.copy()) @render.text def clickInfoOutput(): return hoverInfo.get() @render_widget def sunburst_chart(): # Prepare data for the Sunburst chart labels = [] parents = [] values = [] ids = [] # Add Category_L2 (inner ring) data l2_counts = df['Category_L2'].value_counts() for l2_category, count in l2_counts.items(): labels.append(l2_category) parents.append("") values.append(count) ids.append(f"L2_{l2_category}") # Add Category (outer ring) data for index, row in df.iterrows(): category = row['Category'] category_l2 = row['Category_L2'] labels.append(category) parents.append(f"L2_{l2_category}") values.append(1) ids.append(f"Cat_{category}") # Create Sunburst chart fig = go.Figure(go.Sunburst( ids=ids, labels=labels, parents=parents, values=values, branchvalues="total", hovertemplate='<b>%{label}</b><br>Count: %{value}<extra></extra>', )) fig.update_layout( title_text='Two-Level Donut Chart: Category vs. Category_L2', margin=dict(t=50, l=0, r=0, b=0), uniformtext_minsize=10, uniformtext_mode='hide' ) figWidget = go.FigureWidget(fig) for trace in fig.data: trace.on_hover(setHoverValues) trace.on_click(setClickValues) return figWidget app = App(app_ui, server)
解决方案:直接创建FigureWidget并绑定事件
问题根源是:从普通go.Figure转换为FigureWidget时,Sunburst trace的事件绑定上下文会丢失,导致交互无法触发回调。直接创建FigureWidget即可解决。
修改后的核心代码
@render_widget def sunburst_chart(): # 数据准备部分保持不变 labels = [] parents = [] values = [] ids = [] l2_counts = df['Category_L2'].value_counts() for l2_category, count in l2_counts.items(): labels.append(l2_category) parents.append("") values.append(count) ids.append(f"L2_{l2_category}") for index, row in df.iterrows(): category = row['Category'] category_l2 = row['Category_L2'] labels.append(category) parents.append(f"L2_{l2_category}") values.append(1) ids.append(f"Cat_{category}") # 直接创建FigureWidget,而非先创建Figure再转换 figWidget = go.FigureWidget(go.Sunburst( ids=ids, labels=labels, parents=parents, values=values, branchvalues="total", hovertemplate='<b>%{label}</b><br>Count: %{value}<extra></extra>', )) figWidget.update_layout( title_text='Two-Level Donut Chart: Category vs. Category_L2', margin=dict(t=50, l=0, r=0, b=0), uniformtext_minsize=10, uniformtext_mode='hide' ) # 直接给FigureWidget里的trace绑定事件 for trace in figWidget.data: trace.on_hover(setHoverValues) trace.on_click(setClickValues) return figWidget
额外修复:纠正clickInfoOutput的逻辑错误
之前clickInfoOutput错误返回了hoverInfo的值,修改为:
@render.text def clickInfoOutput(): return clickInfo.get()
原理说明
FigureWidget是Plotly交互式图表的核心载体,直接创建它能确保事件绑定正确关联到交互式实例,避免转换过程中丢失事件上下文。
内容的提问来源于stack exchange,提问作者Dave Guenther
相关产品推荐
相关产品推荐

