Added TODO and DEVELOPMENT.
[faces-project.git] / faces / charting / graphviz.py
blob12540acec49a28f475185c4278bdb32baf89e27f
1 ############################################################################
2 # Copyright (C) 2006 by Reithinger GmbH
3 # mreithinger@web.de
5 # This file is part of faces.
6 #
7 # faces is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # faces is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the
19 # Free Software Foundation, Inc.,
20 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 ############################################################################
23 import gv
24 import faces.task
25 import sys
26 import faces.charting.charts as charts
27 import faces.charting.faxes as faxes
28 import faces.charting.widgets as widgets
29 import faces.charting.patches as patches
30 import faces.charting.connector as connector
31 from faces.charting.tools import *
32 import faces.charting.printer as printer
34 remove = gv.rm
37 class Graphviz(object):
38 def __init__(self, go):
39 self._go = go
41 def __getattr__(self, name):
42 return gv.getv(self._go, name)
45 def __setattr__(self, name, value):
46 if name[0] == "_":
47 super(Graphviz, self).__setattr__(name, value)
48 else:
49 gv.setv(self._go, name, str(value))
52 class Node(Graphviz):
53 def name(self):
54 return gv.nameof(self._go)
56 name = property(name)
60 class Edge(Graphviz):
61 def head(self):
62 return Node(gv.headof(self._go))
64 head = property(head)
66 def tail(self):
67 return Node(gv.tailof(self._go))
69 tail = property(tail)
73 class Digraph(Graphviz):
74 def __init__(self, graph=None, name=None):
75 if graph:
76 self._go = gv.readstring(str(input))
77 elif name:
78 self._go = gv.digraph(name)
80 self._counter = 0
82 def __del__(self):
83 if remove:
84 remove(self._go)
87 def add_node(self, name=None, **kwargs):
88 if not name:
89 self._counter += 1
90 name = str(self._counter)
92 node = Node(gv.node(self._go, name))
93 for k, v in kwargs.items():
94 setattr(node, k, v)
95 return node
98 def add_edge(self, tail, head, **kwargs):
99 edge = Edge(gv.edge(tail._go, head._go))
100 for k, v in kwargs.items():
101 setattr(edge, k, v)
103 return edge
106 def layout(self, engine):
107 gv.layout(self._go, engine)
109 def render(self, format, filename=None):
110 if filename:
111 gv.render(self._go, format, filename)
112 else:
113 gv.render(self._go, format)
115 def __getattr__(self, name):
116 return gv.getv(self._go, name)
119 def name(self):
120 return gv.nameof(self._go)
122 name = property(name)
125 def nodes(self):
126 node = gv.firstnode(self._go)
127 while node:
128 yield Node(node)
129 node = gv.nextnode(self._go, node)
131 nodes = property(nodes)
133 def edges(self):
134 edge = gv.firstedge(self._go)
135 while edge:
136 yield Edge(edge)
137 return
138 print "hier"
139 edge = gv.nextedge(self._go, edge)
140 print "da"
142 edges = property(edges)
146 class GraphVizChart(charts.MatplotChart):
147 data = None
148 properties = {#"size" : "sularge",
149 "facecolor" : "white",
150 "edgecolor" : "black",
151 "linewidth" : 1,
152 "antialiased" : True }
154 def create_axes(self, rect=None, **kwargs):
155 pprop = self.get_patch
156 rect = rect or [0, 0, 1, 1]
157 fig = self.figure
158 ax = fig.add_axes(faxes.PointAxes(fig, rect, **kwargs))
159 ax.cla()
160 ax.set_marker(pprop("focused.marker"), pprop("marker"))
161 return ax
163 def get_nodes(self, data):
164 "overwrite"
165 for t in data:
166 yield t
168 def printer(cls, **kwargs):
169 return printer.PointPrinter(cls, **kwargs)
171 printer = classmethod(printer)
173 def create_node_widget(self, node):
174 "overwrite"
175 pprop = self.get_patch
177 debug = node.name == "Task3"
178 big = widgets.TableWidget(2, 1)
179 small = widgets.TableWidget(2, 2)
180 title = widgets.BoxedTextWidget(node.title, node, fattrib="title")
181 start = widgets.BoxedTextWidget(node.to_string.start, node, fattrib="start", left=2)
182 end = widgets.BoxedTextWidget(node.to_string.end, node, fattrib="end", left=2)
183 effort = widgets.BoxedTextWidget(node.to_string.effort, node, fattrib="effort", left=2)
184 length = widgets.BoxedTextWidget(node.to_string.length, node, fattrib="length", left=2)
186 big.debug = debug and "big %s" % node.name
187 end.debug = debug and "end"
189 big.set_cell(0, 0, title)
190 big.set_cell(1, 0, small)
191 small.set_cell(0, 0, start, halign="left")
192 small.set_cell(0, 1, end, halign="left")
193 small.set_cell(1, 0, length, halign="left")
194 small.set_cell(1, 1, effort, halign="left")
195 big.add_artist(patches.Rectangle((LEFT, BOTTOM),
196 RIGHT-LEFT,
197 TOP-BOTTOM,
198 **pprop("box")))
200 return big
203 def get_edges(self, nodes):
204 "overwrite"
205 for t in nodes:
206 for sources in t._sources.values():
207 for s in sources:
208 path, sattrib = faces.task._split_path(s)
209 yield t.get_task(path), t
211 def create_graph(self):
212 "overwrite"
213 graph = graphviz.Digraph(name="G")
214 graph.nodesep = "0,5"
215 graph.rankdir = "LR"
216 graph.ordering = "in"
217 graph.outputorder = "nodesfirst"
218 graph.ranksep = "1.4 equally"
219 graph.splines = False
220 graph.start = "regular"
221 return graph
224 def create(self):
225 push_active(self)
227 w = widgets.TableWidget(3, 2)
229 helper = faxes.PointAxes(self.figure, [0, 0, 1, 1])
230 helper.check_limits()
233 graph = self.create_graph()
235 node_to_widget = { }
236 nodes = {}
237 for n in self.get_nodes(self.data):
238 widget = self.create_node_widget(n)
239 helper.add_widget(widget)
240 l, b, w, h = widget.bbox.get_bounds()
241 w = "%.2f" % (w/72.0)
242 h = "%.2f" % (h/72.0)
243 w = w.replace(".", ",")
244 h = h.replace(".", ",")
245 node = nodes[n] = graph.add_node(shape="box", width=w, height=h)
246 node_to_widget[node.name] = widget
248 print "nodes added"
250 edges = []
251 for n1, n2 in self.get_edges(nodes.keys()):
252 edges.append((n1, n2))
253 graph.add_edge(nodes[n1], nodes[n2])
256 graph.layout("dot")
258 graph.render("dot", "/home/michael/temp/test.dot")
259 l, b, r, gheight = map(int, graph.bb.split(","))
261 for n in graph.nodes:
262 w = node_to_widget[n.name]
263 x, y = map(int, n.pos.split(","))
264 w.set_pos(x, - gheight + y)
265 self.axes.add_widget(w)
267 for n1, n2 in edges:
268 w1 = node_to_widget[nodes[n1].name]
269 w2 = node_to_widget[nodes[n2].name]
270 c = connector.ShortConnector(w1, w2)
271 self.axes.add_widget(c)
273 pop_active()
277 if __name__ == "__main__":
278 graph = Digraph(name="G")
279 graph.nodesep = "0,05"
280 graph.rankdir = "LR"
281 graph.ordering = "in"
282 graph.outputorder = "nodesfirst"
283 graph.ranksep = "1.4 equally"
284 graph.splines = False
285 graph.start = "regular"
286 n1 = graph.add_node(label="1", width="3,23", shape="box")
287 n2 = graph.add_node(label="2")
288 print "n1", n1.label, n1.name, n1.width
289 e = graph.add_edge(n1, n2)
290 graph.render("dot")
292 graph.layout("dot")
294 graph.render("dot")
295 #out.render("png", "/home/michael/temp/test.png")
296 #out.render("dot", "/home/michael/temp/test1.dot")
297 print "nodes:"
298 for n in graph.nodes:
299 print " ", n.name, n.label, n.width, n.pos
301 print "edges:"
302 print " ", e.head.label, e.tail.label, e.pos
303 #for e in graph.edges:
304 # print " ", e.head.label, e.tail.label, e.pos
306 print "ende"