能否使用普通HTML及Vue/React组件向Bokeh绘图传递数据实现联动?
Bokeh服务端与自定义前端组件协同的可行方案
完全可以实现你要的效果,不需要局限于Bokeh自带组件,也不用额外发HTTP请求,核心思路是复用Bokeh服务端内置的WebSocket通信通道,通过JS API直接触发服务端回调,以下是具体实现方案:
方案1:桥接数据源同步方案
这是最稳定兼容性最好的方案,核心是用一个无UI的ColumnDataSource作为前后端参数传递的中间载体:
Python端配置
在你的Bokeh服务端应用中预先定义桥接数据源和对应的服务端回调:
from bokeh.models import ColumnDataSource from bokeh.server.server import Server from bokeh.plotting import figure def bokeh_app(doc): # 定义桥接数据源,添加唯一name方便前端定位 bridge_ds = ColumnDataSource( data={"selected_val": [""], "extra_payload": [{}]}, name="vue_bokeh_bridge" ) # 你的绘图逻辑示例 p = figure(title="动态更新图表", width=600, height=400) line_render = p.line(x=[1,2,3,4], y=[1,2,3,4]) # 服务端更新回调,数据源变化时自动触发 def update_chart(attr, old, new): # 直接获取前端传递过来的参数 current_val = bridge_ds.data["selected_val"][0] extra_params = bridge_ds.data["extra_payload"][0] # 这里写你的图表更新逻辑,比如修改渲染器的数据源 new_y = [i*int(current_val) for i in [1,2,3,4]] line_render.data_source.data["y"] = new_y # 监听桥接数据源的变化 bridge_ds.on_change("data", update_chart) # 把图表和桥接数据源都加入文档 doc.add_root(p) doc.add_root(bridge_ds) # 启动服务的逻辑你可以保留原有配置 server = Server({'/': bokeh_app}, port=5006) server.start()
Vue/React端配置
在你的前端组件事件中,直接调用Bokeh暴露在全局的JS API修改桥接数据源即可,Bokeh会自动把变更同步到服务端触发回调:
// Vue组件选择事件示例 const handleSelect = async (selectedValue) => { // 获取当前页面加载的Bokeh文档实例 const bokehDoc = window.Bokeh.documents[0] // 定位到我们预先定义的桥接数据源 const bridgeDS = bokehDoc.get_model_by_name("vue_bokeh_bridge") // 修改数据源,自动触发服务端回调 bridgeDS.data = { selected_val: [selectedValue], extra_payload: [{ user_id: "123", filter: "xxx" }] } }
方案2:自定义事件触发方案
如果你不想额外维护桥接数据源,可以用Bokeh的自定义事件机制实现更轻量的调用:
Python端配置
from bokeh.events import Event from bokeh.server.server import Server from bokeh.plotting import figure # 定义自定义事件 class VueTriggerEvent(Event): event_name = "vue_trigger" def __init__(self, selected_val, extra_payload): self.selected_val = selected_val self.extra_payload = extra_payload def bokeh_app(doc): p = figure(title="动态更新图表", width=600, height=400) line_render = p.line(x=[1,2,3,4], y=[1,2,3,4]) # 自定义事件处理回调 def handle_vue_event(event): current_val = event.selected_val extra_params = event.extra_payload new_y = [i*int(current_val) for i in [1,2,3,4]] line_render.data_source.data["y"] = new_y # 注册事件监听 doc.on_event(VueTriggerEvent, handle_vue_event) doc.add_root(p)
前端调用
const handleSelect = async (selectedValue) => { const bokehDoc = window.Bokeh.documents[0] // 直接触发自定义事件,参数会自动同步到Python端 bokehDoc.send_event("vue_trigger", { selected_val: selectedValue, extra_payload: { user_id: "123", filter: "xxx" } }) }
注意事项
- 以上方案都依赖Bokeh服务端的运行环境,不能用于静态导出的Bokeh图表
- 如果页面嵌入了多个Bokeh应用,可通过
window.Bokeh.documents数组的下标区分不同应用的文档实例 - 所有传递的参数需要满足JSON可序列化要求
内容的提问来源于stack exchange,提问作者Eduardo Rios
相关产品推荐
相关产品推荐

