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
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