如何用Bokeh TapTool点击散点触发对应Thing实例的plot方法生成新图
实现方案
可行性说明
- 直接调用
Thing.plot生成新图的方案完全可行,你的场景下依托Bokeh Server的服务端回调机制即可实现,无需将复杂计算逻辑迁移到前端。 - 预生成所有
Thing.plot实例、点击直接展示的方案也可实现,和前者的实现逻辑几乎一致,仅回调逻辑有少量差异,适合Thing实例数量可控的场景,点击响应速度更快。
具体实现(动态调用Thing.plot版本)
该实现基于Bokeh Server,运行方式为将代码保存为demo.py后执行bokeh serve --show demo.py。
from bokeh.plotting import figure, show from bokeh.models import TapTool, ColumnDataSource from bokeh.layouts import column from bokeh.io import curdoc class Thing: def __init__(self, foo, bar, baz): self.foo = foo self.bar = bar self.baz = baz def plot(self): # 绘制当前Thing实例的全量数据,可保留你的复杂计算逻辑 fig = figure(width=400, height=300, title=f"当前实例属性详情") fig.circle([1,2,3], [self.foo, self.bar, self.baz], size=10) return fig class Collection: def __init__(self, things): self.things = things # 如果用预生成方案,可在这里提前生成所有plot实例 # self.pre_plots = [thing.plot() for thing in self.things] def plot(self, x, y): # 构造带索引的数据源,用于点击后匹配对应Thing实例 xdata = [getattr(th, x) for th in self.things] ydata = [getattr(th, y) for th in self.things] index_data = list(range(len(self.things))) source = ColumnDataSource(data={ x: xdata, y: ydata, "index": index_data }) # 配置绘图参数 title = '{} v {}'.format(x, y) fig = figure(title=title, tools=['pan', 'tap', 'box_zoom', 'reset'], width=600, height=400) fig.circle(x=x, y=y, source=source, size=12) # 点击回调逻辑 def on_point_click(attr, old, new): if not new: return # 拿到选中点的索引 selected_idx = new[0] # 动态调用Thing.plot detail_fig = self.things[selected_idx].plot() # 预生成方案替换为下面的代码即可 # detail_fig = self.pre_plots[selected_idx] # 更新页面布局,在散点图下方展示详情图 layout.children = [layout.children[0], detail_fig] # 绑定选中事件回调 source.selected.on_change('indices', on_point_click) return fig # 初始化测试数据 A = Thing(2, 4, 6) B = Thing(3, 6, 9) C = Thing(7, 2, 5) D = Thing(9, 2, 1) X = Collection([A, B, C, D]) scatter_fig = X.plot('foo', 'baz') # 初始化页面布局 layout = column(scatter_fig) curdoc().add_root(layout)
注意事项
- 该实现必须运行在Bokeh Server环境下,因为需要执行Python端的计算逻辑,纯静态导出的HTML无法触发Python方法调用。
- 如果需要点击后弹出独立窗口展示详情图,可在回调中使用
bokeh.models.widgets.Div插入打开新窗口的JS代码,将详情图渲染到新窗口即可。
内容的提问来源于stack exchange,提问作者Joe Flip
相关产品推荐
相关产品推荐

