NetworkX 0.99

Release date: 18 November 2008

See: https://networkx.lanl.gov/trac/timeline

New features

This release has significant changes to parts of the graph API. See http://networkx.lanl.gov/reference/api_changes.html

  • Update Graph and DiGraph classes to use weighted graphs as default Change in API for performance and code simplicity.

  • New MultiGraph and MultiDiGraph classes (replace XGraph and XDiGraph)

  • Update to use Sphinx documentation system http://networkx.lanl.gov/

  • Developer site at https://networkx.lanl.gov/trac/

  • Experimental LabeledGraph and LabeledDiGraph

  • Moved package and file layout to subdirectories.

Bug fixes

  • handle root= option to draw_graphviz correctly

Examples

  • Update to work with networkx-0.99 API

  • Drawing examples now use matplotlib.pyplot interface

  • Improved drawings in many examples

  • New examples - see http://networkx.lanl.gov/examples/

The version networkx-0.99 is the penultimate release before networkx-1.0. We have bumped the version from 0.37 to 0.99 to indicate (in our unusual version number scheme) that this is a major change to NetworkX.

We have made some significant changes, detailed below, to NetworkX to improve performance, functionality, and clarity.

Version 0.99 requires Python 2.4 or greater.

Please send comments and questions to the networkx-discuss mailing list. http://groups.google.com/group/networkx-discuss

Changes in base classes

The most significant changes are in the graph classes. We have redesigned the Graph() and DiGraph() classes to optionally allow edge data. This change allows Graph and DiGraph to naturally represent weighted graphs and to hold arbitrary information on edges.

  • Both Graph and DiGraph take an optional argument weighted=True|False. When weighted=True the graph is assumed to have numeric edge data (with default 1). The Graph and DiGraph classes in earlier versions used the Python None as data (which is still allowed as edge data).

  • The Graph and DiGraph classes now allow self loops.

  • The XGraph and XDiGraph classes are removed and replaced with MultiGraph and MultiDiGraph. MultiGraph and MultiDiGraph optionally allow parallel (multiple) edges between two nodes.

The mapping from old to new classes is as follows:

- Graph -> Graph (self loops allowed now, default edge data is 1)
- DiGraph -> DiGraph (self loops allowed now, default edge data is 1)
- XGraph(multiedges=False) -> Graph
- XGraph(multiedges=True) -> MultiGraph
- XDiGraph(multiedges=False) -> DiGraph
- XDiGraph(multiedges=True) -> MultiDiGraph

Methods changed

edges()

New keyword data=True|False keyword determines whether to return two-tuples (u,v) (False) or three-tuples (u,v,d) (True)

delete_node()

The preferred name is now remove_node().

delete_nodes_from()

No longer raises an exception on an attempt to delete a node not in the graph. The preferred name is now remove_nodes_from().

delete_edge()

Now raises an exception on an attempt to delete an edge not in the graph. The preferred name is now remove_edge().

delete_edges_from()

The preferred name is now remove_edges_from().

add_edge()

The add_edge() method no longer accepts an edge tuple (u,v) directly. The tuple must be unpacked into individual nodes.

>>> import networkx as nx
>>> u='a'
>>> v='b'
>>> e=(u,v)
>>> G=nx.Graph()

Old

>>> # G.add_edge((u,v))  # or G.add_edge(e)

New

>>> G.add_edge(*e) # or G.add_edge(*(u,v))

The * operator unpacks the edge tuple in the argument list.

Add edge now has a data keyword parameter for setting the default (data=1) edge data.

>>> # G.add_edge('a','b','foo')  # add edge with string "foo" as data
>>> # G.add_edge(1,2,5.0)  # add edge with float 5 as data

add_edges_from()

Now can take list or iterator of either 2-tuples (u,v), 3-tuples (u,v,data) or a mix of both.

Now has data keyword parameter (default 1) for setting the edge data for any edge in the edge list that is a 2-tuple.

has_edge()

The has_edge() method no longer accepts an edge tuple (u,v) directly. The tuple must be unpacked into individual nodes.

