Package networkx :: Package drawing :: Module nx_pydot
[hide private]
[frames] | no frames]

Source Code for Module networkx.drawing.nx_pydot

  1  """ 
  2  Import and export NetworkX graphs in Graphviz dot format using pydot. 
  3   
  4  Provides: 
  5   
  6   - write_dot() 
  7   - read_dot() 
  8   - graphviz_layout() 
  9   - pydot_layout() 
 10   
 11   - to_pydot() 
 12   - from_pydot(0 
 13   
 14  Either this module or nx_pygraphviz can be used to interface with graphviz.   
 15   
 16  References: 
 17   - pydot Homepage: http://www.dkbza.org/pydot.html 
 18   - Graphviz:       http://www.research.att.com/sw/tools/graphviz/ 
 19   - DOT Language:   http://www.research.att.com/~erg/graphviz/info/lang.html 
 20   
 21  """ 
 22  __author__ = """Aric Hagberg (hagberg@lanl.gov)""" 
 23  #    Copyright (C) 2004-2008 by  
 24  #    Aric Hagberg <hagberg@lanl.gov> 
 25  #    Dan Schult <dschult@colgate.edu> 
 26  #    Pieter Swart <swart@lanl.gov> 
 27  #    Distributed under the terms of the GNU Lesser General Public License 
 28  #    http://www.gnu.org/copyleft/lesser.html 
 29  import sys 
 30  from networkx.utils import _get_fh 
 31  try: 
 32      import pydot 
 33  except ImportError: 
 34      raise 
 35   
 36   
