在Python3中使用NetworkX创建弯曲的边缘

时间:2018-10-01 09:47:36

标签: python matplotlib graph networkx directed-graph

我想使用networkx(如果您知道更好的框架,我也想采用其他框架)来创建一个 节点位于固定位置的抓图。同时,图形的边缘不应重叠。

我之前的代码如下:

#!/usr/bin/env python3

import networkx as nx
import matplotlib.pyplot as plt

# Graph data
names = ['A', 'B', 'C', 'D', 'E']
positions = [(0, 0), (0, 1), (1, 0), (0.5, 0.5), (1, 1)]
edges = [('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('D', 'A')]

# Matplotlib figure
plt.figure('My graph problem')

# Create graph
G = nx.MultiDiGraph(format='png', directed=True)

for index, name in enumerate(names):
    G.add_node(name, pos=positions[index])

labels = {}
for edge in edges:
    G.add_edge(edge[0], edge[1])
    labels[(edge[0], edge[1])] = '{} -> {}'.format(edge[0], edge[1])

layout = dict((n, G.node[n]["pos"]) for n in G.nodes())
nx.draw(G, pos=layout, with_labels=True, node_size=300)
nx.draw_networkx_edge_labels(G, layout, edge_labels=labels)

plt.show()

并给出以下结果

enter image description here

如何确保边缘是“圆角的”,以免边缘重叠?

4 个答案:

答案 0 :(得分:3)

我认为您不能直接使用networkx函数来执行此操作。但是您可以直接使用已计算的节点位置来使用matplotlib。

修改您的代码:

 import networkx as nx
import matplotlib.pyplot as plt

# Graph data
names = ['A', 'B', 'C', 'D', 'E']
positions = [(0, 0), (0, 1), (1, 0), (0.5, 0.5), (1, 1)]
edges = [('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('D', 'A')]

# Matplotlib figure
plt.figure('My graph problem')

# Create graph
G = nx.MultiDiGraph(format='png', directed=True)

for index, name in enumerate(names):
    G.add_node(name, pos=positions[index])

labels = {}




layout = dict((n, G.node[n]["pos"]) for n in G.nodes())
nx.draw(G, pos=layout, with_labels=True, node_size=300)
ax = plt.gca()
for edge in edges:
    ax.annotate("",
                xy=layout[edge[0]], xycoords='data',
                xytext=layout[edge[1]], textcoords='data',
                arrowprops=dict(arrowstyle="->", color="0.5",
                                shrinkA=5, shrinkB=5,
                                patchA=None, patchB=None,
                                connectionstyle="arc3,rad=-0.3",
                                ),
                )
plt.show()

礼物:

enter image description here

另请参阅this

答案 1 :(得分:1)

正如Paul所提到的,尽管FancyArrowPatch仅在有向图上运行而且非常慢,但现在可以在draw_networkx_edges中使用bezier

对于它的价值,我打包了一些我以前使用的代码,这些代码使用view包从NetworkX图(或实际上是任何边缘列表)生成漂亮的弯曲边缘,并绘制它们。可能会有用:https://github.com/beyondbeneath/bezier-curved-edges-networkx

使用SNAP Facebook数据集和ForceAtlas2布局对图像进行采样:

enter image description here

答案 2 :(得分:1)

在其他NetworkX新闻中,您现在可以为connectionstyle指定一个nx.draw_networkx_edges参数。例如,如果我想要一个具有弯曲边缘的网络,我可以这样写:

# Compute position of nodes
pos = nx.kamada_kawai_layout(G)

# Draw nodes and edges
nx.draw_networkx_nodes(G, pos)
nx.draw_networkx_edges(
    G, pos,
    connectionstyle="arc3,rad=0.1"  # <-- THIS IS IT
)

使边缘更加弯曲,只需增加“ rad = x”的x。

注意:代码不会生成带有所有颜色和箭头的图形,为此需要更多代码。

答案 3 :(得分:0)

<块引用>

图的边不应该重叠

使用 connectionstyle 参数绘制具有预定曲率的弧不会减少边-边或节点-边重叠。

对于直边,与其他情节元素的重叠通常是不可避免的。但是,如果允许绘制弯曲的边,我们可以对每条边进行布线,使其尽可能避开其他节点和边。这种效果可以通过在每条边中插入控制点来实现,有效地将每条边分割成短的子边。然后我们可以使用标准的 Fruchterman-Reingold 算法(在 spring_layout 中称为 networkx)将图模拟为一个弹簧系统,其中所有节点和控制点相互排斥,但连接的节点和控制点也互相吸引。 (原始)节点的位置保持固定,而我们让边缘控制点的位置退火到它们的平衡位置。

我已经实现了这种方法 here。该代码是名为 netgraph 的 Python 网络绘图库的一部分,我是其中的作者。 netgraph 与 networkx 和 igraph Graph 对象完全兼容,因此应该可以轻松快速地生成美观的图形。

enter image description here

#!/usr/bin/env python
import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph # pip install netgraph

g = nx.florentine_families_graph()
Graph(g, edge_layout='curved')
plt.show()