如何在Bokeh的NetworkX图中设置节点网格状自定义布局?
问题描述
我想创建类似元素周期表的网格状矩形元素,同时部分元素需要像图节点那样相互连接。我尝试用Bokeh结合NetworkX创建图,但没法设置节点的静态位置,测试代码如下:
import networkx as nx from bokeh.io import save, output_file, show from bokeh.models import Rect, MultiLine, Plot from bokeh.models import HoverTool from bokeh.models.graphs import NodesAndLinkedEdges from bokeh.plotting import from_networkx # Create Graph with seperate adding edges G = nx.MultiGraph() G.add_edge(1, 2) G.add_edge(2, 3) G.add_node(4) # Create Graph with edge_list G = nx.MultiGraph() edge_list = [(1,2), (2,3), (2,4), (1,3)] G.add_edges_from(edge_list) G.add_nodes_from((5,6,7,8,9,10)) # create plot plot = Plot(width = 1200,height = 900) plot.add_tools(HoverTool(tooltips=[("Index", "@index")])) # create graph with spring_layout network_graph = from_networkx(G, nx.spring_layout, scale=3.4, center=(0,0)) # nodes # test with x=10 and y=10, to set custom position network_graph.node_renderer.glyph = Rect(x=10,y=10,width=0.3, height=0.2, fill_color='skyblue') network_graph.node_renderer.hover_glyph = Rect(width=0.3, height=0.2, fill_color='navy') # edges network_graph.edge_renderer.glyph = MultiLine(line_width=3, line_color="lightgray", line_alpha=1.0) network_graph.edge_renderer.hover_glyph = MultiLine(line_width=5, line_color="darkblue", line_alpha=1.0) network_graph.inspection_policy = NodesAndLinkedEdges() plot.renderers.append(network_graph) output_file("graph_test.html") save(plot) show(plot)
请问如何为NetworkX图中的节点设置自定义位置,使其像元素周期表示例那样排列?
解决方案
要实现节点的自定义网格布局,核心是手动指定每个节点的坐标,并替换掉自动布局算法,具体步骤如下:
定义节点位置字典
创建一个字典,键是节点ID,值是对应的(x,y)坐标,按照周期表的网格规则排列,比如:# 自定义网格位置,示例按2行5列排列 node_positions = { 1: (0, 1), 2: (1, 1), 3: (2, 1), 4: (3, 1), 5: (4, 1), 6: (0, 0), 7: (1, 0), 8: (2, 0), 9: (3, 0), 10: (4, 0) }使用自定义布局替代自动布局
调用from_networkx时,把布局函数换成这个字典(NetworkX支持直接传入位置字典作为布局):network_graph = from_networkx(G, node_positions, scale=1, center=(0,0))这里
scale和center可以根据需要调整,让整体布局适配画布大小。修正节点渲染器的坐标绑定
之前直接把x=10,y=10写死是错误的,应该绑定数据源中的x和y字段(from_networkx会自动把位置存入节点数据源的x、y列):network_graph.node_renderer.glyph = Rect(x='x', y='y', width=0.8, height=0.8, fill_color='skyblue')调整
width和height让节点更贴合网格。
修改后的完整代码
import networkx as nx from bokeh.io import save, output_file, show from bokeh.models import Rect, MultiLine, Plot, Range1d from bokeh.models import HoverTool from bokeh.models.graphs import NodesAndLinkedEdges from bokeh.plotting import from_networkx # 创建图结构 G = nx.MultiGraph() edge_list = [(1,2), (2,3), (2,4), (1,3)] G.add_edges_from(edge_list) G.add_nodes_from((5,6,7,8,9,10)) # 定义自定义网格位置(模拟周期表布局) node_positions = { 1: (0, 1), 2: (1, 1), 3: (2, 1), 4: (3, 1), 5: (4, 1), 6: (0, 0), 7: (1, 0), 8: (2, 0), 9: (3, 0), 10: (4, 0) } # 创建画布,设置坐标轴范围适配布局 plot = Plot(width=1200, height=900, x_range=Range1d(-1, 5), y_range=Range1d(-1, 2)) plot.add_tools(HoverTool(tooltips=[("节点索引", "@index")])) # 使用自定义位置创建图 network_graph = from_networkx(G, node_positions, scale=1, center=(0,0)) # 配置节点样式 network_graph.node_renderer.glyph = Rect(x='x', y='y', width=0.8, height=0.8, fill_color='skyblue', line_color='black') network_graph.node_renderer.hover_glyph = Rect(x='x', y='y', width=0.8, height=0.8, fill_color='navy', line_color='black') # 配置边样式 network_graph.edge_renderer.glyph = MultiLine(line_width=3, line_color="lightgray", line_alpha=1.0) network_graph.edge_renderer.hover_glyph = MultiLine(line_width=5, line_color="darkblue", line_alpha=1.0) network_graph.inspection_policy = NodesAndLinkedEdges() plot.renderers.append(network_graph) output_file("periodic_graph.html") save(plot) show(plot)
关键说明
- 自定义位置字典可以完全按照周期表的行列规则设计,比如给每个节点分配对应的周期(y轴)和族(x轴)坐标。
- 画布的
x_range和y_range需要根据自定义位置调整,确保所有节点都在可视范围内。 - 节点的
width和height可以根据网格密度调整,避免重叠。
内容的提问来源于stack exchange,提问作者scoda
相关产品推荐
相关产品推荐