Old:

>>> # G.has_edge((u,v))  # or has_edge(e)

New:

>>> G.has_edge(*e) # or has_edge(*(u,v))
True

The * operator unpacks the edge tuple in the argument list.

get_edge()

Now has the keyword argument “default” to specify what value to return if no edge is found. If not specified an exception is raised if no edge is found.

The fastest way to get edge data for edge (u,v) is to use G[u][v] instead of G.get_edge(u,v)

degree_iter()

The degree_iter method now returns an iterator over pairs of (node, degree). This was the previous behavior of degree_iter(with_labels=true) Also there is a new keyword weighted=False|True for weighted degree.

subgraph()

The argument inplace=False|True has been replaced with copy=True|False.

Subgraph no longer takes create_using keyword. To change the graph type either make a copy of the graph first and then change type or change type and make a subgraph. E.g.

>>> G=nx.path_graph(5)
>>> H=nx.DiGraph(G.subgraph([0,1])) # digraph of copy of induced subgraph

__getitem__()

Getting node neighbors from the graph with G[v] now returns a dictionary.

>>> G=nx.path_graph(5)
>>> # G[0]
#  {1: 1}

To get a list of neighbors you can either use the keys of that dictionary or use

>>> G.neighbors(0)  
[1]

This change allows algorithms to use the underlying dict-of-dict representation through G[v] for substantial performance gains. Warning: The returned dictionary should not be modified as it may corrupt the graph data structure. Make a copy G[v].copy() if you wish to modify the dict.

Methods removed

info()

now a function

>>> G=nx.Graph(name='test me')
>>> nx.info(G)  
Name:                  test me
Type:                  Graph
Number of nodes:       0
Number of edges:       0

node_boundary()

now a function

edge_boundary()

now a function

is_directed()

use the directed attribute

>>> G=nx.DiGraph()
>>> # G.directed
#  True

G.out_edges()

use G.edges()

G.in_edges()

use

>>> G = nx.DiGraph()
>>> R = G.reverse()
>>> R.edges()  
[]

or

>>> [(v,u) for (u,v) in G.edges()]
[]

Methods added

adjacency_list()

Returns a list-of-lists adjacency list representation of the graph.

adjacency_iter()

Returns an iterator of (node, adjacency_dict[node]) over all nodes in the graph. Intended for fast access to the internal data structure for use in internal algorithms.

Other possible incompatibilities with existing code

Imports

Some of the code modules were moved into subdirectories.

Import statements such as:

import networkx.centrality
from networkx.centrality import *

may no longer work (including that example).

Use either

>>> import networkx # e.g. centrality functions available as networkx.fcn()

or

>>> from networkx import * # e.g. centrality functions available as fcn()

Self-loops

For Graph and DiGraph self loops are now allowed. This might affect code or algorithms that add self loops which were intended to be ignored.

Use the methods

  • nodes_with_selfloops()

  • selfloop_edges()

  • number_of_selfloops()

to discover any self loops.

Copy

Copies of NetworkX graphs including using the copy() method now return complete copies of the graph. This means that all connection information is copied–subsequent changes in the copy do not change the old graph. But node keys and edge data in the original and copy graphs are pointers to the same data.

prepare_nbunch

Used internally - now called nbunch_iter and returns an iterator.

Converting your old code to Version 0.99

Mostly you can just run the code and python will raise an exception for features that changed. Common places for changes are

  • Converting XGraph() to either Graph or MultiGraph

  • Converting XGraph.edges() to Graph.edges(data=True)

  • Switching some rarely used methods to attributes (e.g. directed) or to functions (e.g. node_boundary)

  • If you relied on the old default edge data being None, you will have to account for it now being 1.

You may also want to look through your code for places which could improve speed or readability. The iterators are helpful with large graphs and getting edge data via G[u][v] is quite fast. You may also want to change G.neighbors(n) to G[n] which returns the dict keyed by neighbor nodes to the edge data. It is faster for many purposes but does not work well when you are changing the graph.