python——NetworkX库
networkx官方教程:https://networkx.org/documentation/latest/tutorial.html
https://networkx.org/documentation/latest/reference/introduction.html
简介
NetworkX 是一个 Python 包,用于创建、操作和研究复杂网络的结构、动力学和功能。它提供:
- 用于研究社会、生物和基础设施网络的结构和动态的工具;
- 适用于许多应用程序的标准编程接口和图形实现;
- 协作、多学科项目的快速开发环境;
- 现有数值算法和用 C、C++ 和 FORTRAN 编写的代码的接口;
- 轻松处理大型非标准数据集的能力。
使用 NetworkX,您可以以标准和非标准数据格式加载和存储网络,生成多种随机和经典网络,分析网络结构,构建网络模型,设计新的网络算法,绘制网络等等。
创建图表
创建一个没有节点和边的空图。
import networkx as nx
G = nx.Graph()
根据定义,aGraph是节点(顶点)的集合以及已识别的节点对(称为边、链接等)。在 NetworkX 中,节点可以是任何可散列的对象,例如,文本字符串、图像、XML 对象、另一个 Graph、自定义节点对象等。
不允许将Python 的None对象用作节点。它确定是否在许多函数中分配了可选函数参数。
节点
该图G可以通过多种方式增长。NetworkX 包含许多图形生成器函数和工具,可以读取和写入多种格式的图形。首先,我们将看看简单的操作。您可以一次添加一个节点,
G.add_node(1)
或从任何可迭代容器中添加节点,例如列表
G.add_nodes_from([2, 3])
如果您的容器产生以下形式的 2 元组,您还可以添加节点以及节点属性 :(node, node_attribute_dict)
G.add_nodes_from([
(4, {"color": "red"}),
(5, {"color": "green"}),
])
节点属性将在下面进一步讨论。
一个图中的节点可以合并到另一个图中:
H = nx.path_graph(10)
G.add_nodes_from(H)
G现在包含了H的节点作为G的节点。相反,你可以使用H图作为G中的节点。
G.add_node(H)
该图G现在包含H一个节点。这种灵活性非常强大,因为它允许图形图形、文件图形、函数图形等等。值得考虑如何构建您的应用程序,使节点成为有用的实体。当然,G 如果您愿意,您始终可以使用唯一标识符,并拥有一个单独的字典,该字典由节点信息的标识符键控。
如果散列依赖于节点对象的内容,则不应更改节点对象。
边缘
G也可以通过一次添加一条边来增长,
G.add_edge(1, 2)
e = (2, 3)
G.add_edge(*e) # unpack edge tuple* (解压缩边缘元组*)
通过添加边列表,
G.add_edges_from([(1, 2), (1, 3)])
或通过添加任何边缘。ebunch是边缘元组的任何可迭代容器。边元组可以是节点的 2 元组或 2 个节点后跟边属性字典的 3 元组,例如 . 边缘属性将在 下面进一步讨论。(2, 3, {'weight': 3.1415})
G.add_edges_from(H.edges)
添加现有节点或边时没有抱怨(complaints)。例如,在删除所有节点和边之后,
G.clear()
我们添加新的节点/边,NetworkX 悄悄地忽略任何已经存在的节点/边(添加重复不会报错)。
G.add_edges_from([(1, 2), (1, 3)])
G.add_node(1)
G.add_edge(1, 2)
G.add_node("spam") # adds node "spam"
G.add_nodes_from("spam") # adds 4 nodes: 's', 'p', 'a', 'm'
G.add_edge(3, 'm')
在这个阶段,图G由 8 个节点和 3 条边组成,如下所示:
G.number_of_nodes()
8 #1, 2, 3, 'spam', 's', 'p', 'a', 'm'
G.number_of_edges()
3 #(1, 2), (1, 3), (3, 'm')
邻接报告的顺序(例如,G.adj, G.successors, G.predecessors)是边添加的顺序。但是,G.edges 的顺序是邻接的顺序,包括节点的顺序和每个节点的邻接。请参见下面的示例:
DG = nx.DiGraph()
DG.add_edge(2, 1) # adds the nodes in order 2, 1
DG.add_edge(1, 3)
DG.add_edge(2, 4)
DG.add_edge(1, 2)
assert list(DG.successors(2)) == [1, 4]
assert list(DG.edges) == [(2, 1), (2, 4), (1, 3), (1, 2)]
检查图的元素
我们可以检查节点和边。四个基本图形属性便于报告:G.nodes, G.edges, G.adj and G.degree。这些是图中节点、边、邻居(邻接)和节点度数的集合视图。它们为图形结构提供了一个不断更新的只读视图。它们也类似于 dict,因为您可以通过视图查找节点和边缘数据属性,并使用方法迭代数据属性,. 如果你想要一个特定的容器类型而不是一个视图,你可以指定一个。这里我们使用列表,尽管集合、字典、元组和其他容器在其他情况下可能会更好。G.adj或G.degree.items().data()
list(G.nodes)
[1, 2, 3, 'spam', 's', 'p', 'a', 'm']
list(G.edges)
[(1, 2), (1, 3), (3, 'm')]
list(G.adj[1]) # or list(G.neighbors(1))
[2, 3]
G.degree[1] # the number of edges incident to 1
2
可以指定使用nbunch报告来自所有节点子集的边缘和度数。nbunch是以下任何一种:(表示None所有节点)、节点或节点的可迭代容器,其本身不是图中的节点。
G.edges([2, 'm'])
EdgeDataView([(2, 1), ('m', 3)])
G.degree([2, 3])
DegreeView({2: 1, 3: 2})
从图中删除元素
可以以与添加类似的方式从图中删除节点和边。使用方法 Graph.remove_node(), 和 Graph.remove_nodes_from(), 例如Graph.remove_edge()或Graph.remove_edges_from()
G.remove_node(2)
G.remove_nodes_from("spam")
list(G.nodes)
[1, 3, 'spam']
G.remove_edge(1, 3)
使用图构造函数
图形对象不必以增量方式构建 - 指定图形结构的数据可以直接传递给各种图形类的构造函数。通过实例化其中一个图形类来创建图形结构时,您可以指定多种格式的数据。
G.add_edge(1, 2)
H = nx.DiGraph(G) # create a DiGraph using the connections from G
list(H.edges())
[(1, 2), (2, 1)]
edgelist = [(0, 1), (1, 2), (2, 3)]
H = nx.Graph(edgelist) # create a graph from an edge list
list(H.edges())
[(0, 1), (1, 2), (2, 3)]
adjacency_dict = {0: (1, 2), 1: (0, 2), 2: (0, 1)}
H = nx.Graph(adjacency_dict) # create a Graph dict mapping nodes to nbrs
list(H.edges())
[(0, 1), (0, 2), (1, 2)]
使用什么作为节点和边
您可能会注意到节点和边未指定为 NetworkX 对象。这使您可以自由地将有意义的项目用作节点和边。最常见的选择是数字或字符串,但节点可以是任何可散列对象(除了),并且可以使用None将边与任何对象关联。xG.add_edge(n1, n2, object=x)
例如,n1和n2可以是来自RCSB蛋白质数据库的蛋白质对象,x可以参考出版物的XML记录,详细介绍了它们相互作用的实验观察。
我们发现这种功能非常有用,但如果滥用它,可能会导致令人惊讶的行为,除非熟悉Python的人。如果有疑问,可以考虑使用convert_node_labels_to_integers()来获得带有整数标签的更传统的图。
访问边和邻居
除了视图Graph.edges和之外Graph.adj,还可以使用下标表示法访问边和邻居。
G = nx.Graph([(1, 2, {"color": "yellow"})])
G[1] # same as G.adj[1]
AtlasView({2: {'color': 'yellow'}})
G[1][2]
{'color': 'yellow'}
G.edges[1, 2]
{'color': 'yellow'}
如果边已经存在,您可以使用下标表示法获取/设置边缘的属性。
G.add_edge(1, 3)
G[1][3]['color'] = "blue"
G.edges[1, 2]['color'] = "red"
G.edges[1, 2]
{'color': 'red'}
快速检查所有(节点,邻接)对是使用G.adjacency()或G.adj.items()实现的。注意,对于无向图,邻接迭代看到每条边两次。
FG = nx.Graph()
FG.add_weighted_edges_from([(1, 2, 0.125), (1, 3, 0.75), (2, 4, 1.2), (3, 4, 0.375)])
for n, nbrs in FG.adj.items():
for nbr, eattr in nbrs.items():
wt = eattr['weight']
if wt < 0.5: print(f"({n}, {nbr}, {wt:.3})")
(1, 2, 0.125)
(2, 1, 0.125)
(3, 4, 0.375)
(4, 3, 0.375)
使用edges 属性可以方便地访问所有边。
for (u, v, wt) in FG.edges.data('weight'):
if wt < 0.5:
print(f"({u}, {v}, {wt:.3})")
(1, 2, 0.125)
(3, 4, 0.375)
向图、节点和边添加属性
诸如权重、标签、颜色或任何您喜欢的 Python 对象之类的属性都可以附加到图形、节点或边上。
每个图、节点和边都可以在关联的属性字典中保存键/值属性对(键必须是可散列的)。默认情况下这些都是空的,但是属性可以通过add_edge, add_node或者直接操作属性字典G.graph, G.nodes和G.edges来添加或修改。
图属性
创建新图形时分配图形属性
G = nx.Graph(day="Friday")
G.graph
{'day': 'Friday'}
或者您可以稍后修改属性
G.graph['day'] = "Monday"
G.graph
{'day': 'Monday'}
节点属性
使用add_node()、add_nodes_from()或G.nodes添加节点属性
G.add_node(1, time='5pm')
G.add_nodes_from([3], time='2pm')
G.nodes[1]
{'time': '5pm'}
G.nodes[1]['room'] = 714
G.nodes.data()
NodeDataView({1: {'time': '5pm', 'room': 714}, 3: {'time': '2pm'}})
请注意,添加节点G.nodes不会将其添加到图形中,用于 G.add_node()添加新节点。对于边也是如此。
边属性
使用add_edge()、add_edges_from()或下标符号添加/更改边缘属性。
G.add_edge(1, 2, weight=4.7 )
G.add_edges_from([(3, 4), (4, 5)], color='red')
G.add_edges_from([(1, 2, {'color': 'blue'}), (2, 3, {'weight': 8})])
G[1][2]['weight'] = 4.7
G.edges[3, 4]['weight'] = 4.2
特殊属性weight应该是数字的,因为它被需要在加权边的算法中使用。
有向图
DiGraph类提供了额外的特定于有向边的方法和属性,例如 DiGraph.out_edges, DiGraph.in_degree, DiGraph.predecessors, DiGraph.successors 等等。为了允许算法轻松地处理两个类,近邻的定向版本与后继类等效,而degree报告in_degree和out_degree的总和,尽管有时感觉不一致。
DG = nx.DiGraph()
DG.add_weighted_edges_from([(1, 2, 0.5), (3, 1, 0.75)])
DG.out_degree(1, weight='weight')
0.5
DG.degree(1, weight='weight')
1.25
list(DG.successors(1))
[2]
list(DG.neighbors(1))
[2]
有些算法只适用于有向图,而有些算法则不能很好地用于有向图。事实上,把有向图和无向图混为一谈的倾向是危险的。如果你想将一个有向图作为无向测量,你应该使用graph .to_undirected()或with将其转换
H = nx.Graph(G) # create an undirected graph H from a directed graph G
多图
NetworkX为图提供了允许任意对节点之间有多条边的类。MultiGraph和MultiDiGraph类允许您两次添加相同的边,可能使用不同的边数据。这对于某些应用程序来说非常强大,但是许多算法在这样的图上没有很好地定义。在结果定义良好的情况下,例如,我们提供MultiGraph.degree()函数。否则,您应该转换为一个标准图,使测量得到很好的定义。
MG = nx.MultiGraph()
MG.add_weighted_edges_from([(1, 2, 0.5), (1, 2, 0.75), (2, 3, 0.5)])
dict(MG.degree(weight='weight'))
{1: 1.25, 2: 1.75, 3: 0.5}
GG = nx.Graph()
for n, nbrs in MG.adjacency():
for nbr, edict in nbrs.items():
minvalue = min([d['weight'] for d in edict.values()])
GG.add_edge(n, nbr, weight = minvalue)
nx.shortest_path(GG, 1, 3)
[1, 2, 3]
图生成器和图操作
除了逐节点或逐边构造图之外,它们还可以通过以下方式生成
- 应用经典的图操作,例如:
-
subgraph(G, nbunch):返回在 nbunch 中的节点上诱导的子图。
-
union(G, H[, rename, name]):返回图 G 和 H 的并集。
-
disjoint_union(G, H):返回图 G 和 H 的不相交并集。
-
cartesian_product(G, H):返回 G 和 H 的笛卡尔积。
-
compose(G, H):返回由 H 组成的 G 的新图。
-
complement(G):返回 G 的图补集。
-
create_empty_copy(G[, with_data]):返回删除所有边的图 G 的副本。
-
to_undirected(graph):返回图的无向视图graph。
-
to_directed(graph):返回图形的有向视图graph。
- 使用对一个经典小图的调用,例如,
- petersen_graph([create_using]):返回彼得森图。
- tutte_graph([create_using]):返回 Tutte 图。
- sedgewick_maze_graph([create_using]):返回一个带循环的小迷宫。
- tetrahedral_graph([create_using]):返回 3 正则柏拉图四面体图。
- 对经典图使用(构造)生成器,例如:
-
complete_graph(n[, create_using]):返回具有n个节点的完整图K_n。
-
complete_bipartite_graph(n1, n2[, create_using]):返回完全二部图K_{n_1,n_2}。
-
barbell_graph(m1, m2[, create_using]):返回杠铃图:由一条路径连接的两个完整的图。
-
lollipop_graph(m, n[, create_using]):返回棒棒糖图;K_m连接到P_n。
像这样:
K_5 = nx.complete_graph(5)
K_3_5 = nx.complete_bipartite_graph(3, 5)
barbell = nx.barbell_graph(10, 10)
lollipop = nx.lollipop_graph(10, 20)
- 使用随机图形生成器,例如:
-
erdos_renyi_graph(n, p[, seed, directed]):返回一个(G_{n,p})随机图,也称为Erdős-Rényi图或二项式图。
-
watts_strogatz_graph(n, k, p[, seed]):返回 Watts-Strogatz 小世界图。
-
barabasi_albert_graph(n, m[, seed, ...]):使用 Barabási–Albert 优先附件返回一个随机图
-
random_lobster(n, p1, p2[, seed]):返回一个随机lobster图。
像这样:
er = nx.erdos_renyi_graph(100, 0.15)
ws = nx.watts_strogatz_graph(30, 3, 0.1)
ba = nx.barabasi_albert_graph(100, 5)
red = nx.random_lobster(100, 0.9, 0.9)
- 读取使用通用图形格式存储在文件中的图形
NetworkX 支持许多流行的格式,例如边缘列表、邻接列表、GML、GraphML、pickle、LEDA 等。
nx.write_gml(red, "path.to.file")
mygraph = nx.read_gml("path.to.file")
有关图形格式的详细信息,请参阅读和写图形 ,有关图形生成器函数,请参阅图形生成器
分析图表
G的结构可以用各种图论函数来分析,例如:
G = nx.Graph()
G.add_edges_from([(1, 2), (1, 3)])
G.add_node("spam") # adds node "spam"
list(nx.connected_components(G))
[{1, 2, 3}, {'spam'}]
sorted(d for n, d in G.degree())
[0, 1, 1, 2]
nx.clustering(G)
{1: 0, 2: 0, 3: 0, 'spam': 0}
一些具有大输出的函数遍历(节点,值)2元组。如果需要,可以很容易地将它们存储在dict结构中。
sp = dict(nx.all_pairs_shortest_path(G))
sp[3]
{3: [3], 1: [3, 1], 2: [3, 1, 2]}
有关支持的图形算法的详细信息,请参阅算法。
绘制图表
NetworkX 主要不是一个图形绘图包,而是包含使用 Matplotlib 的基本绘图以及使用开源 Graphviz 软件包的接口。这些是networkx.drawing 模块的一部分,如果可能,将被导入。
首先导入 Matplotlib 的绘图界面(pylab 也可以)
import matplotlib.pyplot as plt
使用以下之一测试导入nx_pylab是否成功绘制G
G = nx.petersen_graph()
subax1 = plt.subplot(121)
nx.draw(G, with_labels=True, font_weight='bold')
subax2 = plt.subplot(122)
nx.draw_shell(G, nlist=[range(5, 10), range(5)], with_labels=True, font_weight='bold')
绘制到交互式显示器时。请注意,您可能需要发布一个 Matplotlib
plt.show()
如果您没有在交互模式下使用 matplotlib,则使用命令。
options = {
'node_color': 'black',
'node_size': 100,
'width': 3,
}
subax1 = plt.subplot(221)
nx.draw_random(G, **options)
subax2 = plt.subplot(222)
nx.draw_circular(G, **options)
subax3 = plt.subplot(223)
nx.draw_spectral(G, **options)
subax4 = plt.subplot(224)
nx.draw_shell(G, nlist=[range(5,10), range(5)], **options)
你可以通过draw_networkx()和layout模块找到其他选项。使用draw_shell()可以使用多个shell。
G = nx.dodecahedral_graph()
shells = [[2, 3, 4, 5, 6], [8, 1, 0, 19, 18, 17, 16, 15, 14, 7], [9, 10, 11, 12, 13]]
nx.draw_shell(G, nlist=shells, **options)
要将图形保存到文件中,请使用,例如
nx.draw(G)
plt.savefig("path.png")
此函数写入path.png本地目录中的文件。如果 Graphviz 和 PyGraphviz 或 pydot 在您的系统上可用,您还可以使用 networkx.drawing.nx_agraph.graphviz_layout 或者 networkx.drawing.nx_pydot.graphviz_layout来获取节点位置,或者以点格式编写图形以进行进一步处理。
from networkx.drawing.nx_pydot import write_dot
pos = nx.nx_agraph.graphviz_layout(G)
nx.draw(G, pos=pos)
write_dot(G, 'file.dot')
有关其他详细信息,请参见Drawing。

浙公网安备 33010602011771号