如何获取Streamlit中Vega-Altair图表的选中数据点?
在Streamlit中获取Vega-Altair框选数据的解决方案
问题描述
我在Streamlit里用Vega-Altair绘图,已经通过box_selection = alt.selection_interval(name="interval")实现了框选数据点的功能,但没法获取选中的数据做后续处理。在Jupyter Notebook里用alt.JupyterChart能拿到选中数据,但在Streamlit里这个方法没法保留图表状态,试过用st.session_state存图表状态,但图表更新时session_state不会动态同步,需要合适的桥接方案。
附上完整图表生成代码:
import altair as alt import streamlit as st def generate_chart(df,xcol,ycol,lbl='off',color='basic',title='', tooltip=['DataPoint','Ccontent']): legendSelection = alt.selection_point(fields=['Data'], bind='legend') zoompan = alt.selection_interval(bind='scales', # on="[mousedown[event.altKey], mouseup] > mousemove", translate="[mousedown[event.altKey], mouseup] > mousemove!", zoom="wheel![event.altKey]" ) # Box selection for highlighting or filtering data points box_selection = alt.selection_interval(name="interval") chart = alt.Chart(df).mark_circle(size=150, stroke='#666', strokeWidth=0.8, opacity=1).encode( x= alt.X(xcol, scale=alt.Scale(zero=False), axis=alt.Axis(labels=False, ticks=False, domain=False) ), y= alt.Y(ycol, scale=alt.Scale(zero=False), axis=alt.Axis(labels=False, ticks=False, domain=False) ), color=alt.condition(box_selection, 'Data:N', alt.value('lightgray'), # Update color based on selection legend=alt.Legend(columns=1, symbolLimit=0, labelFontSize=14)), tooltip=tooltip, opacity=alt.condition(legendSelection, alt.value(1), alt.value(0.2)), # Use selection to control opacity ).add_params( box_selection, zoompan, legendSelection ) if lbl == 'on': text = chart.mark_text(align='left', baseline='middle',dx=15, size=13,color='black').encode(text=tooltip[0], color= alt.value('black')) else: text = chart.mark_text(align='left', baseline='middle',dx=10).encode() result = (chart + text).configure(background="#FFFFFF" ).properties( # width=800, height=700, title=title ).configure_legend( orient='bottom', labelLimit=0, titleFontSize=14, labelFontSize=14, symbolStrokeWidth=0.8 ) jchart = alt.JupyterChart(result) st.session_state["jchart"] = jchart # For getting selection of points, but does not look like this will work as the object will not get dynamically updated in session state. return result #.interactive()
可行解决思路
1. 使用Streamlit的st.altair_chart的on_select参数(Streamlit 1.28+)
Streamlit 1.28版本后新增了对Altair图表选择事件的原生支持,直接通过on_select回调获取选中数据:
- 替换原有的
st.altair_chart(generate_chart(...))调用,添加on_select参数绑定回调函数 - 在回调中解析选中的区间范围,直接筛选原始DataFrame得到选中数据
示例代码:
def handle_selection(selected_data): if selected_data and 'interval' in selected_data: # 解析框选的x、y轴范围 x_range = selected_data['interval']['x'] y_range = selected_data['interval']['y'] # 从原始数据中筛选符合范围的记录 selected_df = df[(df[xcol] >= x_range[0]) & (df[xcol] <= x_range[1]) & (df[ycol] >= y_range[0]) & (df[ycol] <= y_range[1])] st.session_state['selected_data'] = selected_df # 生成图表后绑定回调渲染 chart = generate_chart(df, xcol='your_x_column', ycol='your_y_column') st.altair_chart(chart, on_select=handle_selection) # 展示选中的数据 if 'selected_data' in st.session_state: st.subheader('选中的数据') st.dataframe(st.session_state['selected_data'])
2. 利用Altair选择状态结合按钮触发筛选
如果需要手动确认选择结果,可以保留Altair的box_selection,添加按钮触发数据筛选:
- 在图表渲染后,通过按钮点击事件,解析Altair图表的选择参数
- 用选择参数过滤原始DataFrame,结果存入
st.session_state供后续使用
3. 替换为Streamlit原生交互图表
如果对图表样式自定义要求不高,可以改用st.scatter_chart结合st.data_editor的交互能力,原生支持数据点选择与后续处理,但会损失Altair的部分样式定制功能。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

