qfd
qfd

Reputation: 788

converting network graph to graphviz

I am having trouble visualizing a multidirectional graph with parallel edges in networkx so I have resorted to using pydot, but I am having two issues

1) I cant seem to understand why the node positions are not being fixed I would like to plot them at the x and y specified coordinates 2) How do I set the size of the figure being plotted the plt.figure command does not really work 3) How do I add edge labels (if I had them)

many thanks

import networkx as nx  
from io import StringIO
from io import BytesIO

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import networkx as nx


graph= nx.MultiGraph()                                                                                    

#add 4 nodes in the vertexs of a square. X and Y are the coordinates                                      
graph.add_node(1,x=100,y=100)                                                                             
graph.add_node(2,x=100,y=200)                                                                             
graph.add_node(3,x=200,y=100)                                                                             
graph.add_node(4,x=200,y=200)                                                                             
graph.add_edge(1,2)                                                                                       
graph.add_edge(2,1)   
graph.add_edge(3,1)
graph.add_edge(3,4)                                                                                       
graph.add_edge(4,1)                                                                                       
                                                                                                         # assign positions                                                                                        
for n in graph:                                                                                           
    graph.node[n]['pos'] = '"%d,%d"'%(graph.node[n]['x'], graph.node[n]['y'])                             
p = nx.drawing.nx_pydot.to_pydot(graph)                                                                                    

# render pydot by calling dot, no file saved to disk
png_str = p.create_png(prog='C:\\Anaconda3\\Library\\bin\\graphviz\\dot.exe')

# treat the dot output string as an image file
sio = BytesIO()
sio.write(png_str)
sio.seek(0)
img = mpimg.imread(sio)





plt.figure(figsize = (10,10))
imgplot = plt.imshow(img)

Upvotes: 2

Views: 2810

Answers (2)

sroush
sroush

Reputation: 6801

digraph G {
    graph [bb="0,0,270,396",
        sep="+6",
        splines=true
    ];
    node [label="\N",
        nodesep=.4,
        pin=true,
        style=invis
    ];
    edge [style=invis];
    {
        graph [rank=same];
        node [style=solid];
        1   [height=0.5,
            pos="27,378",
            width=0.75];
    }
    {
        graph [rank=same];
        node [style=solid];
        2   [height=0.5,
            pos="27,306",
            width=0.75];
        3   [height=0.5,
            pos="99,306",
            width=0.75];
        5   [height=0.5,
            pos="243,306",
            width=0.75];
    }
    {
        graph [rank=same];
        node [style=solid];
        c1  [height=0.5,
            pos="27,234",
            style=invis,
            width=0.75];
        6   [height=0.5,
            pos="99,234",
            width=0.75];
    }

    1 -> 2  [pos="e,27,324.1 27,359.7 27,351.98 27,342.71 27,334.11"];
    2 -> c1 [pos="e,27,252.1 27,287.7 27,279.98 27,270.71 27,262.11"];

edge[constraint=false style=solid]  

1 -> 2 [label=aaa ]
1 -> 3 [label=abb] 
1 -> 5 [label=abc ]
1 -> 6   [label=aba]
3 -> 6 
}

Linux command to run neato - note the "-s" option
F=stylized1Tiny; neato -s -Tpng $F.dot >$F.png;

enter image description here

Upvotes: 0

Bonlenfum
Bonlenfum

Reputation: 20175

TLDR (a) use neato, not dot to draw (b) pos attrs should be of the form "100,200!" in the dot file. Don't double-quote it, and add an ! mark.

Firstly, not all of the graphviz tools support positions. See docs:

In neato and fdp, pos can be used to set the initial position of a node

Secondly, once you are using a tool that reads the pos attribute, you'll see some errors in the output. To understand problems with an external tool, it makes more sense to test it in isolation, so let's do that to file:

nx.drawing.write_dot(graph, "test.dot")

And then run neato:

> neato -Tpng test.dot >test1.png 
Error: node 1, position "100,100", expected two doubles
Error: node 2, position "100,200", expected two doubles
Error: node 3, position "200,100", expected two doubles
Error: node 4, position "200,200", expected two doubles

You'll now see that the format isn't right. And so neato proceeds to layout the graph as if pos wasn't specified.

automatic layout, ignoring pos attr

for n in graph:
    graph.node[n]['pos'] = "{},{}!".format(
        graph.node[n]['x'], graph.node[n]['y'])

Now try again:

nx.drawing.write_dot(graph, "test_fix.dot")

# note: the -n flag causes neato to use points rather than inches. 
# see docs, and/or experiment with -s setting as well
> neato -n -Tpng test_fix.dot >test2.png 

And positions are now respected:

format of pos argument correct

Edge labels and image size

The dot manual and this site both have info on how to draw edge labels (e.g. How to add edge labels in Graphviz? or Graphviz: Place edge label on the other side (II)), and obviously you need to add some property to your graph (see "associate data to edges using keywords": https://networkx.github.io/documentation/networkx-1.10/reference/generated/networkx.DiGraph.add_edge.html )

It isn't clear what you mean by "plt.figure command does not really work" but this is quite far from the networkx issues here so I think it would be better to post a new question that isolates the problem and explains it fully.

Upvotes: 4

Related Questions