1cef7893435aa41160dd1255c43cb8498279738ccChris Craik''' 2cef7893435aa41160dd1255c43cb8498279738ccChris Craikaltgraph.Dot - Interface to the dot language 3cef7893435aa41160dd1255c43cb8498279738ccChris Craik============================================ 4cef7893435aa41160dd1255c43cb8498279738ccChris Craik 5cef7893435aa41160dd1255c43cb8498279738ccChris CraikThe :py:mod:`~altgraph.Dot` module provides a simple interface to the 6cef7893435aa41160dd1255c43cb8498279738ccChris Craikfile format used in the `graphviz <http://www.research.att.com/sw/tools/graphviz/>`_ 7cef7893435aa41160dd1255c43cb8498279738ccChris Craikprogram. The module is intended to offload the most tedious part of the process 8cef7893435aa41160dd1255c43cb8498279738ccChris Craik(the **dot** file generation) while transparently exposing most of its features. 9cef7893435aa41160dd1255c43cb8498279738ccChris Craik 10cef7893435aa41160dd1255c43cb8498279738ccChris CraikTo display the graphs or to generate image files the `graphviz <http://www.research.att.com/sw/tools/graphviz/>`_ 11cef7893435aa41160dd1255c43cb8498279738ccChris Craikpackage needs to be installed on the system, moreover the :command:`dot` and :command:`dotty` programs must 12cef7893435aa41160dd1255c43cb8498279738ccChris Craikbe accesible in the program path so that they can be ran from processes spawned 13cef7893435aa41160dd1255c43cb8498279738ccChris Craikwithin the module. 14cef7893435aa41160dd1255c43cb8498279738ccChris Craik 15cef7893435aa41160dd1255c43cb8498279738ccChris CraikExample usage 16cef7893435aa41160dd1255c43cb8498279738ccChris Craik------------- 17cef7893435aa41160dd1255c43cb8498279738ccChris Craik 18cef7893435aa41160dd1255c43cb8498279738ccChris CraikHere is a typical usage:: 19cef7893435aa41160dd1255c43cb8498279738ccChris Craik 20cef7893435aa41160dd1255c43cb8498279738ccChris Craik from altgraph import Graph, Dot 21cef7893435aa41160dd1255c43cb8498279738ccChris Craik 22cef7893435aa41160dd1255c43cb8498279738ccChris Craik # create a graph 23cef7893435aa41160dd1255c43cb8498279738ccChris Craik edges = [ (1,2), (1,3), (3,4), (3,5), (4,5), (5,4) ] 24cef7893435aa41160dd1255c43cb8498279738ccChris Craik graph = Graph.Graph(edges) 25cef7893435aa41160dd1255c43cb8498279738ccChris Craik 26cef7893435aa41160dd1255c43cb8498279738ccChris Craik # create a dot representation of the graph 27cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot = Dot.Dot(graph) 28cef7893435aa41160dd1255c43cb8498279738ccChris Craik 29cef7893435aa41160dd1255c43cb8498279738ccChris Craik # display the graph 30cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.display() 31cef7893435aa41160dd1255c43cb8498279738ccChris Craik 32cef7893435aa41160dd1255c43cb8498279738ccChris Craik # save the dot representation into the mydot.dot file 33cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.save_dot(file_name='mydot.dot') 34cef7893435aa41160dd1255c43cb8498279738ccChris Craik 35cef7893435aa41160dd1255c43cb8498279738ccChris Craik # save dot file as gif image into the graph.gif file 36cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.save_img(file_name='graph', file_type='gif') 37cef7893435aa41160dd1255c43cb8498279738ccChris Craik 38cef7893435aa41160dd1255c43cb8498279738ccChris CraikDirected graph and non-directed graph 39cef7893435aa41160dd1255c43cb8498279738ccChris Craik------------------------------------- 40cef7893435aa41160dd1255c43cb8498279738ccChris Craik 41cef7893435aa41160dd1255c43cb8498279738ccChris CraikDot class can use for both directed graph and non-directed graph 42cef7893435aa41160dd1255c43cb8498279738ccChris Craikby passing ``graphtype`` parameter. 43cef7893435aa41160dd1255c43cb8498279738ccChris Craik 44cef7893435aa41160dd1255c43cb8498279738ccChris CraikExample:: 45cef7893435aa41160dd1255c43cb8498279738ccChris Craik 46cef7893435aa41160dd1255c43cb8498279738ccChris Craik # create directed graph(default) 47cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot = Dot.Dot(graph, graphtype="digraph") 48cef7893435aa41160dd1255c43cb8498279738ccChris Craik 49cef7893435aa41160dd1255c43cb8498279738ccChris Craik # create non-directed graph 50cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot = Dot.Dot(graph, graphtype="graph") 51cef7893435aa41160dd1255c43cb8498279738ccChris Craik 52cef7893435aa41160dd1255c43cb8498279738ccChris CraikCustomizing the output 53cef7893435aa41160dd1255c43cb8498279738ccChris Craik---------------------- 54cef7893435aa41160dd1255c43cb8498279738ccChris Craik 55cef7893435aa41160dd1255c43cb8498279738ccChris CraikThe graph drawing process may be customized by passing 56cef7893435aa41160dd1255c43cb8498279738ccChris Craikvalid :command:`dot` parameters for the nodes and edges. For a list of all 57cef7893435aa41160dd1255c43cb8498279738ccChris Craikparameters see the `graphviz <http://www.research.att.com/sw/tools/graphviz/>`_ 58cef7893435aa41160dd1255c43cb8498279738ccChris Craikdocumentation. 59cef7893435aa41160dd1255c43cb8498279738ccChris Craik 60cef7893435aa41160dd1255c43cb8498279738ccChris CraikExample:: 61cef7893435aa41160dd1255c43cb8498279738ccChris Craik 62cef7893435aa41160dd1255c43cb8498279738ccChris Craik # customizing the way the overall graph is drawn 63cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.style(size='10,10', rankdir='RL', page='5, 5' , ranksep=0.75) 64cef7893435aa41160dd1255c43cb8498279738ccChris Craik 65cef7893435aa41160dd1255c43cb8498279738ccChris Craik # customizing node drawing 66cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.node_style(1, label='BASE_NODE',shape='box', color='blue' ) 67cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.node_style(2, style='filled', fillcolor='red') 68cef7893435aa41160dd1255c43cb8498279738ccChris Craik 69cef7893435aa41160dd1255c43cb8498279738ccChris Craik # customizing edge drawing 70cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.edge_style(1, 2, style='dotted') 71cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.edge_style(3, 5, arrowhead='dot', label='binds', labelangle='90') 72cef7893435aa41160dd1255c43cb8498279738ccChris Craik dot.edge_style(4, 5, arrowsize=2, style='bold') 73cef7893435aa41160dd1255c43cb8498279738ccChris Craik 74cef7893435aa41160dd1255c43cb8498279738ccChris Craik 75cef7893435aa41160dd1255c43cb8498279738ccChris Craik.. note:: 76cef7893435aa41160dd1255c43cb8498279738ccChris Craik 77cef7893435aa41160dd1255c43cb8498279738ccChris Craik dotty (invoked via :py:func:`~altgraph.Dot.display`) may not be able to 78cef7893435aa41160dd1255c43cb8498279738ccChris Craik display all graphics styles. To verify the output save it to an image file 79cef7893435aa41160dd1255c43cb8498279738ccChris Craik and look at it that way. 80cef7893435aa41160dd1255c43cb8498279738ccChris Craik 81cef7893435aa41160dd1255c43cb8498279738ccChris CraikValid attributes 82cef7893435aa41160dd1255c43cb8498279738ccChris Craik---------------- 83cef7893435aa41160dd1255c43cb8498279738ccChris Craik 84cef7893435aa41160dd1255c43cb8498279738ccChris Craik - dot styles, passed via the :py:meth:`Dot.style` method:: 85cef7893435aa41160dd1255c43cb8498279738ccChris Craik 86cef7893435aa41160dd1255c43cb8498279738ccChris Craik rankdir = 'LR' (draws the graph horizontally, left to right) 87cef7893435aa41160dd1255c43cb8498279738ccChris Craik ranksep = number (rank separation in inches) 88cef7893435aa41160dd1255c43cb8498279738ccChris Craik 89cef7893435aa41160dd1255c43cb8498279738ccChris Craik - node attributes, passed via the :py:meth:`Dot.node_style` method:: 90cef7893435aa41160dd1255c43cb8498279738ccChris Craik 91cef7893435aa41160dd1255c43cb8498279738ccChris Craik style = 'filled' | 'invisible' | 'diagonals' | 'rounded' 92cef7893435aa41160dd1255c43cb8498279738ccChris Craik shape = 'box' | 'ellipse' | 'circle' | 'point' | 'triangle' 93cef7893435aa41160dd1255c43cb8498279738ccChris Craik 94cef7893435aa41160dd1255c43cb8498279738ccChris Craik - edge attributes, passed via the :py:meth:`Dot.edge_style` method:: 95cef7893435aa41160dd1255c43cb8498279738ccChris Craik 96cef7893435aa41160dd1255c43cb8498279738ccChris Craik style = 'dashed' | 'dotted' | 'solid' | 'invis' | 'bold' 97cef7893435aa41160dd1255c43cb8498279738ccChris Craik arrowhead = 'box' | 'crow' | 'diamond' | 'dot' | 'inv' | 'none' | 'tee' | 'vee' 98cef7893435aa41160dd1255c43cb8498279738ccChris Craik weight = number (the larger the number the closer the nodes will be) 99cef7893435aa41160dd1255c43cb8498279738ccChris Craik 100cef7893435aa41160dd1255c43cb8498279738ccChris Craik - valid `graphviz colors <http://www.research.att.com/~erg/graphviz/info/colors.html>`_ 101cef7893435aa41160dd1255c43cb8498279738ccChris Craik 102cef7893435aa41160dd1255c43cb8498279738ccChris Craik - for more details on how to control the graph drawing process see the 103cef7893435aa41160dd1255c43cb8498279738ccChris Craik `graphviz reference <http://www.research.att.com/sw/tools/graphviz/refs.html>`_. 104cef7893435aa41160dd1255c43cb8498279738ccChris Craik''' 105cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport os 106cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport warnings 107cef7893435aa41160dd1255c43cb8498279738ccChris Craik 108cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom altgraph import GraphError 109cef7893435aa41160dd1255c43cb8498279738ccChris Craik 110cef7893435aa41160dd1255c43cb8498279738ccChris Craik 111cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass Dot(object): 112cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 113cef7893435aa41160dd1255c43cb8498279738ccChris Craik A class providing a **graphviz** (dot language) representation 114cef7893435aa41160dd1255c43cb8498279738ccChris Craik allowing a fine grained control over how the graph is being 115cef7893435aa41160dd1255c43cb8498279738ccChris Craik displayed. 116cef7893435aa41160dd1255c43cb8498279738ccChris Craik 117cef7893435aa41160dd1255c43cb8498279738ccChris Craik If the :command:`dot` and :command:`dotty` programs are not in the current system path 118cef7893435aa41160dd1255c43cb8498279738ccChris Craik their location needs to be specified in the contructor. 119cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 120cef7893435aa41160dd1255c43cb8498279738ccChris Craik 121cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __init__(self, graph=None, nodes=None, edgefn=None, nodevisitor=None, edgevisitor=None, name="G", dot='dot', dotty='dotty', neato='neato', graphtype="digraph"): 122cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 123cef7893435aa41160dd1255c43cb8498279738ccChris Craik Initialization. 124cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 125cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.name, self.attr = name, {} 126cef7893435aa41160dd1255c43cb8498279738ccChris Craik 127cef7893435aa41160dd1255c43cb8498279738ccChris Craik assert graphtype in ['graph', 'digraph'] 128cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.type = graphtype 129cef7893435aa41160dd1255c43cb8498279738ccChris Craik 130cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.temp_dot = "tmp_dot.dot" 131cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.temp_neo = "tmp_neo.dot" 132cef7893435aa41160dd1255c43cb8498279738ccChris Craik 133cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.dot, self.dotty, self.neato = dot, dotty, neato 134cef7893435aa41160dd1255c43cb8498279738ccChris Craik 135cef7893435aa41160dd1255c43cb8498279738ccChris Craik # self.nodes: node styles 136cef7893435aa41160dd1255c43cb8498279738ccChris Craik # self.edges: edge styles 137cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.nodes, self.edges = {}, {} 138cef7893435aa41160dd1255c43cb8498279738ccChris Craik 139cef7893435aa41160dd1255c43cb8498279738ccChris Craik if graph is not None and nodes is None: 140cef7893435aa41160dd1255c43cb8498279738ccChris Craik nodes = graph 141cef7893435aa41160dd1255c43cb8498279738ccChris Craik if graph is not None and edgefn is None: 142cef7893435aa41160dd1255c43cb8498279738ccChris Craik def edgefn(node, graph=graph): 143cef7893435aa41160dd1255c43cb8498279738ccChris Craik return graph.out_nbrs(node) 144cef7893435aa41160dd1255c43cb8498279738ccChris Craik if nodes is None: 145cef7893435aa41160dd1255c43cb8498279738ccChris Craik nodes = () 146cef7893435aa41160dd1255c43cb8498279738ccChris Craik 147cef7893435aa41160dd1255c43cb8498279738ccChris Craik seen = set() 148cef7893435aa41160dd1255c43cb8498279738ccChris Craik for node in nodes: 149cef7893435aa41160dd1255c43cb8498279738ccChris Craik if nodevisitor is None: 150cef7893435aa41160dd1255c43cb8498279738ccChris Craik style = {} 151cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 152cef7893435aa41160dd1255c43cb8498279738ccChris Craik style = nodevisitor(node) 153cef7893435aa41160dd1255c43cb8498279738ccChris Craik if style is not None: 154cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.nodes[node] = {} 155cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.node_style(node, **style) 156cef7893435aa41160dd1255c43cb8498279738ccChris Craik seen.add(node) 157cef7893435aa41160dd1255c43cb8498279738ccChris Craik if edgefn is not None: 158cef7893435aa41160dd1255c43cb8498279738ccChris Craik for head in seen: 159cef7893435aa41160dd1255c43cb8498279738ccChris Craik for tail in (n for n in edgefn(head) if n in seen): 160cef7893435aa41160dd1255c43cb8498279738ccChris Craik if edgevisitor is None: 161cef7893435aa41160dd1255c43cb8498279738ccChris Craik edgestyle = {} 162cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 163cef7893435aa41160dd1255c43cb8498279738ccChris Craik edgestyle = edgevisitor(head, tail) 164cef7893435aa41160dd1255c43cb8498279738ccChris Craik if edgestyle is not None: 165cef7893435aa41160dd1255c43cb8498279738ccChris Craik if head not in self.edges: 166cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.edges[head] = {} 167cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.edges[head][tail] = {} 168cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.edge_style(head, tail, **edgestyle) 169cef7893435aa41160dd1255c43cb8498279738ccChris Craik 170cef7893435aa41160dd1255c43cb8498279738ccChris Craik def style(self, **attr): 171cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 172cef7893435aa41160dd1255c43cb8498279738ccChris Craik Changes the overall style 173cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 174cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.attr = attr 175cef7893435aa41160dd1255c43cb8498279738ccChris Craik 176cef7893435aa41160dd1255c43cb8498279738ccChris Craik def display(self, mode='dot'): 177cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 178cef7893435aa41160dd1255c43cb8498279738ccChris Craik Displays the current graph via dotty 179cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 180cef7893435aa41160dd1255c43cb8498279738ccChris Craik 181cef7893435aa41160dd1255c43cb8498279738ccChris Craik if mode == 'neato': 182cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.save_dot(self.temp_neo) 183cef7893435aa41160dd1255c43cb8498279738ccChris Craik neato_cmd = "%s -o %s %s" % (self.neato, self.temp_dot, self.temp_neo) 184cef7893435aa41160dd1255c43cb8498279738ccChris Craik os.system(neato_cmd) 185cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 186cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.save_dot(self.temp_dot) 187cef7893435aa41160dd1255c43cb8498279738ccChris Craik 188cef7893435aa41160dd1255c43cb8498279738ccChris Craik plot_cmd = "%s %s" % (self.dotty, self.temp_dot) 189cef7893435aa41160dd1255c43cb8498279738ccChris Craik os.system(plot_cmd) 190cef7893435aa41160dd1255c43cb8498279738ccChris Craik 191cef7893435aa41160dd1255c43cb8498279738ccChris Craik def node_style(self, node, **kwargs): 192cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 193cef7893435aa41160dd1255c43cb8498279738ccChris Craik Modifies a node style to the dot representation. 194cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 195cef7893435aa41160dd1255c43cb8498279738ccChris Craik if node not in self.edges: 196cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.edges[node] = {} 197cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.nodes[node] = kwargs 198cef7893435aa41160dd1255c43cb8498279738ccChris Craik 199cef7893435aa41160dd1255c43cb8498279738ccChris Craik def all_node_style(self, **kwargs): 200cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 201cef7893435aa41160dd1255c43cb8498279738ccChris Craik Modifies all node styles 202cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 203cef7893435aa41160dd1255c43cb8498279738ccChris Craik for node in self.nodes: 204cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.node_style(node, **kwargs) 205cef7893435aa41160dd1255c43cb8498279738ccChris Craik 206cef7893435aa41160dd1255c43cb8498279738ccChris Craik def edge_style(self, head, tail, **kwargs): 207cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 208cef7893435aa41160dd1255c43cb8498279738ccChris Craik Modifies an edge style to the dot representation. 209cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 210cef7893435aa41160dd1255c43cb8498279738ccChris Craik if tail not in self.nodes: 211cef7893435aa41160dd1255c43cb8498279738ccChris Craik raise GraphError("invalid node %s" % (tail,)) 212cef7893435aa41160dd1255c43cb8498279738ccChris Craik 213cef7893435aa41160dd1255c43cb8498279738ccChris Craik try: 214cef7893435aa41160dd1255c43cb8498279738ccChris Craik if tail not in self.edges[head]: 215cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.edges[head][tail]= {} 216cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.edges[head][tail] = kwargs 217cef7893435aa41160dd1255c43cb8498279738ccChris Craik except KeyError: 218cef7893435aa41160dd1255c43cb8498279738ccChris Craik raise GraphError("invalid edge %s -> %s " % (head, tail) ) 219cef7893435aa41160dd1255c43cb8498279738ccChris Craik 220cef7893435aa41160dd1255c43cb8498279738ccChris Craik def iterdot(self): 221cef7893435aa41160dd1255c43cb8498279738ccChris Craik # write graph title 222cef7893435aa41160dd1255c43cb8498279738ccChris Craik if self.type == 'digraph': 223cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield 'digraph %s {\n' % (self.name,) 224cef7893435aa41160dd1255c43cb8498279738ccChris Craik elif self.type == 'graph': 225cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield 'graph %s {\n' % (self.name,) 226cef7893435aa41160dd1255c43cb8498279738ccChris Craik 227cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 228cef7893435aa41160dd1255c43cb8498279738ccChris Craik raise GraphError("unsupported graphtype %s" % (self.type,)) 229cef7893435aa41160dd1255c43cb8498279738ccChris Craik 230cef7893435aa41160dd1255c43cb8498279738ccChris Craik # write overall graph attributes 231cef7893435aa41160dd1255c43cb8498279738ccChris Craik for attr_name, attr_value in sorted(self.attr.items()): 232cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield '%s="%s";' % (attr_name, attr_value) 233cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield '\n' 234cef7893435aa41160dd1255c43cb8498279738ccChris Craik 235cef7893435aa41160dd1255c43cb8498279738ccChris Craik # some reusable patterns 236cef7893435aa41160dd1255c43cb8498279738ccChris Craik cpatt = '%s="%s",' # to separate attributes 237cef7893435aa41160dd1255c43cb8498279738ccChris Craik epatt = '];\n' # to end attributes 238cef7893435aa41160dd1255c43cb8498279738ccChris Craik 239cef7893435aa41160dd1255c43cb8498279738ccChris Craik # write node attributes 240cef7893435aa41160dd1255c43cb8498279738ccChris Craik for node_name, node_attr in sorted(self.nodes.items()): 241cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield '\t"%s" [' % (node_name,) 242cef7893435aa41160dd1255c43cb8498279738ccChris Craik for attr_name, attr_value in sorted(node_attr.items()): 243cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield cpatt % (attr_name, attr_value) 244cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield epatt 245cef7893435aa41160dd1255c43cb8498279738ccChris Craik 246cef7893435aa41160dd1255c43cb8498279738ccChris Craik # write edge attributes 247cef7893435aa41160dd1255c43cb8498279738ccChris Craik for head in sorted(self.edges): 248cef7893435aa41160dd1255c43cb8498279738ccChris Craik for tail in sorted(self.edges[head]): 249cef7893435aa41160dd1255c43cb8498279738ccChris Craik if self.type == 'digraph': 250cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield '\t"%s" -> "%s" [' % (head, tail) 251cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 252cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield '\t"%s" -- "%s" [' % (head, tail) 253cef7893435aa41160dd1255c43cb8498279738ccChris Craik for attr_name, attr_value in sorted(self.edges[head][tail].items()): 254cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield cpatt % (attr_name, attr_value) 255cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield epatt 256cef7893435aa41160dd1255c43cb8498279738ccChris Craik 257cef7893435aa41160dd1255c43cb8498279738ccChris Craik # finish file 258cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield '}\n' 259cef7893435aa41160dd1255c43cb8498279738ccChris Craik 260cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __iter__(self): 261cef7893435aa41160dd1255c43cb8498279738ccChris Craik return self.iterdot() 262cef7893435aa41160dd1255c43cb8498279738ccChris Craik 263cef7893435aa41160dd1255c43cb8498279738ccChris Craik def save_dot(self, file_name=None): 264cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 265cef7893435aa41160dd1255c43cb8498279738ccChris Craik Saves the current graph representation into a file 266cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 267cef7893435aa41160dd1255c43cb8498279738ccChris Craik 268cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not file_name: 269cef7893435aa41160dd1255c43cb8498279738ccChris Craik warnings.warn(DeprecationWarning, "always pass a file_name") 270cef7893435aa41160dd1255c43cb8498279738ccChris Craik file_name = self.temp_dot 271cef7893435aa41160dd1255c43cb8498279738ccChris Craik 272cef7893435aa41160dd1255c43cb8498279738ccChris Craik fp = open(file_name, "w") 273cef7893435aa41160dd1255c43cb8498279738ccChris Craik try: 274cef7893435aa41160dd1255c43cb8498279738ccChris Craik for chunk in self.iterdot(): 275cef7893435aa41160dd1255c43cb8498279738ccChris Craik fp.write(chunk) 276cef7893435aa41160dd1255c43cb8498279738ccChris Craik finally: 277cef7893435aa41160dd1255c43cb8498279738ccChris Craik fp.close() 278cef7893435aa41160dd1255c43cb8498279738ccChris Craik 279cef7893435aa41160dd1255c43cb8498279738ccChris Craik def save_img(self, file_name=None, file_type="gif", mode='dot'): 280cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 281cef7893435aa41160dd1255c43cb8498279738ccChris Craik Saves the dot file as an image file 282cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''' 283cef7893435aa41160dd1255c43cb8498279738ccChris Craik 284cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not file_name: 285cef7893435aa41160dd1255c43cb8498279738ccChris Craik warnings.warn(DeprecationWarning, "always pass a file_name") 286cef7893435aa41160dd1255c43cb8498279738ccChris Craik file_name = "out" 287cef7893435aa41160dd1255c43cb8498279738ccChris Craik 288cef7893435aa41160dd1255c43cb8498279738ccChris Craik if mode == 'neato': 289cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.save_dot(self.temp_neo) 290cef7893435aa41160dd1255c43cb8498279738ccChris Craik neato_cmd = "%s -o %s %s" % (self.neato, self.temp_dot, self.temp_neo) 291cef7893435aa41160dd1255c43cb8498279738ccChris Craik os.system(neato_cmd) 292cef7893435aa41160dd1255c43cb8498279738ccChris Craik plot_cmd = self.dot 293cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 294cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.save_dot(self.temp_dot) 295cef7893435aa41160dd1255c43cb8498279738ccChris Craik plot_cmd = self.dot 296cef7893435aa41160dd1255c43cb8498279738ccChris Craik 297cef7893435aa41160dd1255c43cb8498279738ccChris Craik file_name = "%s.%s" % (file_name, file_type) 298cef7893435aa41160dd1255c43cb8498279738ccChris Craik create_cmd = "%s -T%s %s -o %s" % (plot_cmd, file_type, self.temp_dot, file_name) 299cef7893435aa41160dd1255c43cb8498279738ccChris Craik os.system(create_cmd) 300