使用Bokeh绘制网络图时StaticLayoutProvider验证失败求助
参考示例绘制网络图时,运行代码出现类型验证错误,具体代码如下:
data = { 'source': ['A', 'C', 'B', 'F', 'G'], 'target': ['B', 'D', 'E', 'C', 'E'], 'weight': [5, 3, 10, 4, 7] } df = pd.DataFrame(data=data) G = networkx.from_pandas_edgelist(df, 'source', 'target', 'weight') # Choose a title! title = 'Graph Network' # Establish which categories will appear when hovering over each node HOVER_TOOLTIPS = [("Character", "@index")] # Create a plot — set dimensions, toolbar, and title plot = figure(tooltips=HOVER_TOOLTIPS, tools="pan,wheel_zoom,save,reset", active_scroll='wheel_zoom', x_range=Range1d(-10.1, 10.1), y_range=Range1d(-10.1, 10.1), title=title) network_graph = from_networkx(G, networkx.spring_layout, scale=10, center=(0, 0)) # Set node size and color network_graph.node_renderer.glyph = Circle(size=15, fill_color='skyblue') # Set edge opacity and width network_graph.edge_renderer.glyph = MultiLine(line_alpha=0.5, line_width=1) # Add network graph to the plot plot.renderers.append(network_graph) return plot
运行时报错:
failed to validate StaticLayoutProvider(id='p1075', ...).graph_layout: expected an
element of Dict(Int, Seq(Any)), got {'A': array([-7.94707039, 3.45521447]), 'B':
array([-6.60505319, 4.31869148]), 'C': array([ 8.38746457, -6.26423001]), 'D':
array([ 6.7178286 , -6.63523276]), 'E': array([-5.66671517, 5.25260372]), 'F':
array([10. , -6.53836091]), 'G': array([-4.88645443, 6.41131401])}
错误提示期望Dict(Int, Seq(Any))类型的graph_layout,但实际传入了字符串作为键。使用整数节点ID时可正常绘制,当前使用版本:networkx~=2.8.8、bokeh==3.0.3。
这是Bokeh 3.x版本的兼容性问题,在Bokeh 3.0+中,from_networkx生成的布局默认要求节点ID为整数。可通过以下方式解决:
方法1:映射字符串节点为整数ID并保留显示名称
这是最通用的解决方案,适用于任何字符串节点名:
- 为字符串节点分配唯一整数ID,重建带节点属性的图:
# 获取所有唯一节点 nodes = list(G.nodes()) node_id_map = {node: idx for idx, node in enumerate(nodes)} # 构建带整数ID的图,保留边权重属性 G_int = networkx.Graph() for u, v, attrs in G.edges(data=True): G_int.add_edge(node_id_map[u], node_id_map[v], **attrs) # 给整数节点添加原始名称属性 for node in nodes: G_int.nodes[node_id_map[node]]['name'] = node
- 调整绘图代码,使用新图并修改hover提示显示原始名称:
HOVER_TOOLTIPS = [("Character", "@name")] plot = figure(tooltips=HOVER_TOOLTIPS, tools="pan,wheel_zoom,save,reset", active_scroll='wheel_zoom', x_range=Range1d(-10.1, 10.1), y_range=Range1d(-10.1, 10.1), title=title) network_graph = from_networkx(G_int, networkx.spring_layout, scale=10, center=(0, 0)) # 将原始名称传入节点数据源,用于hover显示 network_graph.node_renderer.data_source.data['name'] = [G_int.nodes[n]['name'] for n in G_int.nodes]
方法2:降级Bokeh到2.x版本
如果不需要Bokeh 3.x的新特性,可直接降级到支持字符串节点ID的2.x版本:
pip install bokeh==2.4.3
方法3:转换布局字典键为整数(仅特定场景适用)
仅当节点名称本身是可转换为整数的字符串时使用,比如节点名为"1""2"这类:
# 先生成布局 layout = networkx.spring_layout(G, scale=10, center=(0, 0)) # 转换键为整数 int_layout = {int(k): v for k, v in layout.items()} # 传入转换后的布局 network_graph = from_networkx(G, lambda G: int_layout, scale=10, center=(0, 0))
内容的提问来源于stack exchange,提问作者unlockme

