Michael
Michael

Reputation: 1905

Getting layout coordinates of graph vertices using python, networkx, pygraphviz

I want to create a graph using NetworkX, layout the graph using Graphviz(via pygraphviz). I have successfully ran all the examples in the NetworkX pygraphviz examples documentation

The question I have is - how do I get the coordinates (x, y) and dimensions (width, height) of the vertices back into the NetworkX graph. That is the goal. I want only Graphviz' layout capabilities, not drawing capabilities. Is that possible using this stack (NetworkX, pygraphviz, graphviz)? Any other way?

The background motivation is this. Graphviz outputs png, or ps, or svg and many other formats. But I don't want to be constrained by the formats Graphviz handles. And I want to be able to post-process the layout results, even if I end up outputting the popular formats like Graphviz does support.

Update: I have rewritten the question for clarity. The advice on Graphviz output formats miss the point. It is the layout data that I need

Update2: One suggestion was to make Graphviz ouptput in some format that I can then parse the layout data back from. The suggestion was for SVG. I had had considered that possibility. Graphviz outputs json (according to Graphviz output formats documentation page). I failed to make it work on my windows installation - for some reason not all the output formats were present). However it is the approach that makes me uneasy. Parsing formatted output for data that was used to create that output seems backwards. The data itself should have been made available, I think.

Update 3 - There is a similar question - How to get the coordinates from layout from graphviz?. One of the answers suggests using NetworkX. However the answer uses layout made by NetworkX and not Graphviz. The author of the answer did not know how to get the Graphviz layout data. So my question remains relevant, and yet to be answered

Update 4 - it is 07-2019 and I still did not find a way to solve this. I marked one answer as accepted - but with a caveat - I still am in the dark despite the good advice found in that answer

Upvotes: 3

Views: 1878

Answers (4)

Jonathan Laurent
Jonathan Laurent

Reputation: 423

Here is another solution. It differs from Dominik Kummer's as it exposes the pygraphviz.AGraph object, making it possible to specify arbitrary gaphviz attributes to customize the layout.

import networkx as nx
import pygraphviz as pgv

g = nx.complete_graph(10)
ag = nx.drawing.nx_agraph.to_agraph(g)
ag.layout(prog='dot')
layout = [ag.get_node(n).attr['pos'] for n in ag.nodes()]
layout = [[int(ss) for ss in s.split(",")] for s in layout]
print(layout)

give me:

[[327, 666], [504, 594], [327, 522], [449, 450], [283, 378], [283, 306], [473, 234], [287, 162], [418, 90], [287, 18]]

Upvotes: 1

domson
domson

Reputation: 221

regarding Update 4

it is still 2019 but this works perfectly for my needs

import networkx as nx
G = nx.complete_graph(10)
pos = nx.drawing.nx_agraph.graphviz_layout(G, prog='dot')
print(pos)

give me

{0: (327.0, 666.0), 1: (504.0, 594.0), 2: (327.0, 522.0), 3: (449.0, 450.0), 4: (283.0, 378.0), 5: (283.0, 306.0), 6: (473.0, 234.0), 7: (287.0, 162.0), 8: (418.0, 90.0), 9: (287.0, 18.0)}

a dict of nodes and positions!

Greets dom

Upvotes: 1

Aric
Aric

Reputation: 25299

PyGraphviz doesn't have an API for retrieving and setting layout information such as node shapes, edge routing, etc. I'm not aware of any Python interface to those parts of the Graphviz C library. Graphviz itself does provide a Python interface including to the renderer but I don't think it does exactly what you want either - see http://www.graphviz.org/pdf/gv.3python.pdf.

The simplest approach may indeed by generating SVG as @JHL suggests.

Upvotes: 0

TomServo
TomServo

Reputation: 7409

Michael, I re-read your question and comments and with the tools I know that work (and I know how to use), this is what I'd do in your shoes. I would draw your charts in DOT/GraphViz and then choose a human-readable and easy-to-parse format such as SVG, "plain", or even x-dot. Why? Not to get the graph itself -- some of these don't even realize graphs -- but because these formats are human-readable and contain the X-Y coordinates of the different drawing components. You can use those coordinates and sizes to your own purposes. Some snips from a simple graph I just did should illustrate. SVG first

<svg width="89pt" height="188pt"

<g id="node1" class="node"><title>A</title>
<ellipse fill="none" stroke="black" cx="54" cy="-162" rx="27" ry="18"/>
<text text-anchor="middle" x="54" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">A</text>

Or in "plain" format, perhaps simplest for parsing:

graph 1 0.75 1.5
node A 0.375 1.25 0.75 0.5 A solid ellipse black lightgrey
node B 0.375 0.25 0.75 0.5 B solid ellipse black lightgrey
edge A B 4 0.375 0.99579 0.375 0.88865 0.375 0.7599 0.375 0.64045 solid black
stop

Or VML which is html-like:

<v:oval style="position:absolute; left: 0.00; top: 0.00; width: 54.00; height: 36.00" filled="false"  >

Etc... Not hard to imagine parsing out all the X-Ys of the various elements and repurposing them as you see fit.

Upvotes: 1

Related Questions