37 -def write_dot(G,path):
38 """Write NetworkX graph G to Graphviz dot format on path. 39 40 Path can be a string or a file handle. 41 """ 42 fh=_get_fh(path,'w') 43 P=to_pydot(G) 44 fh.write(P.to_string()) 45 fh.flush() # might be a user filehandle so leave open (but flush) 46 return
47
48 -def read_dot(path):
49 """Return a NetworkX Graph or DiGraph from a dot file on path. 50 51 Path can be a string or a file handle. 52 53 """ 54 fh=_get_fh(path,'r') 55 data=fh.read() 56 P=pydot.graph_from_dot_data(data) 57 return from_pydot(P)
58 59
60 -def from_pydot(P):
61 """Return a NetworkX XGraph or XDiGraph from a pydot graph. 62 63 >>> X=from_pydot(P) 64 65 The XGraph X will have a dictionary X.graph_attr containing 66 the default graphviz attributes for graphs, nodes and edges. 67 68 Default node attributes will be in the dictionary X.node_attr 69 which is keyed by node. 70 71 Edge attributes will be returned as edge data in the graph X. 72 73 If you want a Graph with no attributes attached instead of an XGraph 74 with attributes use 75 76 >>> G=Graph(X) 77 78 Similarly to make a DiGraph from an XDiGraph 79 80 >>> D=DiGraph(X) 81 82 """ 83 import networkx 84 85 if P.get_strict(0): # pydot bug: get_strict() shouldn't take argument 86 multiedges=False 87 selfloops=False 88 else: 89 multiedges=True 90 selfloops=True 91 92 if P.get_type()=='graph': # undirected 93 create_using=networkx.XGraph(multiedges=multiedges, 94 selfloops=selfloops) 95 else: 96 create_using=networkx.XDiGraph(multiedges=multiedges, 97 selfloops=selfloops) 98 99 # assign defaults 100 N=networkx.empty_graph(0,create_using) 101 N.name=P.get_name() 102 node_attr={} 103 104 # add nodes, attributes to N.node_attr 105 for p in P.get_node_list(): 106 n=p.get_name() 107 if n.startswith('"'): 108 n=n[1:-1] 109 if n in ('node','graph','edge'): 110 continue 111 N.add_node(n) 112 node_attr[n]=p.get_attributes() 113 114 # add edges 115 for e in P.get_edge_list(): 116 source=e.get_source() 117 dest=e.get_destination() 118 if hasattr(N,'allow_multiedges')==True: # XGraph or XDiGraph 119 N.add_edge(source,dest,e.get_attributes()) 120 else: # Graph 121 N.add_edge(source,dest) 122 123 # add default attributes for graph, nodes, and edges 124 # hang them on N.graph_attr 125 if hasattr(N,'allow_multiedges')==True: # XGraph 126 N.graph_attr={} 127 N.graph_attr['graph']=P.get_attributes() 128 # get atributes not working for these? 129 # get_node_defaults() 130 if 'node' in P.obj_dict['nodes']: 131 N.graph_attr['node']=P.obj_dict['nodes']['node'][0]['attributes'] 132 # get_edge_defaults() 133 if 'edge' in P.obj_dict['nodes']: 134 N.graph_attr['edge']=P.obj_dict['nodes']['edge'][0]['attributes'] 135 N.node_attr=node_attr 136 137 return N
138
139 -def to_pydot(N, graph_attr=None, node_attr=None, edge_attr=None, 140 strict=True):
141 """Return a pydot graph from a NetworkX graph N. 142 143 If N is a Graph or DiGraph, graphviz attributes can 144 be supplied through the keyword arguments 145 146 graph_attr: dictionary with default attributes for graph, nodes, and edges 147 keyed by 'graph', 'node', and 'edge' to attribute dictionaries 148 149 node_attr: dictionary keyed by node to node attribute dictionary 150 151 edge_attr: dictionary keyed by edge tuple to edge attribute dictionary 152 153 If N is an XGraph or XDiGraph an attempt will be made first 154 to copy properties attached to the graph (see from_pydot) 155 and then updated with the calling arguments, if any. 156 157 """ 158 if hasattr(N,'graph_attr'): 159 graph_attributes=N.graph_attr 160 else: 161 graph_attributes={} 162 if graph_attr is not None: 163 graph_attributes.update(graph_attr) 164 165 directed=N.is_directed() 166 if N.is_directed(): 167 graph_type='digraph' 168 else: 169 graph_type='graph' 170 if hasattr(N,'allow_multiedges'): 171 if N.multiedges: 172 strict=False 173 if hasattr(N,'allow_selfloops'): 174 if N.selfloops: 175 strict=False 176 177 try: 178 node_a=N.node_attr 179 except: 180 node_a={} 181 if node_attr is not None: 182 node_a.update(node_attr) 183 184 P = pydot.Dot(graph_type=graph_type,strict=strict) 185 186 for n in N.nodes_iter(): 187 if n in node_a: 188 attr=node_a[n] 189 else: 190 attr={} 191 p=pydot.Node(str(n),**attr) 192 P.add_node(p) 193 194 for e in N.edges_iter(): 195 if len(e)==2: 196 (u,v)=e 197 edge=pydot.Edge(str(u),str(v)) 198 P.add_edge(edge) 199 if len(e)==3: 200 (u,v,x)=e 201 try: 202 N.allow_multiedges()==True 203 dlist=N.get_edge(u,v) 204 except: 205 dlist=[N.get_edge(u,v)] 206 for d in dlist: 207 if hasattr(d,"__getitem__"): 208 attr=d 209 else: 210 attr={'label':d} 211 try: 212 attr.update(edge_attr[(u,v)]) 213 except: 214 pass 215 edge=pydot.Edge(str(u),str(v),**attr) 216 P.add_edge(edge) 217 218 try: 219 P.obj_dict['attributes'].update(graph_attributes['graph']) 220 except: 221 pass 222 try: 223 P.obj_dict['nodes']['node'][0]['attributes'].update(graph_attributes['node']) 224 except: 225 pass 226 try: 227 P.obj_dict['nodes']['edge'][0]['attributes'].update(graph_attributes['edge']) 228 except: 229 pass 230 231 return P
232 233
234 -def pydot_from_networkx(N):
235 """Creates a pydot graph from an networkx graph N""" 236 from warnings import warn 237 warn('pydot_from_networkx is replaced by to_pydot', DeprecationWarning) 238 return to_pydot(N)
239
240 -def networkx_from_pydot(D, create_using=None):
241 """Creates an networkx graph from an pydot graph D""" 242 from warnings import warn 243 warn('networkx_from_pydot is replaced by from_pydot', 244 DeprecationWarning) 245 return from_pydot(D)
246
247 -def graphviz_layout(G,prog='neato',root=None, **kwds):
248 """Create layout using pydot and graphviz. 249 Returns a dictionary of positions keyed by node. 250 251 >>> pos=graphviz_layout(G) 252 >>> pos=graphviz_layout(G,prog='dot') 253 254 This is a wrapper for pydot_layout. 255 256 """ 257 return pydot_layout(G=G,prog=prog,root=root,**kwds)
258 259
260 -def pydot_layout(G,prog='neato',root=None, **kwds):
261 """ 262 Create layout using pydot and graphviz. 263 Returns a dictionary of positions keyed by node. 264 265 >>> pos=pydot_layout(G) 266 >>> pos=pydot_layout(G,prog='dot') 267 268 """ 269 from networkx.drawing.nx_pydot import pydot_from_networkx 270 try: 271 import pydot 272 except: 273 print "Import Error: not able to import pydot." 274 raise 275 P=to_pydot(G) 276 if root is not None : 277 P.set("root",str(root)) 278 279 D=P.create_dot(prog=prog) 280 281 if D=="": # no data returned 282 print "Graphviz layout with %s failed"%(prog) 283 print 284 print "To debug what happened try:" 285 print "P=pydot_from_networkx(G)" 286 print "P.write_dot(\"file.dot\")" 287 print "And then run %s on file.dot"%(prog) 288 return 289 290 Q=pydot.graph_from_dot_data(D) 291 292 node_pos={} 293 for n in G.nodes(): 294 node=Q.get_node(str(n)) 295 pos=node.get_pos()[1:-1] # strip leading and trailing double quotes 296 if pos != None: 297 xx,yy=pos.split(",") 298 node_pos[n]=(float(xx),float(yy)) 299 return node_pos
300
301 -def _test_suite():
302 import doctest 303 suite = doctest.DocFileSuite('tests/drawing/nx_pydot.txt',package='networkx') 304 return suite
305 306 307 if __name__ == "__main__": 308 import os 309 import sys 310 import unittest 311 if sys.version_info[:2] < (2, 4): 312 print "Python version 2.4 or later required for tests (%d.%d detected)." % sys.version_info[:2] 313 sys.exit(-1) 314 # directory of networkx package (relative to this) 315 nxbase=sys.path[0]+os.sep+os.pardir 316 sys.path.insert(0,nxbase) # prepend to search path 317 unittest.TextTestRunner().run(_test_suite()) 318