我正在尝试建立一个公司联系网络。主要公司位于中心。内圈是其子公司。外圈代表与子公司合作的公司。到目前为止我做了以下网络表示。
但问题来了。我希望内圈和外圈彼此靠近,换句话说,方向相同。我保留内圆的坐标,但无法根据固定内圆计算外圆的坐标。
G1 = nx.from_pandas_edgelist(layer1_edges,
source='source',
target='target',
create_using=nx.MultiDiGraph())
pos1 = nx.circular_layout(G1, scale=200, center=(0, 0))
pos1["centered_node"] = np.array([0.0, 0.0])
G2 = nx.from_pandas_edgelist(layer2_edges,
source='source',
target='target',
create_using=nx.MultiDiGraph())
pos2 = nx.circular_layout(G2, scale=300, center=(0, 0))
F = nx.compose(G1, G2)
pos_f = pos1.copy()
for name, pos in pos2.items():
if name not in pos_f:
pos_f[name] = pos
以下答案假设您要解决的问题是连接的节点通常彼此距离不近。
看起来您有一个多方网络,并且正在尝试使用 shell 布局来绘制该网络。 NetworkX 确实实现了shell 布局。 但是,此函数没有实现边缘交叉减少或任何其他技术,以使连接的节点在可视化中彼此靠近。
由于 graph-tool 的 igraph 似乎都没有实现 shell 布局,因此您唯一的选择可能是 Netgraph,一个我编写和维护的库。 Netgraph 支持各种节点布局的边交叉减少,这在分层图中通常具有将连接的节点分组在一起的效果。对于壳布局,它使用 Eades & Wormald (1994) 中提出的算法。可以在此处找到教程。可以使用以下代码创建与您类似的简单可视化:
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from itertools import product
from netgraph import InteractiveGraph
################################################################################
# SIMULATE DATA
# initialize shells
shell_sizes = [1, 20, 100]
ctr = 0
shells = []
for size in shell_sizes:
shells.append(list(range(ctr, ctr+size)))
ctr += size
# initialize edges
multipartite_edges = []
# the node in the first layer connects to all nodes in the second layer
multipartite_edges.extend(list(product(shells[0], shells[1])))
# nodes in subsequent layers only connect to a subset of nodes in the next layer
minimum_edges = 1
maximum_edges = 3
for p1, p2 in zip(shells[1:-1], shells[2:]):
for target in p2:
total_edges = np.random.randint(minimum_edges, maximum_edges, 1)
sources = np.random.choice(p1, total_edges, replace=False)
multipartite_edges.extend([(source, target) for source in sources])
graph = nx.Graph(multipartite_edges)
################################################################################
# DRAW
node_size = dict()
for node in range(ctr):
if node in shells[0]:
node_size[node] = 9
elif node in shells[1]:
node_size[node] = 3
else:
node_size[node] = 1
g = InteractiveGraph(
graph, node_layout='shell',
node_layout_kwargs=dict(shells=shells, reduce_edge_crossings=True),
node_size=node_size,
edge_width=0.5,
)
plt.show()