1 """
2 Interface to pygraphviz AGraph class.
3
4 Usage
5
6 >>> from networkx import *
7 >>> G=complete_graph(5)
8 >>> A=to_agraph(G)
9 >>> H=from_agraph(A)
10
11 """
12 __author__ = """Aric Hagberg (hagberg@lanl.gov)"""
13
14
15
16
17
18
19 import os
20 import sys
21 from networkx.utils import _get_fh
22 try:
23 import pygraphviz
24 except ImportError:
25 raise
26
28 """Return a NetworkX XGraph or XDiGraph from a pygraphviz graph.
29
30 >>> X=from_agraph(A)
31
32 The XGraph X will have a dictionary X.graph_attr containing
33 the default graphviz attributes for graphs, nodes and edges.
34
35 Default node attributes will be in the dictionary X.node_attr
36 which is keyed by node.
37
38 Edge attributes will be returned as edge data in the graph X.
39
40 If you want a Graph with no attributes attached instead of an XGraph
41 with attributes use
42
43 >>> G=Graph(X)
44
45 """
46 import networkx
47 if A.is_strict():
48 multiedges=False
49 selfloops=False
50 else:
51 multiedges=True
52 selfloops=True
53
54 if create_using is None:
55 if A.is_undirected():
56 create_using=networkx.XGraph(multiedges=multiedges,
57 selfloops=selfloops)
58 else:
59 create_using=networkx.XDiGraph(multiedges=multiedges,
60 selfloops=selfloops)
61
62
63 N=networkx.empty_graph(0,create_using)
64 N.name=str(A)
65 node_attr={}
66
67 for n in A.nodes():
68 N.add_node(n)
69 node_attr[n]=n.attr
70
71
72 for e in A.edges():
73 if len(e)==2:
74 u,v=e
75 else:
76 u,v,k=e
77 if hasattr(N,'allow_multiedges')==True:
78 N.add_edge(u,v,e.attr)
79 else:
80 N.add_edge(u,v)
81
82
83
84 if hasattr(N,'allow_multiedges')==True:
85 N.graph_attr={}
86 N.graph_attr['graph']=A.graph_attr
87 N.graph_attr['node']=A.node_attr
88 N.graph_attr['edge']=A.edge_attr
89 N.node_attr=node_attr
90
91 return N
92
93 -def to_agraph(N, graph_attr=None, node_attr=None, edge_attr=None,
94 strict=True):
95 """Return a pygraphviz graph from a NetworkX graph N.
96
97 If N is a Graph or DiGraph, graphviz attributes can
98 be supplied through the arguments
99
100 graph_attr: dictionary with default attributes for graph, nodes, and edges
101 keyed by 'graph', 'node', and 'edge' to attribute dictionaries
102
103 node_attr: dictionary keyed by node to node attribute dictionary
104
105 edge_attr: dictionary keyed by edge tuple to edge attribute dictionary
106
107 If N is an XGraph or XDiGraph an attempt will be made first
108 to copy properties attached to the graph (see from_agraph)
109 and then updated with the calling arguments if any.
110
111 """
112 directed=N.is_directed()
113 if hasattr(N,'allow_multiedges'):
114 if N.multiedges:
115 strict=False
116 if hasattr(N,'allow_selfloops'):
117 if N.selfloops:
118 strict=False
119 A=pygraphviz.AGraph(name=N.name,strict=strict,directed=directed)
120
121
122 try:
123 A.graph_attr.update(N.graph_attr['graph'])
124 except:
125 pass
126 try:
127 A.graph_attr.update(graph_attr['graph'])
128 except:
129 pass
130
131 try:
132 A.node_attr.update(N.graph_attr['node'])
133 except:
134 pass
135 try:
136 A.node_attr.update(graph_attr['node'])
137 except:
138 pass
139
140 try:
141 A.edge_attr.update(N.graph_attr['edge'])
142 except:
143 pass
144 try:
145 A.edge_attr.update(graph_attr['edge'])
146 except:
147 pass
148
149
150 for n in N.nodes_iter():
151 A.add_node(n)
152 node=pygraphviz.Node(A,n)
153
154 try:
155 if n in N.node_attr:
156 node.attr.update(N.node_attr[n])
157 except:
158 pass
159
160 try:
161 if n in node_attr:
162 node.attr.update(node_attr[n])
163 except:
164 pass
165
166
167 for e in N.edges_iter():
168 if len(e)==2:
169 (u,v)=e
170 data=None
171 else:
172 (u,v,data)=e
173
174 if data is None:
175 A.add_edge(u,v)
176 edge=pygraphviz.Edge(A,u,v)
177 else:
178 try:
179 N.allow_multiedges()==True
180 dlist=N.get_edge(u,v)
181 except:
182 dlist=[N.get_edge(u,v)]
183 for d in dlist:
184 A.add_edge(u,v)
185 edge=pygraphviz.Edge(A,u,v)
186 if hasattr(d,"__getitem__"):
187 edge.attr.update(d)
188
189 try:
190 if (u,v) in edge_attr:
191 edge.attr.update(edge_attr[(u,v)])
192 except:
193 pass
194
195 return A
196
198 """Write NetworkX graph G to Graphviz dot format on path.
199
200 Path can be a string or a file handle.
201 """
202 A=to_agraph(G)
203 A.write(path)
204 return
205
207 """Return a NetworkX XGraph or XdiGraph from a dot file on path.
208
209 Path can be a string or a file handle.
210
211 """
212 A=pygraphviz.AGraph(file=path)
213 return from_agraph(A)
214
215
217 """
218 Create layout using graphviz.
219 Returns a dictionary of positions keyed by node.
220
221 >>> from networkx import *
222 >>> G=petersen_graph()
223 >>> pos=graphviz_layout(G)
224 >>> pos=graphviz_layout(G,prog='dot')
225
226 This is a wrapper for pygraphviz_layout.
227
228 """
229 return pygraphviz_layout(G,prog=prog,root=root,args=args)
230
232 """
233 Create layout using pygraphviz and graphviz.
234 Returns a dictionary of positions keyed by node.
235
236 >>> from networkx import *
237 >>> G=petersen_graph()
238 >>> pos=pygraphviz_layout(G)
239 >>> pos=pygraphviz_layout(G,prog='dot')
240
241 """
242 A=to_agraph(G)
243 A.layout(prog=prog,args=args)
244 node_pos={}
245 for n in G.nodes():
246 node=pygraphviz.Node(A,n)
247 try:
248 xx,yy=node.attr["pos"].split(',')
249 node_pos[n]=(float(xx),float(yy))
250 except:
251 print "no position for node",n
252 node_pos[n]=(0.0,0.0)
253 return node_pos
254
255
257 import doctest
258 suite = doctest.DocFileSuite('tests/drawing/nx_agraph.txt',package='networkx')
259 return suite
260
261
262
263
264 if __name__ == "__main__":
265 import os
266 import sys
267 import unittest
268 if sys.version_info[:2] < (2, 4):
269 print "Python version 2.4 or later required for tests (%d.%d detected)." % sys.version_info[:2]
270 sys.exit(-1)
271
272 nxbase=sys.path[0]+os.sep+os.pardir
273 sys.path.insert(0,nxbase)
274 unittest.TextTestRunner().run(_test_suite())
275