Search code examples
pythongraphvizpygraphviz

pygraphviz 1.5 default edge no arrow?


I have updated to pygraphviz 1.5 using this wheel here Installing pygraphviz on Windows 10 64-bit, Python 3.6.

I'm having problems with it.

import pygraphviz as pgv

G = pgv.AGraph()

G.add_node('a')
G.add_node('b')
G.add_edge('a', 'b')
g_string = G.string()

print(g_string)

gives me

strict digraph {
    a -- b;
}

while the same code ran on previous version 1.3 gives me

strict digraph {
    a -> b;
}

I have even tried

G.add_edge('a', 'b', arrowhead="normal") which gives a -- b [arrowhead=normal]; but draws with no arrowheads.

I'm running graphviz 2.38. pygraphviz 1.3 on python 2.7. pygraphviz 1.5 on python 3.6.


Solution

  • I want to start by pointing out that in order for this example to work, it's not enough to have the PyGraphviz module installed (check [SO]: Installing pygraphviz on Windows 10 64-bit, Python 3.6 (@CristiFati's answer)), but a version of Graphviz is required as well, as PyGraphviz uses one of its tools (called nop).
    It is available for download, anyway I chose to build it (for 32bit, but that's not relevant).

    Also, I tested with 2 .whls:

    • One (that I've) built for Python 3.6 (64 bit)
    • One built for Python 2.7 (64 bit)

    Since there was the possibility of me having to modify them (for debugging purposes), I didn't pip install them, but rather unpacked them in cwd (which required some extra code):

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> dir /b
    code00.py
    pygraphviz131_27
    pygraphviz15_36
    
    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> tree /a
    Folder PATH listing for volume Work
    Volume serial number is 3655-6FED
    E:.
    +---pygraphviz131_27
    |   \---pygraphviz
    |       \---tests
    \---pygraphviz15_36
        \---pygraphviz
            \---tests
    

    code00.py:

    #!/usr/bin/env python3
    
    import sys
    
    
    # @TODO - cfati: The 5 lines below are because I unpacked the 2 `.whl`s in the current dir, instead of `pip install`ing them
    maj, min = sys.version_info[:2]
    if maj == 3 and min == 6:
        sys.path.insert(0, "pygraphviz15_36")
    elif maj == 2 and min == 7:
        sys.path.insert(0, "pygraphviz131_27")
    # @TODO end
    
    import pygraphviz as pgv
    
    
    def main():
        print(pgv)
        g = pgv.AGraph(directed=len(sys.argv) > 1)
        g.add_node("a")
        g.add_node("b")
        g.add_edge("a", "b")
        #print(dir(g))
        g_string = g.string()  # Nice var name, btw :)
        print(g_string)
    
    
    if __name__ == "__main__":
        print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
        main()
    

    Output:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> set PATH=%PATH%;e:\Work\Dev\Fati\WinBuild\graphviz\src\graphviz\Release\Graphviz\bin
    
    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> "e:\Work\Dev\VEnvs\py_064_02.07.15_test0\Scripts\python.exe" code00.py
    Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32
    
    <module 'pygraphviz' from 'pygraphviz131_27\pygraphviz\__init__.pyc'>
    strict digraph {
            a -> b;
    }
    
    
    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code00.py
    Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32
    
    <module 'pygraphviz' from 'pygraphviz15_36\\pygraphviz\\__init__.py'>
    strict graph "" {
            a -- b;
    }
    

    As seen, the problem is easily reproducible. Now, the outputs -- vs. -> look awfully a lot to how I'd represent an undirected vs. directed graph edge. I looked in the source code and found something strange.

    [GitHub.PyGraphviz 1.5]: class AGraph(thing=None, filename=None, data=None, string=None, handle=None, name='', strict=True, directed=False, **attr) has the directed=False arg. Setting it to True, fixed the problem.

    Output:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> "e:\Work\Dev\VEnvs\py_064_02.07.15_test0\Scripts\python.exe" code00.py dummy_arg
    Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32
    
    <module 'pygraphviz' from 'pygraphviz131_27\pygraphviz\__init__.pyc'>
    strict digraph {
            a -> b;
    }
    
    
    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055196206]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code00.py dummy_arg
    Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32
    
    <module 'pygraphviz' from 'pygraphviz15_36\\pygraphviz\\__init__.py'>
    strict digraph "" {
            a -> b;
    }
    

    I said that I discovered something strange: well, for PyGraphviz 1.3.1 things are the same: directed=False (code and doc), yet it somehow initializes the graph as it would be directed.
    A quick check on agraph.py (on the 2 package versions) didn't reveal where this difference comes from, so I can safely assume that it's because of Graphviz package versions that the 2 PyGraphviz versions were built with.

    Nevertheless, PyGraphviz 1.5 (built by me) behavior is the correct one.