Search code examples
pythonpositionnodesjupytergraphviz

Set node positions using Graphviz in Jupyter Python


I want to make a graph with random node positions but it seems that the "pos" attribute for nodes does nothing. Here is a minimal example:

import graphviz
import pylab
from graphviz import Digraph

g = Digraph('G', filename='ex.gv',format='pdf')
g.attr(size='7')
g.node('1',pos='1,2')
g.node('2',pos='2,3')
g.node('3',pos='0,0')
g.edge('1','2')
g.edge('1','3')
graphviz.Source(g)

Any ideas of how achieve that? Thanks in advance.


Solution

  • Although not 100% clear in the docs, I think pos is not supported in the dot engine on input. The fdp or neato engines do support pos on input for setting the initial position, and if you end the coordinate specification with '!', the coordinates will not change and thus become the final node position.

    Play with a live example at https://beta.observablehq.com/@magjac/placing-graphviz-nodes-in-fixed-positions

    This standalone python script generates a pdf with the expected node positions:

    #!/usr/bin/python
    
    import graphviz
    from graphviz import Digraph
    
    g = Digraph('G', engine="neato", filename='ex.gv',format='pdf')
    g.attr(size='7')
    g.node('1',pos='1,2!')
    g.node('2',pos='2,3!')
    g.node('3',pos='0,0!')
    g.edge('1','2')
    g.edge('1','3')
    g.render()
    

    Since SO does not support pdf uploading, here's a png image generated with the same code except format='png':

    enter image description here

    Without the exclamation marks you get:

    enter image description here

    Without any pos attributes at all you get a similar (but not exactly the same) result:

    enter image description here