2

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)
CodeFreezr
  • 362
  • 2
  • 18
qfd
  • 778
  • 2
  • 10
  • 24

2 Answers2

4

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.

Bonlenfum
  • 19,101
  • 2
  • 53
  • 56
  • hi thanks for this and apologies for more noob questions – qfd Mar 01 '18 at 16:32
  • 1
    @qfd no probs. If the answer helped resolve your problem, please consider accepting it ([click the green tick at the top left of the answer](https://meta.stackexchange.com/a/5235/208898))! – Bonlenfum Mar 02 '18 at 11:20
  • Good answer, thanks. I was getting the "expected two doubles" complaint trying to build the pos assignment dynamically, until I built the string value for it ahead of time. For each node, from a "vals" position array, I built a pos string, and then assigned it: rows=["A","B","C","D","E"] for r in range(len(rows)): x=str(vals[r][7]+0.0) y=str(vals[r][8]+0.0)+"!" posstr=x+","+y network.node(rows[r],pos=posstr) – gkd720 Mar 05 '20 at 16:54
  • Whoa, thanks!! For me both the format with and without the ! are working, however, if I **don't** put it, then the positions of the nodes are exactly equal to the ones I specify, while if I **do** put it, then the positions are close, but not exactly the ones I specified. I am wondering if it means that they are taken as "initial" positions, and then relaxed to something close to them. Do you know why is this happening? – Tropilio Jul 15 '20 at 16:14
0
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

sroush
  • 5,375
  • 2
  • 5
  • 11