Altair分层图表多下拉筛选时出现重复信号名JS错误
解决Altair分层图表中重复信号名的JavaScript错误
问题场景
需要通过多个下拉菜单切换查看不同日期的预测区间与物品实际价格,单个图表可正常渲染,但使用alt.layer()合并图表后,触发**Javascript Error: Duplicate signal name: "History__tuple"**错误。
原问题代码
run_list = list(results.runs.unique()) datas = list(results.dataDays.unique()) looks = list(results.looks.unique()) dates = list(results.date.unique()) date_dropdown = alt.binding_select(options=dates) date_select = alt.selection_single(bind=date_dropdown, fields=['date'], name="Day") look_dropdown = alt.binding_select(options=looks) look_select = alt.selection_single(bind=look_dropdown, fields=['looks'], name="Back Forward_") data_dropdown = alt.binding_select(options=datas) data_select = alt.selection_single(fields=['dataDays'], bind=data_dropdown, name="History:") run_dropdown = alt.binding_select(options=run_list) run_select = alt.selection_single(fields=['runs'], bind=run_dropdown, name="Variation:") domain = [True, False] range_ = ['#858987', '#C62B0A'] base_sp = alt.Chart(results, width=835, height=500 ).encode( x=alt.X('hoursminutes(endtime)', title='Time of Day') ) diff_viz = base_sp.mark_point(filled=True, opacity=0.7 ).encode( y=alt.Y('open', title= 'StockPrice', scale=alt.Scale(zero=False)), tooltip=['hoursminutes(endtime)','open','looks','runs','dataDays'], color = alt.Color('bound_check', scale=alt.Scale(domain=domain, range=range_),title='In/Out Bounds') ).add_selection( data_select, look_select, run_select, date_select ).transform_filter( look_select ).transform_filter( data_select ).transform_filter( run_select ).transform_filter( date_select ).properties(title="Prediction Interval + True StockPrice") upp_intervals = base_sp.mark_line( opacity=0.5, strokeDash=[1,2], color='#3655C7', interpolate='monotone' ).encode( alt.Y('upper', scale = alt.Scale(zero=False)), tooltip=['upper'] ).add_selection( data_select, look_select, run_select, date_select ).transform_filter( look_select ).transform_filter( data_select ).transform_filter( run_select ).transform_filter( date_select ) alt.layer(upp_intervals, diff_viz)
错误原因
diff_viz和upp_intervals两个子图表中重复添加了相同的选择器(data_select、look_select等)和过滤条件。当用alt.layer()合并时,这些选择器会被重复注册到Vega的信号系统中,导致生成重复的信号名称(如History__tuple),触发JavaScript错误。
修复方案
将选择器和过滤逻辑统一移到alt.layer()层面,子图表仅保留可视化相关配置,避免重复注册选择器:
run_list = list(results.runs.unique()) datas = list(results.dataDays.unique()) looks = list(results.looks.unique()) dates = list(results.date.unique()) # 创建下拉选择器 date_dropdown = alt.binding_select(options=dates) date_select = alt.selection_single(bind=date_dropdown, fields=['date'], name="Day") look_dropdown = alt.binding_select(options=looks) look_select = alt.selection_single(bind=look_dropdown, fields=['looks'], name="Back Forward_") data_dropdown = alt.binding_select(options=datas) data_select = alt.selection_single(fields=['dataDays'], bind=data_dropdown, name="History:") run_dropdown = alt.binding_select(options=run_list) run_select = alt.selection_single(fields=['runs'], bind=run_dropdown, name="Variation:") domain = [True, False] range_ = ['#858987', '#C62B0A'] # 基础图表配置(共享x轴等通用设置) base_sp = alt.Chart(results, width=835, height=500 ).encode( x=alt.X('hoursminutes(endtime)', title='Time of Day') ) # 实际价格点图:仅保留可视化配置 diff_viz = base_sp.mark_point(filled=True, opacity=0.7 ).encode( y=alt.Y('open', title= 'StockPrice', scale=alt.Scale(zero=False)), tooltip=['hoursminutes(endtime)','open','looks','runs','dataDays'], color = alt.Color('bound_check', scale=alt.Scale(domain=domain, range=range_),title='In/Out Bounds') ).properties(title="Prediction Interval + True StockPrice") # 预测区间上线:仅保留可视化配置 upp_intervals = base_sp.mark_line( opacity=0.5, strokeDash=[1,2], color='#3655C7', interpolate='monotone' ).encode( alt.Y('upper', scale = alt.Scale(zero=False)), tooltip=['upper'] ) # 在layer层面统一添加选择器和过滤条件 alt.layer(upp_intervals, diff_viz).add_selection( data_select, look_select, run_select, date_select ).transform_filter( look_select ).transform_filter( data_select ).transform_filter( run_select ).transform_filter( date_select )
测试用例验证
你提供的测试用例写法是正确的——仅在alt.layer()层面添加选择器和过滤,因此不会触发重复信号错误:
import vega_datasets as vd df = vd.data.climate() df['date'] = [str(x.date()) for x in df['DATE']] dates = list(df.date.unique()) date_dropdown = alt.binding_select(options=dates) date_select = alt.selection_single(bind=date_dropdown, fields=['date'], name="Day") base = alt.Chart(df, width=835, height=500 ).encode( x=alt.X('hoursminutes(DATE)', title='Time of Day') ) temps = base.mark_point(filled=True, opacity=0.7, color='#0766B4', interpolate='monotone' ).encode( y=alt.Y('HLY-TEMP-NORMAL', title= 'Hourly Temps', scale=alt.Scale(zero=False)), tooltip=['hoursminutes(DATE)','HLY-TEMP-NORMAL'], ) dews = base.mark_point( opacity=0.7, filled=True, color='#228006', interpolate='monotone' ).encode( alt.Y('HLY-DEWP-NORMAL', title='Hourly Dew Point', scale = alt.Scale(zero=False)), tooltip=['hoursminutes(DATE)', 'HLY-DEWP-NORMAL'] ) chart = alt.layer(temps, dews).add_selection( date_select ).transform_filter( date_select )
内容的提问来源于stack exchange,提问作者GN_nick
相关产品推荐
相关产品推荐

