Is it possible to get unique paths in networkx with attribute included in the path?

Viewed 151

I have the following graph and I want to be able to discover all ways that I can go from 'ip' to 'name' with the following graph in networkx it shows that I can go from 'ip' to 'name' if I follow this path [['ip', 'address', 'name']] the problem is I also defined that address to name can go from two different edges, one that has the attribute through=isptool and another that goes through the attribute through=phyonebook is it possible to have networkx list out these two paths as separate paths and also include the through attribute in the path? Something like

ip -sometool-> address -isptool-> name

ip -sometool-> address -phonebook-> name
import networkx as nx
g = nx.DiGraph()
g.add_node('email')
g.add_node('ip')
g.add_node('address')
g.add_node('name')
g.add_edges_from([('address', 'name')], through='isptool')
g.add_edges_from([('address', 'name')], through='phonebook')
g.add_edge('email', 'address')
g.add_edge('ip', 'address', through='sometool')
list(nx.all_simple_paths(g, 'ip', 'name'))
>>>[['ip', 'address', 'name']] # should have 2 paths one using isptool and one using phonebook edge
list(nx.all_simple_paths(g, 'email', 'name'))
>>>[['email', 'address', 'name']] # same here, should have 2 paths
1 Answers

The issue is that you're trying to use a DiGraph, which can only handle one directed edge from one node to another. If we switch to using a MultiDiGraph, nx.all_simple_paths() returns the expected result:

>>> import networkx as nx
    g = nx.MultiDiGraph()
    g.add_nodes_from(['email', 'ip', 'address', 'name'])
    
    g.add_edges_from([('address', 'name')], through='isptool')
    g.add_edges_from([('address', 'name')], through='phonebook')
    g.add_edge('email', 'address')
    g.add_edge('ip', 'address', through='sometool')
>>> list(nx.all_simple_paths(g, 'ip', 'name'))
[['ip', 'address', 'name'], ['ip', 'address', 'name']]
>>> list(nx.all_simple_paths(g, 'email', 'name'))
[['email', 'address', 'name'], ['email', 'address', 'name']]

However, although we get two paths now, we can't see the edge attributes. We can use nx.all_simple_edge_paths() instead:

>>> list(nx.all_simple_edge_paths(g, 'email', 'name'))
[[('email', 'address', 0), ('address', 'name', 0)],
 [('email', 'address', 0), ('address', 'name', 1)]]

And with some f-string magic, we can use the edge data to produce the output you wanted:

>>> for path in nx.all_simple_edge_paths(g, 'email', 'name'):
        a, b, e = path[0]
        print(f'{a} -{g[a][b][e].get("through", "sometool")}-> {b}', end='')
        for a, b, e in path[1:]:
            print(f' -{g[a][b][e].get("through", "sometool")}-> {b}', end='')
        print('\n')
email -sometool-> address -isptool-> name

email -sometool-> address -phonebook-> name
Related