You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pyvis添加大量边时hierarchical布局显示异常排查

pyvis三分网络分层布局失效问题

问题表现

  • 仅向网络添加配置了level层级属性的节点时,渲染效果符合分层预期
  • 当网络规模达到约300个节点、700条边时,添加全部边后所有节点被压缩排列为一条直线,分层布局完全失效;节点、边数量较少时该问题不会出现
  • 小规模场景可正常运行的测试代码如下:
from pyvis.network import Network
import networkx as nx
import matplotlib.pyplot as plt

ddd = {'a', 'b', 'c'}
ccc = {'p', 'q', 'r'}
yyy = {'x', 'y', 'z'}
edge_list_tuples = [('a', 'q'), ('b', 'p'), ('b', 'q'), ('p', 'y'), ('r', 'y'), ('r', 'z'), ('x', 'x')]
g = nx.Graph()
pyvs = Network(notebook=True, height = "100%", width = "100%", layout=True)

g.add_nodes_from(yyy, bipartite="yy")
g.add_nodes_from(ccc, bipartite="cc")
g.add_nodes_from(ddd, bipartite="dd")
g.add_edges_from(edge_list_tuples)

color_map = nx.get_node_attributes(g, "bipartite")

for key in color_map:
    if color_map[key] == "dd":
        color_map[key] = "yellow"
        lvl = 3
    if color_map[key] == "cc":
        color_map[key] = "green"
        lvl = 2
    if color_map[key] == "yy":
        color_map[key] = "blue"
        lvl = 1
    pyvs.add_node(key, color=color_map[key], level=lvl)

pyvs.add_edges(g.edges())
pyvs.show_buttons(filter_=['physics'])
pyvs.show("output_network.html")
  • 业务数据场景下可稳定复现问题的代码如下:
from pyvis.network import Network
import networkx as nx
import matplotlib.pyplot as plt
import xlrd

file = "./so-factors.xls"

ddd = set()
ccc = set()
yyy = set()
edge_list_tuples = []

book = xlrd.open_workbook(file)

sheet1 = book.sheet_by_index(0)
for row in range(sheet1.nrows-1):
    data = sheet1.row_slice(row+1)
    ddd.add(data[0].value)
    ccc.add(data[1].value)
    edge_list_tuples.append((data[0].value, data[1].value))

sheet2 = book.sheet_by_index(1)
for row in range(sheet2.nrows-1):
    data = sheet2.row_slice(row+1)
    ccc.add(data[0].value)
    yyy.add(data[1].value)
    edge_list_tuples.append((data[0].value, data[1].value))

g = nx.Graph()
pyvs = Network(notebook=True, height = "100%", width = "100%", layout=True)

g.add_nodes_from(yyy, bipartite="yy")
g.add_nodes_from(ccc, bipartite="cc")
g.add_nodes_from(ddd, bipartite="dd")
g.add_edges_from(edge_list_tuples)

color_map = nx.get_node_attributes(g, "bipartite")

for key in color_map:
    if color_map[key] == "dd":
        color_map[key] = "yellow"
        lvl = 3
    if color_map[key] == "cc":
        color_map[key] = "green"
        lvl = 2
    if color_map[key] == "yy":
        color_map[key] = "blue"
        lvl = 1
    pyvs.add_node(key, color=color_map[key], level=lvl)

pyvs.add_edges(g.edges())
pyvs.show_buttons(filter_=['physics'])
pyvs.show("./output-gitignore/my_output_network.html")

问题根源

  • 初始化时传入layout=True仅会让pyvis在渲染初始阶段,按照节点的level属性分配y轴初始坐标,不会锁死节点的层级位置
  • pyvis默认使用的barnesHut物理求解器没有分层约束逻辑,当节点、边数量增多后,边的弹簧拉力、节点中心引力的总强度会盖过初始位置的偏移量,把所有节点往画布中心轴线拉扯,最终挤成一条直线
  • 小规模网络下力的总强度低,初始层级坐标不会被完全拉平,因此看起来布局正常。

修复方案

在调用show()方法前追加如下配置,替换物理求解器、关闭会拉扯节点的中心引力、明确分层布局规则:

pyvs.set_options("""
{
  "layout": {
    "hierarchical": {
      "enabled": true,
      "levelSeparation": 180,
      "nodeSpacing": 100,
      "direction": "UD",
      "sortMethod": "directed"
    }
  },
  "physics": {
    "hierarchicalRepulsion": {
      "centralGravity": 0,
      "springLength": 120,
      "springConstant": 0.01,
      "nodeDistance": 130,
      "damping": 0.1
    },
    "solver": "hierarchicalRepulsion"
  }
}
""")

配置说明:

  • 显式开启分层布局,设置固定的层间距、同层节点间距
  • 将默认的barnesHut求解器替换为hierarchicalRepulsion,该求解器会严格遵守节点的level属性约束,不会跨层拉扯节点
  • 将中心引力设为0,避免节点被往画布中心拖拽压缩
  • 调低边的弹簧系数,降低边对节点位置的拉扯强度
  • 上述参数中的间距、弹簧系数可以根据实际节点大小、显示需求微调,只要保持求解器为hierarchicalRepulsion、中心引力为0,就不会出现节点被压成直线的问题。

内容的提问来源于stack exchange,提问作者Rys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:48:18