In contrast to Graphviz and other graph optimizers, graphopt does not use a finite-pass approach to layout optimization. Instead, it uses basic principles of physics to iteratively determine an optimal layout.
Each node is given mass and an electric charge, and each edge is represented as a spring. Node mass, electric charge, optimal spring length, and the spring constant are all configurable.
For most graphs, this is all that is needed - the graph organizes itself much as the analagous real-life system would if constrained to two dimensions. For more complex graphs, some fiddling with the physical parameters at different stages of optimization usually does the trick.
Graphs can be imported using a subset of the dot format from AT&T Research and Lucent Bell Labs' Graphviz tools, and can be exported as Postscript or in a Visio-importable format.
Example usage:
>>> import graphopt
>>> g = graphopt.graphopt()
>>> g.add_edge('foo', 'bar')
>>> g.add_edge('foo', 'baz')
>>> g.add_edge('foo', 'quux')
>>> g.separate_nodes()
>>> g.advance_model(1000)
>>> g.get_nodes_and_edges()
({'baz': (471.55908256857947, 672.15410666428852), 'foo': (480.31842017203962, 661.66561410383247), 'bar': (493.7822207984309, 664.00379981011474), 'quux': (475.61105198067708, 648.83709095797167)}, [('foo', 'bar'), ('foo', 'baz'), ('foo', 'quux')])
>>> g.export_as_ps('foo.ps')