1
2
3
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8 import gobject
9
10 from types import *
11
12 from teamwork.math.KeyedMatrix import *
13
14
15
17
19 gtk.main_quit()
20 return gtk.FALSE
21
22 - def __init__(self,feature,tree=None,states=[],actions=[],classes=[]):
23
24 self.feature = feature
25 self.choices = [classes,['self','actor','object'],states,actions]
26
27 if tree:
28 self.tree = tree
29 else:
30
31 self.tree = createDynamicNode(feature,KeyedRow())
32
33 self.keys = tree.getKeys()
34 self.columnTypes = map(lambda x:gobject.TYPE_STRING,self.keys)
35
36 self.columnTypes.append(gobject.TYPE_STRING)
37
38
39 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
40
41 self.window.set_title("Decision Tree Editor")
42
43 self.window.set_size_request(200, 200)
44
45 self.window.connect("delete_event", self.delete_event)
46
47 self.frame = gtk.VBox()
48 self.window.add(self.frame)
49
50 self.menu_items = (
51 ( "/_File", None, None, 0, "<Branch>" ),
52 ( "/File/_New", "<control>N", None, 0, None ),
53 ( "/File/_Open", "<control>O", None, 0, None ),
54 ( "/File/_Save", "<control>S", None, 0, None ),
55 ( "/File/Save _As", None, None, 0, None ),
56 ( "/File/sep1", None, None, 0, "<Separator>" ),
57 ( "/File/Quit", "<control>Q", lambda x,y:gtk.main_quit(),
58 0, None ),
59 ( "/_Insert", None, None, 0, "<Branch>" ),
60 ( "/Insert/_Key", None, None, 0, "<Branch>" ),
61 ( "/Insert/Key/_Action", None,
62 lambda x,y,s=self:s.get_key(ActionKey)),
63 ( "/Insert/Key/_Class", None,
64 lambda x,y,s=self:s.get_key(ClassKey)),
65 ( "/Insert/Key/_Identity", None,
66 lambda x,y,s=self:s.get_key(IdentityKey)),
67 ( "/Insert/Key/_State", None,
68 lambda x,y,s=self:s.get_key(StateKey)),
69 ( "/Insert/_Split", None,
70 lambda x,y,s=self:s.new_row('split')),
71 ( "/_Help", None, None, 0, "<LastBranch>" ),
72 ( "/_Help/About", None, None, 0, None ),
73 )
74
75 self.menu = self.get_main_menu(self.window)
76 self.frame.pack_start(self.menu,expand=0)
77
78
79 self.treestore = apply(gtk.TreeStore,self.columnTypes)
80
81
82 self.addTree()
83
84
85 self.treeview = gtk.TreeView(self.treestore)
86
87 for index in range(len(self.keys)):
88 key = self.keys[index]
89 content = str(key)
90
91 self.tvcolumn = gtk.TreeViewColumn(content)
92
93 self.treeview.append_column(self.tvcolumn)
94
95 self.cell = gtk.CellRendererText()
96
97 self.tvcolumn.pack_start(self.cell, True)
98
99
100 self.tvcolumn.add_attribute(self.cell, 'text', index)
101
102 self.treeview.set_search_column(index)
103
104 self.tvcolumn.set_sort_column_id(index)
105
106
107 self.treeview.set_reorderable(True)
108
109 self.frame.add(self.treeview)
110
111 self.window.show_all()
112
113 - def addTree(self,tree=None,parent=None,label=''):
114 if not tree:
115 tree = self.tree
116 if tree.isLeaf():
117 value = tree.getValue().values()
118 row = self.treestore.insert_before(parent,None)
119 if len(value) > 0:
120 value = value[0]
121 for key in value.keys():
122 index = self.keys.index(key)
123 content = '%5.3f' % value[key]
124 self.treestore.set_value(row,index,content)
125 else:
126 self.treestore.set_value(row,len(self.keys),'No change')
127 else:
128 left,right = tree.getValue()
129 row = self.treestore.insert_before(parent,None)
130 for key,value in tree.split.weights.items():
131 index = self.keys.index(key)
132 if abs(value) > epsilon:
133 content = '%5.3f' % value
134 else:
135 content = ''
136 self.treestore.set_value(row,index,content)
137 self.treestore.set_value(row,len(self.keys),tree.split.threshold)
138 self.addTree(left,row,'< ')
139 self.addTree(right,row,'> ')
140
141 - def get_main_menu(self, window):
142 accel_group = gtk.AccelGroup()
143
144
145
146
147
148
149
150 item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", accel_group)
151
152
153
154 item_factory.create_items(self.menu_items)
155
156
157 window.add_accel_group(accel_group)
158
159
160 self.item_factory = item_factory
161
162 return item_factory.get_widget("<main>")
163
165 """Pops up a dialog to allow user to specify a new key.
166
167 The key argument should be a Key *class*"""
168 dialog = gtk.Dialog('New %s' % (key.__name__), self.window,
169 gtk.DIALOG_MODAL + gtk.DIALOG_DESTROY_WITH_PARENT,
170 ((gtk.STOCK_OK,1,gtk.STOCK_CANCEL,0)))
171 buttons = {}
172 for slotName,value in key.slots.items():
173
174 buttons[slotName] = {}
175 frame = gtk.Frame(slotName)
176 bbox = gtk.VButtonBox()
177 frame.add(bbox)
178 last = None
179 for option in self.choices[value]:
180
181 button = gtk.RadioButton(last,option)
182 buttons[slotName][option] = button
183 bbox.add(button)
184 last = button
185 dialog.vbox.pack_start(frame)
186 frame.show_all()
187
188 response = dialog.run()
189 dialog.destroy()
190 if response:
191
192 value = {}
193 for slotName in key.slots.keys():
194 for name,button in buttons[slotName].items():
195 if button.get_active():
196 value[slotName] = name
197 break
198
199 newKey = key(value)
200 if not newKey in self.keys:
201 self.keys.append(newKey)
202
204 """Pops up a dialog to allow user to specify a new split."""
205 selection = self.treeview.get_selection().get_selected()[1]
206 if not selection:
207 self.error('Select a split point first.')
208 return
209 dialog = gtk.Dialog('New %s' % (rowType), self.window,
210 gtk.DIALOG_MODAL,
211 ((gtk.STOCK_OK,1,gtk.STOCK_CANCEL,0)))
212
213 keyButtons = []
214 for row in range(2):
215 button,menu = self.makeRowEntry('key')
216 dialog.vbox.pack_start(button)
217 keyButtons.append((menu,button.get_children()[0]))
218
219 dialog.vbox.pack_start(self.makeRowEntry('constant')[0])
220 if rowType == 'split':
221
222 dialog.vbox.pack_start(self.makeRowEntry('threshold')[0])
223
224 frame = gtk.Frame('Current subtree:')
225 bbox = gtk.HButtonBox()
226 frame.add(bbox)
227 button = gtk.RadioButton(None,'<')
228 bbox.add(button)
229 button = gtk.RadioButton(button,'>')
230 bbox.add(button)
231 frame.show_all()
232 dialog.vbox.pack_start(frame)
233
234 result = dialog.run()
235 if result:
236 if rowType == 'split':
237 result = self.new_row('row')
238 else:
239 result = {}
240 else:
241 result = {'cancel':1}
242 if not result.has_key('cancel'):
243 if rowType == 'split':
244
245 node = createDynamicNode(feature,KeyedRow(result))
246 result = {}
247
248 for menu,button in keyButtons:
249 children = button.get_children()
250 active = children[0].get_menu().get_active()
251 for key,value in menu.items():
252 if value == active:
253 break
254 scale = children[1]
255 value = scale.get_value()
256 if value:
257 result[key] = value
258 if rowType == 'split':
259
260 pass
261 dialog.destroy()
262 return result
263
264 - def makeRowEntry(self,entryType):
265 frame = gtk.Frame(entryType)
266 box = gtk.VBox()
267 frame.add(box)
268 menuDict = {}
269 if entryType == 'key':
270 left = gtk.OptionMenu()
271 menu = gtk.Menu()
272 left.set_menu(menu)
273 last = None
274 for key in self.keys:
275 item = gtk.RadioMenuItem(last,str(key))
276 menuDict[key] = item
277 menu.append(item)
278 last = item
279 box.pack_start(left)
280 box.pack_start(self.makeScale())
281 frame.show_all()
282 return frame,menuDict
283
288
291
293 """Pops up an error dialog with the specified message"""
294 dialog = gtk.Dialog('Error', self.window,
295 gtk.DIALOG_MODAL,
296 ((gtk.STOCK_OK,0)))
297 label = gtk.Label(msg)
298 dialog.vbox.pack_start(label)
299 dialog.vbox.show_all()
300 dialog.run()
301 dialog.destroy()
302
305
306 if __name__ == "__main__":
307 from teamwork.examples.Cortina import violence
308
309
310 feature = 'militarypower'
311 result = violence.genAttackDyn(feature)['tree']
312 tvexample = DecisionTreeEditor(feature,result,states=[feature],
313 actions=['violence','aid','wait'],
314 classes=['TerroristGroup','Government',
315 'Poor','US'])
316 main()
317