如何基于ColumnDataSource的值通过函数绘制Bokeh Glyph?
问题描述
希望利用ColumnDataSource中的值通过函数计算后绘制Glyph,而非直接使用原始值。以拖拽点场景为例:拖拽第一个点时,第二个点会按照自定义函数(如(2x, 2y))随之移动。现有代码仅能实现两个点坐标完全相同,尝试多种写法均无效,求正确实现方式。
解决方案
要实现这个需求,核心是监听原始数据源的变化,实时通过前端逻辑计算新坐标并联动更新第二个点的位置。以下是具体实现方案:
实现思路
- 维护两个
ColumnDataSource:一个用于存储可拖拽的原始点数据,另一个用于存储计算后的点坐标。 - 通过
CustomJS编写计算逻辑,监听原始数据源的data变化事件,实时执行自定义函数计算新坐标,并更新第二个数据源。 - 将两个数据源分别绑定到对应的Glyph组件,实现拖拽时的联动效果。
完整代码
from bokeh.plotting import figure, show from bokeh.models import PointDrawTool, ColumnDataSource, Circle, CustomJS # 创建绘图对象,扩大坐标范围以容纳计算后的点 p = figure(x_range=(0, 20), y_range=(0, 20), tools=[], title='拖拽点联动示例') # 原始可拖拽点的数据源 source = ColumnDataSource({'x': [1], 'y': [1], 'color': ['red']}) # 存储计算后点的数据源,初始化时先计算一次初始值 computed_source = ColumnDataSource({'x': [2*1], 'y': [2*1]}) # 绘制原始可拖拽点 renderer = p.scatter(x='x', y='y', source=source, color='color', size=10) # 绘制计算后的半透明蓝色点 p.add_glyph(computed_source, Circle(x='x', y='y', size=30, color='blue', alpha=0.5)) # 编写前端回调逻辑,实现自定义计算函数 callback = CustomJS(args=dict(source=source, computed=computed_source), code=""" const raw_data = source.data; const computed_data = computed.data; // 自定义计算逻辑:这里实现(2x, 2y),可替换为任意f(x,y)、g(x,y) computed_data.x = raw_data.x.map(x => 2 * x); computed_data.y = raw_data.y.map(y => 2 * y); // 通知Bokeh数据源已更新 computed.change.emit(); """) # 绑定回调到原始数据源的变化事件 source.js_on_change('data', callback) # 添加拖拽工具并设为激活状态 draw_tool = PointDrawTool(renderers=[renderer], empty_value='black') p.add_tools(draw_tool) p.toolbar.active_tap = draw_tool show(p)
通用扩展
如果需要实现任意自定义函数f(x,y)和g(x,y),只需修改CustomJS中的计算逻辑即可。例如要实现(x+y, x-y)的联动效果,将计算部分替换为:
computed_data.x = raw_data.x.map((x, index) => x + raw_data.y[index]); computed_data.y = raw_data.x.map((x, index) => x - raw_data.y[index]);
注意:Bokeh的前端交互逻辑依赖JavaScript,因此计算函数需用JS编写。如果必须使用Python函数处理复杂逻辑,可结合Bokeh Server实现,但对于简单交互,前端CustomJS更轻量高效。
内容的提问来源于stack exchange,提问作者emj
相关产品推荐
相关产品推荐

