如何在Plotly中捕获用户操作图例后的可见图例项?
如何在Plotly中捕获用户操作图例后的可见图例项?
我完全懂你的需求——用户点击雷达图的图例切换显示状态后,你想实时拿到当前还在展示的Zone名称,用来后续过滤数据框做分析对吧?结合你用的Streamlit+Plotly场景,我们可以通过Streamlit会话状态 + Plotly的restyle事件监听来实现,我来一步步给你说怎么改代码:
完整修改后的可运行代码
import streamlit as st import pandas as pd from typing import Dict, List import plotly.graph_objects as go metrics = { "Baseline": [60, 70, 80, 65, 90], "Zone A": [75, 85, 70, 80, 95], "Zone B": [65, 60, 75, 70, 85], "Zone C": [55, 65, 85, 60, 80], "Zone D": [80, 90, 70, 85, 88] } categories = ["Safety", "Infrastructure", "Resources", "Response Time", "Efficiency"] def create_radar_chart(metrics: Dict[str, List[float]], categories: List[str]) -> go.Figure: """Create radar chart.""" fig = go.Figure() fig.add_trace(go.Scatterpolar( r=metrics['Baseline'], theta=categories, fill='toself', name='Baseline', line=dict(color='#808080'), fillcolor='rgba(128, 128, 128, 0.2)' )) colors = ['#00FFB8', '#4A9DFF', '#FF6B6B', '#FFD93D', '#6C63FF'] for i, (zone, values) in enumerate(metrics.items()): if zone != 'Baseline': color = colors[i % len(colors)] fig.add_trace(go.Scatterpolar( r=values, theta=categories, fill='toself', name=zone, line=dict(color=color), fillcolor=f'rgba{tuple(list(int(color.lstrip("#")[i:i+2], 16) for i in (0, 2, 4)) + [0.4])}' )) fig.update_layout( width=500, height=500, polar=dict( radialaxis=dict( visible=True, range=[0, max([max(vals) for vals in metrics.values()]) * 1.1] ), bgcolor='rgba(0,0,0,0)' ), showlegend=True, paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)', font_color = '#7A7F8C', legend_font_color = '#7A7F8C', ) return fig # 初始化会话状态:持久化存储当前可见的Zone名称 if "visible_zones" not in st.session_state: st.session_state.visible_zones = list(metrics.keys()) # 初始状态下所有区域都可见 # 创建并显示雷达图,指定唯一key用于捕获交互事件 fig = create_radar_chart(metrics, categories) st.plotly_chart(fig, key="radar_chart") # 捕获图例点击触发的restyle事件 chart_interaction = st.session_state.get("radar_chart", {}) restyle_event = chart_interaction.get("restyleData") if restyle_event: # 解析事件数据:格式为 [{'visible': 可见状态}, [受影响的trace索引列表]] visible_status = restyle_event[0].get("visible") affected_traces = restyle_event[1] for trace_idx in affected_traces: trace_name = fig.data[trace_idx].name # 处理可见状态:如果是批量修改则取对应索引的值,否则直接用当前状态 is_visible = visible_status[trace_idx] if isinstance(visible_status, list) else visible_status # 更新会话状态中的可见Zone列表 if is_visible and trace_name not in st.session_state.visible_zones: st.session_state.visible_zones.append(trace_name) elif not is_visible and trace_name in st.session_state.visible_zones: st.session_state.visible_zones.remove(trace_name) # 展示当前可见的Zone,这里可以替换成你的数据分析逻辑 st.subheader("当前可见的区域") st.markdown(f"可见项:{', '.join(st.session_state.visible_zones)}") # 示例:用可见Zone过滤数据框(假设你有对应的业务数据) # sample_df = pd.DataFrame({ # "Zone": ["Zone A", "Zone B", "Zone C", "Zone D", "Baseline"], # "Overall Score": [85, 75, 70, 88, 75] # }) # filtered_df = sample_df[sample_df["Zone"].isin(st.session_state.visible_zones)] # st.subheader("过滤后的数据分析") # st.dataframe(filtered_df)
核心逻辑说明
- 会话状态持久化:用
st.session_state.visible_zones保存可见区域列表,避免Streamlit每次重运行后丢失状态。 - 交互事件捕获:给
st.plotly_chart指定唯一key,Streamlit会自动把图表的所有交互事件(比如图例点击)存在对应的会话状态中。 - 事件解析与状态更新:图例点击会触发Plotly的
restyle事件,我们解析事件里的trace索引和可见状态,实时更新visible_zones列表。 - 业务联动:你可以直接用
st.session_state.visible_zones过滤数据框,实现图表和后续分析模块的联动。
备注:内容来源于stack exchange,提问作者Sree
相关产品推荐
相关产品推荐

