如何在Bokeh multi_line图中隐藏单条线并实现单条线选择?
我来帮你搞定这个Bokeh的多线交互问题!你遇到的multi_line无法单独选线、大量p.line性能拉胯的情况很常见,咱们可以用数据源管理+JS回调的方式完美解决,既保留multi_line的高性能,又能实现单条线选择和隐藏功能。
完整实现代码
import pandas as pd import numpy as np from bokeh.palettes import Spectral11 from bokeh.plotting import figure, show, output_file from bokeh.models import ColumnDataSource, TapTool, CustomJS, CheckboxGroup from bokeh.layouts import column output_file('multi_line_interactive.html') # 生成完整测试数据 dates = pd.date_range(start='2023-01-01', periods=5) toy_df = pd.DataFrame(data=np.random.rand(5,3), columns=('a', 'b', 'c'), index=dates) # 构造multi_line专用的数据源,新增控制字段 xs = [toy_df.index.to_list()] * len(toy_df.columns) ys = [toy_df[col].to_list() for col in toy_df.columns] colors = Spectral11[:len(toy_df.columns)] source = ColumnDataSource(data={ 'xs': xs, 'ys': ys, 'colors': colors, 'visible': [True]*len(toy_df.columns), # 控制线条是否显示 'selected': [False]*len(toy_df.columns) # 控制线条是否被选中 }) # 创建绘图对象 p = figure(x_axis_type="datetime", title="Interactive Multi-Line Chart", width=800, height=400) # 绘制multi_line,绑定动态样式和可见性 multi_line_renderer = p.multi_line( 'xs', 'ys', source=source, line_color='colors', # 用selected字段动态切换线条宽度,区分选中状态 line_width={'field': 'selected', 'transform': {'type': 'factor_cmap', 'factors': [True, False], 'palette': [4, 2]}}, visible='visible' # 绑定可见性控制字段 ) # 1. 实现单条线点击选择功能 tap_tool = TapTool(renderers=[multi_line_renderer], behavior='select') p.add_tools(tap_tool) # 自定义JS回调:点击时切换对应线条的选中状态 select_callback = CustomJS(args=dict(source=source), code=""" const indices = source.selected.indices; const selected = source.data.selected; // 清空所有之前的选中状态 for (let i=0; i<selected.length; i++) { selected[i] = false; } // 标记当前点击的线条为选中 if (indices.length > 0) { selected[indices[0]] = true; } source.change.emit(); """) source.selected.js_on_change('indices', select_callback) # 2. 实现线条显示/隐藏功能 checkbox_group = CheckboxGroup( labels=toy_df.columns.tolist(), active=list(range(len(toy_df.columns))), # 默认全部显示 width=200 ) # 绑定CheckboxGroup的JS回调,更新visible字段 hide_callback = CustomJS(args=dict(source=source, checkbox=checkbox_group), code=""" const visible = source.data.visible; const active = checkbox.active; // 先将所有线条设为隐藏 for (let i=0; i<visible.length; i++) { visible[i] = false; } // 将选中的Checkbox对应的线条设为显示 for (let i=0; i<active.length; i++) { visible[active[i]] = true; } source.change.emit(); """) checkbox_group.js_on_change('active', hide_callback) # 组合控件与图表并展示 show(column(checkbox_group, p))
关键功能说明
- 高性能保障:全程使用
multi_line渲染,Bokeh会批量处理线条的绘制逻辑,比几百条单独的p.line快数倍 - 单条线选择:通过
TapTool捕获点击事件,JS回调更新数据源的selected字段,再通过factor_cmap动态调整选中线条的宽度(你也可以改成颜色变化,比如把选中线条设为红色) - 线条隐藏/显示:
CheckboxGroup的勾选状态直接关联数据源的visible字段,multi_line会自动根据该字段控制线条是否渲染,无需重绘整个图表 - 可扩展性:如果后续需要添加更多交互(比如右键菜单、双击事件),只需在数据源中新增对应控制字段,再编写JS回调即可
内容的提问来源于stack exchange,提问作者Guido
相关产品推荐
相关产品推荐

