Search code examples
pythongraphgraphviznetworkxpygraphviz

What could cause NetworkX & PyGraphViz to work fine alone but not together?


I'm working to learning some Python graph visualization. I found a few blog posts doing some things I wanted to try. Unfortunately I didn't get too far, encountering this error: AttributeError: 'module' object has no attribute 'graphviz_layout'

The simplest snip of code which reproduces the error on my system is this,

In [1]: import networkx as nx
In [2]: G=nx.complete_graph(5)
In [3]: nx.draw_graphviz(G)
------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-481ad1c1771c> in <module>()
----> 1 nx.draw_graphviz(G)
/usr/lib/python2.7/site-packages/networkx/drawing/nx_pylab.pyc in draw_graphviz(G, prog, **kwargs)
982 See networkx.draw_networkx() for a description of optional keywords.
983 """
--> 984 pos = nx.drawing.graphviz_layout(G, prog)
985 draw(G, pos, **kwargs)
986
AttributeError: 'module' object has no attribute 'graphviz_layout'

I found a similar questions, and posts having difficulty with this combo, but not quite the same error. One was close, but it automagically resolved itself.

First, I verified all the required packages for NetworkX and PyGraphViz (which lists similar requirements to Scipy) were installed.

Next, I looked for snips to test my installation of these modules in Python. The first two examples are from the NetworkX Reference Documentation. This lists a few example snips using both MatPlotLib and GraphViz.

The MatPlotLib code example works for me (renders an image to the screen),

In [11]: import networkx as nx
In [12]: G=nx.complete_graph(5)
In [13]: import matplotlib.pyplot as plt
In [13]: nx.draw(G)
In [13]: plt.show()  

However, the GraphViz snips also produce similar errors,

In [16]: import networkx as nx
In [17]: G=nx.complete_graph(5)
In [18]: H=nx.from_agraph(A)
------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-18-808fa68cefaa> in <module>()
----> 1 H=nx.from_agraph(A)
AttributeError: 'module' object has no attribute 'from_agraph'
In [19]: A=nx.to_agraph(G)
------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-19-32d1616bb41a> in <module>()
----> 1 A=nx.to_agraph(G)
AttributeError: 'module' object has no attribute 'to_agraph'
In [20]: print G
complete_graph(5)

Then I tried PyGraphViz's tutorial page on Layout & Drawing. This has some snips as well. PyGraphViz passed with Neato (default), PyDot, and Circo Post Script output (viewed using Gimp). (The only difference is these PyGraphViz examples are not rendered to the display, but to files).

In [1]: import pygraphviz as pgv
In [2]: d={'1': {'2': None}, '2': {'1': None, '3': None}, '3': {'2': None}}
In [3]: A=pgv.AGraph(d)
In [4]: A.write("pygraphviz_test_01.dot")
In [5]: A.layout()
In [6]: A.draw('pygraphviz_test_01.png')

Adding to the complexity, PyGraphViz requires GraphViz package binaries in order to work. I'm using Arch Linux, and installed that distro's version. Arch Linux has an example to test installation (again, output to file) which also passed.

What am I missing? What could cause NetworkX & PyGraphViz to work fine alone but not together?


Solution

  • There is a small bug in the draw_graphviz function in networkx-1.11 triggered by the change that the graphviz drawing tools are no longer imported into the top level namespace of networkx.

    The following is a workaround

    In [1]: import networkx as nx
    
    In [2]: G = nx.complete_graph(5)
    
    In [3]: from networkx.drawing.nx_agraph import graphviz_layout
    
    In [4]: pos = graphviz_layout(G)
    
    In [5]: nx.draw(G, pos)
    

    To use the other functions such as to_agraph, write_dot, etc you will need to explicitly use the longer path name

     nx.drawing.nx_agraph.write_dot()
    

    or import the function into the top-level namespace

    from networkx.drawing.nx_agraph import write_dot()
    write_dot()
    

    These command use graphviz to calculate the positioning of the nodes (graphviz_layout uses neato per default), and matplotlib to actually plot (i.e. draw) the graph.