基于Streamlit实现带可拖拽点的折线图需求及优化问询
实现Streamlit可拖拽点的折线图方案
你想要的是直接在折线图上拖拽点调整数值、同时将数据存入DataFrame的功能,用Altair的交互式拖拽可以完美替代当前的垂直滑块方案,操作更直观,用户体验更好。
改进后的完整代码
import streamlit as st import pandas as pd import altair as alt # 初始化数据 hours = list(range(4, 22)) values_original = [0,3,9,25,62,25,30,30,45,45,28,21,40,55,55,30,10,5,0] # 用session state保存修改后的数据,避免刷新丢失 if 'edited_values' not in st.session_state: st.session_state.edited_values = values_original.copy() # 创建DataFrame df_original = pd.DataFrame({'hours': hours, 'Values': values_original, 'Type': 'reference'}) df_edited = pd.DataFrame({'hours': hours, 'Values': st.session_state.edited_values, 'Type': 'project'}) # 创建可拖拽的Altair图表 # 定义点选择器:鼠标悬停时选中最近的点 point_selection = alt.selection_single( nearest=True, on='mouseover', fields=['hours'], empty='none' ) # 可编辑的折线+面积图 edited_chart = alt.Chart(df_edited).mark_area( opacity=0.7, interpolate='cardinal' ).encode( x=alt.X('hours', title='小时', scale=alt.Scale(domain=[4, 22])), y=alt.Y('Values:Q', title='数值'), fill=alt.Fill(field='Type', title='曲线'), tooltip=['hours', alt.Tooltip('Values', title='当前数值')] ).add_selection( point_selection ) # 拖拽点的交互:允许修改选中点的Y值 drag_handler = alt.Chart(df_edited).mark_point( size=80, fill='white', stroke='black' ).encode( x='hours:Q', y=alt.Y('Values:Q', title='数值'), ).transform_filter( point_selection ).add_selection( alt.selection_single( encodings=['y'], on='mousedown', translate=['x', 'y'], zoom=False, name='drag' ) ).transform_calculate( new_values="drag.y !== null ? drag.y : datum.Values" ) # 原始参考线 original_line = alt.Chart(df_original).mark_line( color='red', interpolate='cardinal', opacity=0.7 ).encode( x='hours:Q', y='Values:Q', tooltip=['hours', alt.Tooltip('Values', title='参考数值')] ) # 组合图表 combined_chart = (edited_chart + drag_handler + original_line).interactive() # 渲染图表 st.altair_chart(combined_chart, use_container_width=True) # 同步拖拽后的数据到session state if 'drag' in st.session_state: drag_data = st.session_state.drag if drag_data: selected_hour = drag_data['hours'][0] new_value = drag_data['new_values'][0] idx = hours.index(selected_hour) st.session_state.edited_values[idx] = round(float(new_value), 1) # 展示当前编辑后的DataFrame,供模型使用 st.subheader('当前编辑后的数据') st.dataframe(df_edited)
关键功能说明
- 拖拽交互:通过Altair的
selection_single实现点的选中和拖拽修改Y值,用户可以直接在图上拖动白色带黑边的控制点调整数值 - 数据持久化:用
st.session_state保存修改后的数值,避免Streamlit刷新后数据丢失 - 数据同步:拖拽后自动更新DataFrame,你可以直接用
df_edited或st.session_state.edited_values传入模型 - 保留参考线:红色参考线始终显示,方便对比原始数据
使用方法
- 鼠标悬停在折线的控制点上,按住鼠标拖动即可调整该点的数值
- 页面下方会实时展示编辑后的DataFrame,直接取用即可
内容的提问来源于stack exchange,提问作者Mathieu P.
相关产品推荐
相关产品推荐

