Bokeh中Select组件js_on_change事件无法更新网络图问题求解
问题原因
你当前代码不生效的核心原因是:你自定义的source变量和Bokeh网络图实际渲染用的数据源完全独立,你在JS回调里只更新了自己创建的source,没有同步修改网络图的边渲染数据源,所以界面不会有任何变化。另外你构建图G的时候仅过滤了初始选中列的有效边,切换选项时也没有重新过滤边集。
修复后的可运行代码
from bokeh.plotting import from_networkx, figure, show from bokeh.models import Range1d, MultiLine, Circle, HoverTool, Select, Column, CustomJS import networkx as nx import pandas as pd # 生成原始数据 d = {'weight': [1, 2,3,1,2], 'var': ["var1","var1","var1","var2", "var2"], 'source': ["a", "b","c","e","f"], 'target': ["c","g","e","a","h"]} df1 = pd.DataFrame(data=d) df2 = df1.pivot(index= ["source","target"], values = "weight", columns = "var").reset_index() df2 = df2.fillna(0) HOVER_TOOLTIPS = [("Search Term", "@index")] title = "my title" plot = figure(tooltips = HOVER_TOOLTIPS, tools="pan,wheel_zoom", active_scroll='wheel_zoom', x_range=Range1d(-10.1, 10.1), y_range=Range1d(-10.1, 10.1), title=title, plot_width=1000 ) category_default = "var1" unique_categories = ["var1","var2"] # 预先构建包含所有节点的图,固定布局避免切换列时节点位置变动 all_edges = df2[["source", "target"]].values.tolist() G_full = nx.from_edgelist(all_edges) pos = nx.spring_layout(G_full, scale=10, center=(0,0)) network_graph = from_networkx(G_full, pos) # 准备全量边数据传给JS,拿到网络图的边渲染数据源 all_edge_data = df2.to_dict("list") edge_renderer = network_graph.edge_renderer edge_source = edge_renderer.data_source select = Select(title='Category Selection', value=category_default, options=unique_categories) callback = CustomJS( args={"all_edge_data": all_edge_data, "edge_source": edge_source}, code=""" const selected_var = cb_obj.value; const sources = all_edge_data.source; const targets = all_edge_data.target; const weights = all_edge_data[selected_var]; // 过滤出weight>0的边 const new_sources = []; const new_targets = []; const new_weights = []; for (let i=0; i<sources.length; i++) { if (weights[i] > 0) { new_sources.push(sources[i]); new_targets.push(targets[i]); new_weights.push(weights[i]); } } // 直接更新边渲染数据源 edge_source.data = { start: new_sources, end: new_targets, weight: new_weights }; """) select.js_on_change("value", callback) # 配置图元素样式 network_graph.edge_renderer.glyph = MultiLine(line_alpha=0.5, line_width="weight" ) network_graph.node_renderer.glyph = Circle(size=15, fill_color="#2f7ed8") plot.renderers.append(network_graph) show(Column(plot, select))
更简便的行过滤方案
你不需要把数据透视成宽表,直接用原始的长表df1处理逻辑更简单:
- 存储的时候直接按
var字段区分不同类别 - 过滤的时候直接按
var值筛选行即可,不需要处理多列映射,后续新增类别也不需要修改数据结构。
内容的提问来源于stack exchange,提问作者linacarrillo
相关产品推荐
相关产品推荐

