Bokeh如何实现跨图表联动高亮同名折线
跨图表同名折线同步悬停加粗实现方案
Bokeh默认的hover_line_width仅作用于当前触发交互的单个图形元素,要实现跨图表同步修改样式,需要自定义JS回调绑定鼠标事件,全局控制同名折线的样式。
完整修改后代码
import random import bokeh.io import bokeh.palettes import bokeh.layouts import bokeh.plotting from bokeh.models import CustomJS months = list(range(12)) quarters = list(range(4)) sales = { 'alice': [random.randint(0,100) for _ in months], 'bob': [random.randint(0,100) for _ in months], } ratings = { 'alice': [random.randint(0,5) for _ in quarters], 'bob': [random.randint(0,5) for _ in quarters], } TOOLS = 'hover' f1 = bokeh.plotting.figure(title='sales', plot_height=200, tools=TOOLS) # 保存折线对象引用 line1_alice = f1.line(months, sales['alice'], name='alice', line_width=1) line1_bob = f1.line(months, sales['bob'], name='bob', line_width=1) f2 = bokeh.plotting.figure(title='ratings', plot_height=200,tools=TOOLS) line2_alice = f2.line(quarters, ratings['alice'], name='alice', line_width=1) line2_bob = f2.line(quarters, ratings['bob'], name='bob', line_width=1) # 构造名称到折线对象的映射,方便回调中批量修改 line_map = { 'alice': [line1_alice, line2_alice], 'bob': [line1_bob, line2_bob] } # 悬停触发回调 hover_callback = CustomJS(args=dict(line_map=line_map), code=""" // 获取当前触发悬停的折线名称 const current_name = cb_obj.name; // 同步修改所有同名折线的线宽为加粗样式 line_map[current_name].forEach(line => line.line_width = 3); """) # 离开触发回调 leave_callback = CustomJS(args=dict(line_map=line_map), code=""" const current_name = cb_obj.name; // 同步恢复所有同名折线的默认线宽 line_map[current_name].forEach(line => line.line_width = 1); """) # 给所有折线绑定鼠标事件 for line in [line1_alice, line1_bob, line2_alice, line2_bob]: line.on_event('mouseenter', hover_callback) line.on_event('mouseleave', leave_callback) bokeh.io.show(bokeh.layouts.gridplot([[f1],[f2]]))
关键改动说明
- 移除了原生的
hover_line_width配置,改为手动控制折线的line_width属性 - 保存了所有折线的对象引用,构造了名称到对应折线列表的映射关系
- 编写了两个JS回调分别处理鼠标悬停、离开事件,回调中会批量修改所有同名折线的样式
- 给所有折线绑定对应的鼠标事件,确保任意一张图的折线触发交互都会全局同步样式
该实现完全兼容Bokeh 2.3.3版本。
内容的提问来源于stack exchange,提问作者Rocket
相关产品推荐
相关产品推荐

