Migration guide from 1.X to 2.0ΒΆ

This is a guide for people moving from NetworkX 1.X to NetworkX 2.0

Any issues with these can be discussed on the mailing list.

We have made some major changes to the methods in the Multi/Di/Graph classes. The methods changed are explained with examples below.

With the release of NetworkX 2.0 we are moving to a view/iterator reporting API. We have moved many methods from reporting lists or dicts to iterating over the information. Most of the changes in this regard are in the base classes. Methods that used to return containers now return views (inspired from dictionary views in Python) and methods that returned iterators have been removed. The methods which create new graphs have changed in the depth of data copying. G.subgraph/edge_subgraph/reverse/to_directed/to_undirected are affected. Many now have options for view creation instead of copying data. The depth of the data copying may have also changed.

One View example is G.nodes (or G.nodes()) which now returns a dict-like NodeView while G.nodes_iter() has been removed. Similarly for views with G.edges and removing G.edges_iter. The Graph attributes G.node and G.edge have been removed in favor of using G.nodes[n] and G.edges[u, v]. Finally, the selfloop methods and add_path/star/cycle have been moved from graph methods to networkx functions.

We expect that these changes will break some code. We have tried to make them break the code in ways that raise exceptions, so it will be obvious that code is broken.

There are also a number of improvements to the codebase outside of the base graph classes. These are too numerous to catalog here, but a couple obvious ones include:

  • centering of nodes in drawing/nx_pylab,
  • iterator vs dict output from a few shortest_path routines

Some demonstrations:

>>> import networkx as nx
>>> G = nx.complete_graph(5)
>>> G.nodes  # for backward compatibility G.nodes() works as well
NodeView((0, 1, 2, 3, 4))

You can iterate through G.nodes (or G.nodes())

>>> for node in G.nodes:
...     print(node)
0
1
2
3
4

If you want a list of nodes you can use the Python list function

>>> list(G.nodes)
[0, 1, 2, 3, 4]

G.nodes is set-like allowing set operations. It is also dict-like in that you can look up node data with G.nodes[n]['weight']. You can still use the calling interface G.nodes(data='weight') to iterate over node/data pairs. In addition to the dict-like views keys/values/items, G.nodes has a data-view G.nodes.data(‘weight’). The new EdgeView G.edges has similar features for edges.

By adding views NetworkX supports some new features like set operations on views.

>>> H = nx.Graph()
>>> H.add_nodes_from([1, 'networkx', '2.0'])
>>> G.nodes & H.nodes  # finding common nodes in 2 graphs
set([1])
>>> G.nodes | H.nodes  # union of nodes in 2 graphs
set([0, 1, 2, 3, 4, 'networkx', '2.0'])

Similarly, G.edges now returns an EdgeView instead of a list of edges and it also supports set operations.

>>> G.edges  # for backward compatibility G.nodes() works as well
EdgeView([(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)])
>>> list(G.edges)
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

G.degree now returns a dict-like DegreeView

>>> G.degree  # for backward compatibility G.degree() works as well
DegreeView({0: 4, 1: 4, 2: 4, 3: 4, 4: 4})
>>> G.degree([1, 2, 3])
DegreeView({1: 4, 2: 4, 3: 4})
>>> list(G.degree([1, 2, 3]))
[(1, 4), (2, 4), (3, 4)]
>>> dict(G.degree([1, 2, 3]))
{1: 4, 2: 4, 3: 4}
>>> G.degree
DegreeView({0: 4, 1: 4, 2: 4, 3: 4, 4: 4})
>>> list(G.degree)
[(0, 4), (1, 4), (2, 4), (3, 4), (4, 4)]
>>> dict(G.degree)
{0: 4, 1: 4, 2: 4, 3: 4, 4: 4}

The degree of an individual node can be calculated by G.degree[node]. Similar changes have been made to in_degree and out_degree for directed graphs.

If n is a node in G, then G.neighbors(n) returns an iterator.

>>> G.neighbors(2)
<dictionary-keyiterator object at ...>
>>> list(G.neighbors(2))
[0, 1, 3, 4]

DiGraphViews behave similar to GraphViews, but have a few more methods.

>>> D = nx.DiGraph()
>>> D.add_edges_from([(1, 2), (2, 3), (1, 3), (2, 4)])
>>> D.nodes
NodeView((1, 2, 3, 4))
>>> list(D.nodes)
[1, 2, 3, 4]
>>> D.edges
OutEdgeView([(1, 2), (1, 3), (2, 3), (2, 4)])
>>> list(D.edges)
[(1, 2), (1, 3), (2, 3), (2, 4)]
>>> D.in_degree[2]
1
>>> D.out_degree[2]
2
>>> D.in_edges
InEdgeView([(1, 2), (1, 3), (2, 3), (2, 4)])
>>> list(D.in_edges())
[(1, 2), (1, 3), (2, 3), (2, 4)]
>>> D.out_edges(2)
OutEdgeDataView([(2, 3), (2, 4)])
>>> list(D.out_edges(2))
[(2, 3), (2, 4)]
>>> D.in_degree
InDegreeView({1: 0, 2: 1, 3: 2, 4: 1})
>>> list(D.in_degree)
[(1, 0), (2, 1), (3, 2), (4, 1)]
>>> D.successors(2)
<dictionary-keyiterator object at ...>
>>> list(D.successors(2))
[3, 4]
>>> D.predecessors(2)
<dictionary-keyiterator object at ...>
>>> list(D.predecessors(2))
[1]

The same changes apply to MultiGraphs and MultiDiGraphs.


The order of arguments to set_edge_attributes and set_node_attributes has changed. The position of name and values has been swapped, and name now defaults to None. The previous call signature of (graph, name, value) has been changed to (graph, value, name=None). The new style allows for name to be omitted in favor of passing a dictionary of dictionaries to values.

A simple method for migrating existing code to the new version is to explicitly specify the keyword argument names. This method is backwards compatible and ensures the correct arguments are passed, regardless of the order. For example the old code

>>> G = nx.Graph([(1, 2), (1, 3)])
>>> nx.set_node_attributes(G, 'label', {1: 'one', 2: 'two', 3: 'three'})  
>>> nx.set_edge_attributes(G, 'label', {(1, 2): 'path1', (2, 3): 'path2'})  

Will cause TypeError: unhashable type: 'dict' in the new version. The code can be refactored as

>>> G = nx.Graph([(1, 2), (1, 3)])
>>> nx.set_node_attributes(G, name='label', values={1: 'one', 2: 'two', 3: 'three'})
>>> nx.set_edge_attributes(G, name='label', values={(1, 2): 'path1', (2, 3): 'path2'})

Some methods have been removed from the base graph class and placed into the main networkx namespace. These are: G.add_path, G.add_star, G.add_cycle, G.number_of_selfloops, G.nodes_with_selfloops, and G.selfloop_edges. These are replaced by nx.path_graph(G, ...) nx.add_star(G, ...), nx.selfloop_edges(G), etc.