WUT Velma robot API
dot_graph.py
Go to the documentation of this file.
1 # Copyright (c) 2014, Robot Control and Pattern Recognition Group, Warsaw University of Technology
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
11 # * Neither the name of the Warsaw University of Technology nor the
12 # names of its contributors may be used to endorse or promote products
13 # derived from this software without specific prior written permission.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL <COPYright HOLDER> BE LIABLE FOR ANY
19 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 import tempfile
27 import os
28 import subprocess
29 import latex_equations
30 
31 class Graph:
32  class Node:
33  def __init__(self):
34  self.label = None
35  self.latex_label = None
36 
37  class Edge:
38  def __init__(self):
39  self.id_from = None
40  self.id_to = None
41  self.label = []
42  self.latex_label = []
43 
44  def addLabel(self, label, latex_label):
45  self.label.append(label)
46  self.latex_label.append(latex_label)
47 
48  def __init__(self, shape=None):
49  self.nodes = {}
50  self.edges = []
51 
52  if shape == "rounded_box":
53  self.shape_str = "shape=box; style=rounded;"
54  elif shape == "ellipse" or shape == None:
55  self.shape_str = "shape=ellipse;"
56  else:
57  raise
58 
59  def getEdge(self, id_from, id_to):
60  for e in self.edges:
61  if e.id_from == id_from and e.id_to == id_to:
62  return e
63  return None
64 
65  def generateDotFile(self, draw_unconnected=False, use_latex=False):
66 
67  eps_file_list = []
68  latex_formulas = []
69 
70  dot = "digraph transition {\n"
71 
72  for e in self.edges:
73  if (e.id_from == None or e.id_to == None) and not draw_unconnected:
74  continue
75 
76  # allow loops?
77  #if c[0] == c[1]:
78  # continue
79  if use_latex:
80  edge_latex_str = ''
81  sep = ''
82  for i in range(len(e.latex_label)):
83  latex = e.latex_label[i]
84  if latex == None:
85  latex = latex_equations.toMathText(e.label[i])
86  edge_latex_str += sep + latex
87  sep = ' \\\\ '
88 
89  if edge_latex_str in latex_formulas:
90  handle, path = eps_file_list[latex_formulas.index(edge_latex_str)]
91  else:
92  handle, path = tempfile.mkstemp(suffix=".eps")
93  eps_file_list.append( (handle, path) )
94  latex_formulas.append( edge_latex_str )
95 
96  if e.id_from == None:
97  dot += "\"" + e.id_to + "_unconnected_in\" [shape=point label=\"\"];\n"
98  dot += e.id_to + "_unconnected_in -> " + e.id_to + " [label=<<TABLE BORDER=\"0\"><TR><TD><IMG src=\"" + path + "\"/></TD></TR></TABLE>>];\n"
99  elif e.id_to == None:
100  dot += "\"" + e.id_from + "_unconnected_out\" [shape=point label=\"\"];\n"
101  dot += e.id_from + " -> " + e.id_from + "_unconnected_out [label=<<TABLE BORDER=\"0\"><TR><TD><IMG src=\"" + path + "\"/></TD></TR></TABLE>>];\n"
102  else:
103  dot += e.id_from + " -> " + e.id_to + " [label=<<TABLE BORDER=\"0\"><TR><TD><IMG src=\"" + path + "\"/></TD></TR></TABLE>>];\n"
104 
105  else:
106  edge_str = ''
107  sep = ''
108  for label in e.label:
109  edge_str += sep + label
110  sep = '\\n'
111  if e.id_from == None:
112  dot += "\"" + e.id_to + "_unconnected_in\" [shape=point label=\"\"];\n"
113  dot += e.id_to + "_unconnected_in -> " + e.id_to + " [label=\"" + edge_str + "\"];\n"
114  elif e.id_to == None:
115  dot += "\"" + e.id_from + "_unconnected_out\" [shape=point label=\"\"];\n"
116  dot += e.id_from + " -> " + e.id_from + "_unconnected_out [label=\"" + edge_str + "\"];\n"
117  else:
118  dot += e.id_from + " -> " + e.id_to + " [label=\"" + edge_str + "\"];\n"
119 
120  if use_latex:
121  for name in self.nodes:
122  n = self.nodes[name]
123  latex_label = n.latex_label
124  if not latex_label:
125  latex_label = '\\text{' + n.label.replace('_', '\_') + '}'
126  if latex_label in latex_formulas:
127  handle, path = eps_file_list[latex_formulas.index(latex_label)]
128  else:
129  handle, path = tempfile.mkstemp(suffix=".eps")
130  eps_file_list.append( (handle, path) )
131  latex_formulas.append( latex_label )
132  dot += n.label + " [" + self.shape_str + " label=\"\"; image=\"" + path + "\"];\n"
133  else:
134  for name in self.nodes:
135  n = self.nodes[name]
136  dot += n.label + " [" + self.shape_str + " label=\"" + n.label + "\"];\n"
137 
138  dot += "}\n"
139  return dot, eps_file_list, latex_formulas
140 
141  def exportToPdf(self, filename):
142  dot, eps_file_list, latex_formulas = self.generateDotFile(draw_unconnected=False, use_latex=True)
143 
144  latex_equations.exportToEpsList(eps_file_list, latex_formulas)
145 
146  # generate eps
147  in_read, in_write = os.pipe()
148  os.write(in_write, dot)
149  os.close(in_write)
150  subprocess.call(['dot', '-Teps', '-o'+filename+'.eps'], stdin=in_read)
151  os.close(in_read)
152 
153  latex_equations.removeEpsListFiles(eps_file_list)
154 
155  subprocess.call(['epspdf', filename+'.eps', filename])
156  os.remove(filename+'.eps')
157 
158  def exportToPlain(self):
159  dot, eps_file_list, latex_formulas = self.generateDotFile(draw_unconnected=False, use_latex=False)
160 
161  in_read, in_write = os.pipe()
162  os.write(in_write, dot)
163  os.close(in_write)
164 
165  out_read, out_write = os.pipe()
166  subprocess.call(['dot', '-Tplain'], stdin=in_read, stdout=out_write)
167  os.close(in_read)
168  graph_str = os.read(out_read, 1000000)
169  os.close(out_read)
170  os.close(out_write)
171  graph_str = graph_str.replace("\\\n", "")
172 
173  return graph_str
174 
def __init__(self, shape=None)
Definition: dot_graph.py:48
def exportToPdf(self, filename)
Definition: dot_graph.py:141
def generateDotFile(self, draw_unconnected=False, use_latex=False)
Definition: dot_graph.py:65
def addLabel(self, label, latex_label)
Definition: dot_graph.py:44
def getEdge(self, id_from, id_to)
Definition: dot_graph.py:59