Search code examples
pythonnetworkx

Traversing level order for the graph in networkx


I am trying to convert a DiGraph into n-ary tree and displaying the nodes in level order or BFS. My tree is similar to this, but much larger, for simplicity using this example:

G = networkx.DiGraph()
G.add_edges_from([('n', 'n1'), ('n', 'n2'), ('n', 'n3')])
G.add_edges_from([('n4', 'n41'), ('n1', 'n11'), ('n1', 'n12'), ('n1', 'n13')])
G.add_edges_from([('n2', 'n21'), ('n2', 'n22')])
G.add_edges_from([('n13', 'n131'), ('n22', 'n221')])

Tree: borrowed the data from this question:

n---->n1--->n11
 |     |--->n12
 |     |--->n13
 |           |--->n131 
 |--->n2              
 |     |---->n21     
 |     |---->n22     
 |            |--->n221 
 |--->n3

I am using networkx.DiGraph for this purpose and created the graph successfully. Here is my code for creating a DiGraph:

G = nx.DiGraph()
roots = set()
for l in raw.splitlines():
    if len(l):
        target, prereq = regex1.split(l)
        deps = tuple(regex2.split(prereq))
        print("Add node:") + target
        roots.add(target)
        G.add_node(target)
        for d in deps:
            if d:
                G.add_edge(target, d)

I am reading the all the data from a file with about 200 lines in the following format and trying to get a dependency tree. My graph is around 100 nodes with 600 edges.

AAA: BBB,CCC,DDD,
BBB:
DDD: EEE,FFF,GGG,KKK
GGG: AAA,BBB,III,LLL
....
...
..
.

After looking into the networkx docs online, now I can achieve the the level order output doing a topological sort on the dependency tree, with the below code.

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

output:

['n2', 'n3', 'n1', 'n21', 'n22', 'n11', 'n13', 'n12', 'n221', 'n131']

The order seems correct, but since I need to process the jobs in a batch (which saves time) and not sequentially, I want the output in level ordered output batches or using BFS. What is the best way to achieve this ?
ex: level[0:n], ex:

0. ['n'] 
1. ['n2', 'n3', 'n1',] 
2. ['n21', 'n22', 'n11',] 
3. ['n13', 'n12', 'n221', 'n131'] 

Solution

  • You could use the bfs_edges() function to get a list of nodes in a breadth-first-search order.

    In [1]: import networkx
    
    In [2]: G = networkx.DiGraph()
    
    In [3]: G.add_edges_from([('n', 'n1'), ('n', 'n2'), ('n', 'n3')])
    
    In [4]: G.add_edges_from([('n4', 'n41'), ('n1', 'n11'), ('n1', 'n12'), ('n1', 'n13')])
    
    In [5]: G.add_edges_from([('n2', 'n21'), ('n2', 'n22')])
    
    In [6]: G.add_edges_from([('n13', 'n131'), ('n22', 'n221')])
    
    In [7]: list(networkx.bfs_edges(G,'n'))
    Out[7]: 
    [('n', 'n2'),
     ('n', 'n3'),
     ('n', 'n1'),
     ('n2', 'n21'),
     ('n2', 'n22'),
     ('n1', 'n11'),
     ('n1', 'n13'),
     ('n1', 'n12'),
     ('n22', 'n221'),
     ('n13', 'n131')]
    
    In [8]: [t for (s,t) in networkx.bfs_edges(G,'n')]
    Out[8]: ['n2', 'n3', 'n1', 'n21', 'n22', 'n11', 'n13', 'n12', 'n221', 'n131']
    
    In [9]: networkx.single_source_shortest_path_length(G,'n')
    Out[9]: 
    {'n': 0,
     'n1': 1,
     'n11': 2,
     'n12': 2,
     'n13': 2,
     'n131': 3,
     'n2': 1,
     'n21': 2,
     'n22': 2,
     'n221': 3,
     'n3': 1}