如何使用Python中的NetworkX绘制有向图?

161

我有一些来自脚本的节点,我想将它们映射到一个图上。在下面的示例中,我想使用箭头从A到D,并且可能也要对边进行颜色标记(红色或其他颜色)。

基本上,这就像是从A到D的路径,当存在所有其他节点时。你可以把每个节点想象成城市,在从A到D的旅程中需要方向指引(箭头头部)。

以下代码构建了该图

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt

G = nx.Graph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

nx.draw(G, cmap = plt.get_cmap('jet'), node_color = values)
plt.show()
但我想要像图片中显示的那样。enter image description here enter image description here 第一张图中的箭头以及红色边缘应用到第二张图上。
6个回答

129

只针对红色边缘的箭头完整示例:

import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

# Specify the edges you want here
red_edges = [('A', 'C'), ('E', 'C')]
edge_colours = ['black' if not edge in red_edges else 'red'
                for edge in G.edges()]
black_edges = [edge for edge in G.edges() if edge not in red_edges]

# Need to create a layout when doing
# separate calls to draw nodes and edges
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, cmap=plt.get_cmap('jet'), 
                       node_color = values, node_size = 500)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edgelist=red_edges, edge_color='r', arrows=True)
nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False)
plt.show()

红色的边缘


2
我们两张更新后的图片差别如此之大,简直让人难以置信。为你解决边缘颜色问题点个赞! - mdml
为什么你的边缘(C,E)不是红色的,尽管根据上面的代码它必须是红色的? - brain storm
@user1988876:啊,抱歉,(C, E)不是红色的,因为当我还在处理你的无向图时,我从G.edges()返回的边中随机选择了边来作为red_edges。应该是red_edges = [('A', 'C'), ('E', 'C')] - Marius
太棒了!不过有一个问题..这个代码 cmap = plt.get_cmap('jet') 是什么意思?我之前已经发了问题,但是不清楚它的作用。 - brain storm
@user1988876 它设置了色图,请参阅matplotlib文档以获取更多选项。 - Marius
显示剩余5条评论

63

你可以使用下面的代码替代常规的nx.draw:

nx.draw_networkx(G[, pos, arrows, with_labels])
例如:
nx.draw_networkx(G, arrows=True, **options)

您可以通过这样初始化**变量来添加选项:

options = {
    'node_color': 'blue',
    'node_size': 100,
    'width': 3,
    'arrowstyle': '-|>',
    'arrowsize': 12,
}

此外,一些函数支持 directed=True 参数。在这种情况下,这个状态是默认的:

G = nx.DiGraph(directed=True)

您可以在这里找到networkx参考文档。

箭头图像的图表


2
给出一个可行的例子会很好。 - Natan

56

我只是为了完整性而加入这个。我从marius和mdml那里学到了很多。这是边权重。箭头的问题很抱歉,看起来好像不止我一个人说它无法被解决。我不能在ipython笔记本中渲染这个,我必须直接从Python进行操作,这也是我之前没能更早设置我的边权重的原因。

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
import pylab

G = nx.DiGraph()

G.add_edges_from([('A', 'B'),('C','D'),('G','D')], weight=1)
G.add_edges_from([('D','A'),('D','E'),('B','D'),('D','E')], weight=2)
G.add_edges_from([('B','C'),('E','F')], weight=3)
G.add_edges_from([('C','F')], weight=4)


val_map = {'A': 1.0,
                   'D': 0.5714285714285714,
                              'H': 0.0}

values = [val_map.get(node, 0.45) for node in G.nodes()]
edge_labels=dict([((u,v,),d['weight'])
                 for u,v,d in G.edges(data=True)])
red_edges = [('C','D'),('D','A')]
edge_colors = ['black' if not edge in red_edges else 'red' for edge in G.edges()]

pos=nx.spring_layout(G)
nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)
nx.draw(G,pos, node_color = values, node_size=1500,edge_color=edge_colors,edge_cmap=plt.cm.Reds)
pylab.show()

在此输入图片描述


10
我运行了这个程序但没有得到节点标签。你需要添加以下内容:node_labels = {node:node for node in G.nodes()}; nx.draw_networkx_labels(G, pos, labels=node_labels) - MadeOfAir
这一部分代码的第一行(除了导入行)设置了图的类型和它接受的边的类型。你可以从有向图(更多信息)转换为无向图(较少信息),但是如果没有信息或构造缺失的信息的方法,你不能从无向图(较少信息)转换为有向图(更多信息)。我建议在另一个stackoverflow问题中举例提出你的问题。 - Back2Basics
1
能否在边缘上得到真正的箭头?我不喜欢只有粗的末端。 - Wikunia
1
在Matplotlib中绘制箭头比较棘手,目前在NetworkX中也不支持。欢迎提交Pull requests。 - Back2Basics
1
更新:NetworkX箭头已经实现。太棒了! - Back2Basics
显示剩余3条评论

29

你需要使用有向图 (directed graph),而不是无向图。

G = nx.DiGraph()
然后,创建一个您想要使用的边缘颜色列表,并将其传递给 nx.draw(如 @Marius 所示)。
将所有这些放在一起,我得到了下面的图像。虽然还不完全与您展示的另一幅图片相同(我不知道您的边缘权重来自何处),但已经非常接近了!如果您想更好地控制输出图形的外观(例如获取箭头形状的箭头),我建议查看NetworkX 与 Graphvizenter image description here

啊,谢谢,我一直看到文档中有箭头的参数,但就是想不通为什么它们不起作用。 - Marius
我尝试了你所做的,但是使用g = nx.Graph(strict=True, directed=True)时,图形不是有向的。但是通过g = g.to_directed()修复了这个问题。我是做错了什么还是这是一个bug? - Charlie Parker

17
import networkx as nx
import matplotlib.pyplot as plt

g = nx.DiGraph()
g.add_nodes_from([1,2,3,4,5])
g.add_edge(1,2)
g.add_edge(4,2)
g.add_edge(3,5)
g.add_edge(2,3)
g.add_edge(5,4)

nx.draw(g,with_labels=True)
plt.draw()
plt.show()

这只是一个简单的使用Python 3.x和networkx绘制有向图的说明。 可以进行简单的表示并且可以修改和着色等。在这里查看生成的图。

注意:这只是一个简单的表示。可以像添加加权边一样进行修改。

g.add_edges_from([(1,2),(2,5)], weight=2)

因此再次绘制。


15
import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()
G.add_node("A")
G.add_node("B")
G.add_node("C")
G.add_node("D")
G.add_node("E")
G.add_node("F")
G.add_node("G")
G.add_edge("A","B")
G.add_edge("B","C")
G.add_edge("C","E")
G.add_edge("C","F")
G.add_edge("D","E")
G.add_edge("F","G")

print(G.nodes())
print(G.edges())

pos = nx.spring_layout(G)

nx.draw_networkx_nodes(G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edge_color='r', arrows = True)

plt.show()

我尝试了你所做的,但是使用g = nx.Graph(strict=True, directed=True)时,图形不是有向的。但是通过g = g.to_directed()修复了这个问题。我是做错了什么还是这是一个bug? - Charlie Parker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接