【问题标题】:Creating curved edges with NetworkX in Python3在 Python3 中使用 NetworkX 创建弯曲边缘
【发布时间】:2018-10-01 09:47:36
【问题描述】:

我想使用 networkx(如果您知道更好的框架,我也想采用另一个框架)来创建一个 节点在固定位置的graps。同时图的边不能重叠。

我之前的代码是这样的:

#!/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()

并给出以下结果

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

【问题讨论】:

  • 对不起,这里帮不上忙;以下 setup.py 会导致您的代码出现段错误。 cairocffi==0.9.0 cffi==1.11.5 cycler==0.10.0 decorator==4.3.0 kiwisolver==1.0.1 matplotlib==3.0.0 networkx==2.2 numpy==1.15.2 pgi==0.0 .11.2 pycparser==2.19 pyparsing==2.2.2 python-dateutil==2.7.3 Six==1.11.0 你介意分享你的吗?
  • 评论格式最差-.-'
  • 只需执行 pip install networkx && pip install matplotlib
  • 谢谢,我猜是好意思。但不是我需要的。我之前做了你的建议,它缺少几个依赖项。安装它们后,我遇到了段错误。这不是我想要调试的,所以如果你可以复制你正在成功使用的 setup.py,那么有人可能会帮助你而不会遇到与我相同的问题。当您使用它时,您使用的是哪个特定的 python 版本? 3.5、3.6 还是 3.7?
  • AFAIK,目前无法使用networkx 绘制具有弯曲边缘的图形,尽管修改源代码不会太困难。 networkx 使用 matplotlib 中的 FancyArrowPatch 类在 draw_networkx_edges(由 draw 包装)中绘制箭头。 FancyArrowPatch 支持connectionstyle 参数,该参数不是由draw_networkx_edges 设置的;默认是一条直线,这就是你现在得到的。鉴于您的 MWE 的质量,我怀疑您将设法克隆 networkx github 存储库,并修补 draw_networkx_edges

标签: python matplotlib graph networkx directed-graph


【解决方案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即可。

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

【讨论】:

  • 我还应该说,出于某种原因,这似乎只在边缘被定向时才有效。这肯定是一个错误,当一些体面的人提出问题并在github.com/networkx/networkx上进行 PR 时可能会得到修复@
  • 如果 G 是定向的(至少在 v.2.5 中),它也适用于 G.draw
【解决方案2】:

我认为您不能直接使用 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()

给予:

另见this

【讨论】:

  • 刚刚试了一下 Colab,结果证明MultiDiGraph 的实现已经改变。我必须在以下行中使用nodes(复数)而不是nodelayout = dict((n, G.nodes[n]["pos"]) for n in G.nodes())
【解决方案3】:

图形的边缘不应重叠

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

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

我有这种方法here 的实现。该代码是名为 netgraph 的 python 网络绘图库的一部分,我是该库的作者。 netgraph 与 networkx 和 igraph Graph 对象完全兼容,因此生成好看的图形应该是容易和快速的。

#!/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()

【讨论】:

  • 很棒的图书馆!精美的文档。期待使用它。
【解决方案4】:

正如 Paul 提到的,现在可以选择在 draw_networkx_edges 中使用 FancyArrowPatch,尽管它仅适用于有向图并且速度也很慢。

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

示例图片,使用 SNAP Facebook 数据集和 ForceAtlas2 布局:

【讨论】:

  • 刚刚尝试将connectionstyle='arc3, rad=0.1' 传递给nx.draw(),它在我的小(ish)图表上的用例非常有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
相关资源
最近更新 更多