Maksim Khaitovich
Maksim Khaitovich

Reputation: 4792

Python NetworkX - get DiGraph from nested dictionaries

I am trying to create a simple DiGraph in python's NetworkX from nested dictionary but it looks like built in initialization doesn't built final leaf nodes.

Toy example:

class_hierarchy= {-1: ["A", "B"], 
"A":{"A1":[1], "A2":[3,4]}, 
"B": {"B1":[5,6], "B2": [7,8]}}

Building graph:

G = DiGraph(class_hierarchy)

Now let's see what we have in it:

G.nodes
Out[86]: NodeView((-1, 'A', 'B', 'A1', 'A2', 'B1', 'B2'))

Looks like final nodes are not added

Checking it:

list(G.successors('A'))
Out[88]: ['A1', 'A2']

Looks reasonable

But:

list(G.successors('A1'))
Out[89]: []

I am not sure why this is the case? Documentation for NetworkX specifies that:

incoming_graph_data (input graph (optional, default: None)) – Data to initialize graph. If None (default) an empty graph is created. The data can be any format that is supported by the to_networkx_graph() function, currently including edge list, dict of dicts, dict of lists, etc...

Any idea what I am doing wrong?

Upvotes: 1

Views: 1323

Answers (1)

abc
abc

Reputation: 11949

You have a mixed input which is both a dict of lists and both a dict of dicts. Networkx will interpretate it as dict of lists.
See the following code, where data is class_hierarchy in your case.

if isinstance(data, dict):
        try:
            #this will raise an exception
            return from_dict_of_dicts(data, create_using=create_using,
                                  multigraph_input=multigraph_input)
        except:
            try:
                # this is what is called in your case
                return from_dict_of_lists(data, create_using=create_using)
            except:
                raise TypeError("Input is not known type.")

In your case, networkx expects a dictionary of lists adjacency representation.
For instance, the expected input is of the form : key: value -> node u: list of nodes [v1,v2,...,vn] u is connected with (e.g., {0: [1,2], 1: [3,4]}.

What networkx does with you input you give is as follows:

G=nx.DiGraph()

edges_list = [((node, nbr)) for node, nbrlist in d.items() for nbr in nbrlist]
# [(-1, 'A'), (-1, 'B'), ('A', 'A1'), ('A', 'A2'), ('B', 'B1'), ('B', 'B2')]

G.add_edges_from(edges_list)

Thus, you have to change your format according to the meaning you give to it.

Upvotes: 2

Related Questions