简体   繁体   English

使用 Networkx (Python) 进行图遍历

[英]Graph traversal with Networkx (Python)

I'm playing a bit with Networkx to manage a graph of dependencies.我正在使用 Networkx 来管理依赖关系图。 Let's say I have this Graph which each letter represent a server假设我有这个图表,每个字母代表一个服务器

>>> G = nx.Graph()
>>> G.add_edge("A","B")
>>> G.add_edge("A","H")
>>> G.add_edge("H","C")
>>> G.add_edge("B","C")
>>> G.add_edge("B","D")

           A
         /   \
       H       B
     /        /  \
   C         C     D 

So here we can see that before starting A we need to start H and B and to start H we need to start C and then to start B wee need to start C and D所以在这里我们可以看到,在启动 A 之前我们需要启动 H 和 B 启动 H 我们需要启动 C 然后启动 B 我们需要启动 C 和 D

By fiddling a bit with Networkx I found that I can get that by doing a dfs traversal通过摆弄 Networkx,我发现我可以通过 dfs 遍历来获得它

print nx.dfs_successors(G,"A")
{A:[H,B], H:[C], B:[D] }

But I have a problem with that method.但我对这种方法有疑问。 As you can see when there is two same letter in the tree, Networkx only chose to put one of them in the final structure (which is correct) But I need to have the complete structure How can I force Networkx to add in the structure B:[D,C] ??如您所见,当树中有两个相同的字母时,Networkx 只选择将其中一个放入最终结构中(这是正确的)但我需要拥有完整的结构如何强制 Networkx 添加到结构 B :[D,C] ??

I want to precise that by doing我想通过这样做来精确

>>> nx.dfs_successors(G,"B")
{'B': ['C', 'D']}

So everything is "Internally" correct, it's just the dfs_successors that displays it not in the way I wish.所以一切都是“内部”正确的,只是 dfs_successors 没有以我希望的方式显示它。

Thank you谢谢

Taking your code, your graph doesn't come out as you'd expect.使用您的代码,您的图表并没有像您预期的那样出现。 If you do:如果你这样做:

import pylab as p
import networkx as nx

G = nx.Graph()
G.add_edge("A","B")
G.add_edge("A","H")
G.add_edge("H","C")
G.add_edge("B","C")
G.add_edge("B","D")

nx.draw(G)
p.show()

you will see your graph as:你会看到你的图表:图形

This is due to the logic of G.add_edge("A", "B") :这是由于G.add_edge("A", "B")的逻辑:

  1. If G has no node of id "A", add it.如果G没有 id 为“A”的节点,则添加它。
  2. If G has no node of id "B", add it.如果G没有 id 为“B”的节点,则添加它。
  3. Connect "A" to "B" with a new edge.用新边将“A”连接到“B”。

Thus, you only create five nodes, not six as in your picture.因此,您只创建五个节点,而不是您图片中的六个。

Edit Networkx can take any hashable as value for a node, and in the graph it uses str(node) to label each circle.编辑Networkx 可以将任何哈希值作为节点的值,并且在图中它使用 str(node) 来标记每个圆。 So we can simply define our own Node class (which you maybe want to call Server?) and give it the desired behavior.因此,我们可以简单地定义我们自己的 Node 类(您可能想将其称为 Server?)并为其提供所需的行为。

import pylab as p
import networkx as nx


class Node(object):
    nodes = []

    def __init__(self, label):
        self._label = label

    def __str__(self):
        return self._label

nodes = [Node(l) for l in ["A","B","C","C","D","H"]]
edges = [(0,1),(0,5),(5,2),(1,3),(1,4)]

G = nx.Graph()
for i,j in edges:
    G.add_edge(nodes[i], nodes[j])

nx.draw(G)
p.show()

gives us给我们新图表and so what you wanted.所以你想要什么。

I think what you are looking for is a topological sort https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.dag.topological_sort.html我认为您正在寻找的是拓扑排序https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.dag.topological_sort.html

This only works if you have a DAG (directed acyclic graph).这仅在您有 DAG(有向无环图)时才有效。 If so you can draw the tree you want too - like this:如果是这样,您也可以绘制您想要的树 - 像这样:

import uuid
import networkx as nx
import matplotlib.pyplot as plt
G = nx.DiGraph()
G.add_edge("A","B")
G.add_edge("A","H")
G.add_edge("H","C")
G.add_edge("B","C")
G.add_edge("B","D")

order =  nx.topological_sort(G)
print "topological sort"
print order

# build tree
start = order[0]
nodes = [order[0]] # start with first node in topological order
labels = {}
print "edges"
tree = nx.Graph()
while nodes:
    source = nodes.pop()
    labels[source] = source
    for target in G.neighbors(source):
        if target in tree:
            t = uuid.uuid1() # new unique id
        else:
            t = target
        labels[t] = target
        tree.add_edge(source,t)
        print source,target,source,t
        nodes.append(target)

nx.draw(tree,labels=labels)
plt.show()

The drawing uses a label mapping to map the ids of the node to the original labels.绘图使用标签映射将节点的 id 映射到原始标签。

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM