Package teamwork :: Package math :: Module treeEditor
[hide private]
[frames] | no frames]

Source Code for Module teamwork.math.treeEditor

  1  #!/usr/bin/env python 
  2   
  3  # example basictreeview.py 
  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  ##from KeyedMatrix import * 
 14   
 15           
16 -class DecisionTreeEditor:
17 # close the window and quit
18 - def delete_event(self, widget, event, data=None):
19 gtk.main_quit() 20 return gtk.FALSE
21
22 - def __init__(self,feature,tree=None,states=[],actions=[],classes=[]):
23 # Set up initial domain 24 self.feature = feature 25 self.choices = [classes,['self','actor','object'],states,actions] 26 # Set up initial tree 27 if tree: 28 self.tree = tree 29 else: 30 # If no tree given, start with an empty one 31 self.tree = createDynamicNode(feature,KeyedRow()) 32 # Set up list of keys 33 self.keys = tree.getKeys() 34 self.columnTypes = map(lambda x:gobject.TYPE_STRING,self.keys) 35 # Extra column for threshold 36 self.columnTypes.append(gobject.TYPE_STRING) 37 38 # Create a new window 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 # Set up menus 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 # Create menubar 75 self.menu = self.get_main_menu(self.window) 76 self.frame.pack_start(self.menu,expand=0) 77 78 # create a TreeStore with one string column to use as the model 79 self.treestore = apply(gtk.TreeStore,self.columnTypes) 80 81 # we'll add some data now 82 self.addTree() 83 84 # create the TreeView using treestore 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 # create the TreeViewColumn to display the data 91 self.tvcolumn = gtk.TreeViewColumn(content) 92 # add tvcolumn to treeview 93 self.treeview.append_column(self.tvcolumn) 94 # create a CellRendererText to render the data 95 self.cell = gtk.CellRendererText() 96 # add the cell to the tvcolumn and allow it to expand 97 self.tvcolumn.pack_start(self.cell, True) 98 # set the cell "text" attribute to column - retrieve text 99 # from that column in treestore 100 self.tvcolumn.add_attribute(self.cell, 'text', index) 101 # make it searchable 102 self.treeview.set_search_column(index) 103 # Allow sorting on the column 104 self.tvcolumn.set_sort_column_id(index) 105 106 # Allow drag and drop reordering of rows 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 # This function initializes the item factory. 145 # Param 1: The type of menu - can be MenuBar, Menu, 146 # or OptionMenu. 147 # Param 2: The path of the menu. 148 # Param 3: A reference to an AccelGroup. The item factory sets up 149 # the accelerator table while generating menus. 150 item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", accel_group) 151 152 # This method generates the menu items. Pass to the item factory 153 # the list of menu items 154 item_factory.create_items(self.menu_items) 155 156 # Attach the new accelerator group to the window. 157 window.add_accel_group(accel_group) 158 159 # need to keep a reference to item_factory to prevent its destruction 160 self.item_factory = item_factory 161 # Finally, return the actual menu bar created by the item factory. 162 return item_factory.get_widget("<main>")
163
164 - def get_key(self,key):
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 # Create a button box for each slot in this key type 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 # Create a radio button for each possible slot filler 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 # Activate dialog 188 response = dialog.run() 189 dialog.destroy() 190 if response: 191 # Extract radio button selections 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 # Create and insert new key 199 newKey = key(value) 200 if not newKey in self.keys: 201 self.keys.append(newKey)
202
203 - def new_row(self,rowType):
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 # Add 2 entries for keyed terms 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 # Add entry for constant term 219 dialog.vbox.pack_start(self.makeRowEntry('constant')[0]) 220 if rowType == 'split': 221 # Add entry for threshold 222 dialog.vbox.pack_start(self.makeRowEntry('threshold')[0]) 223 # Add control of move of current subtree 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 # Get input 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 # Create node 245 node = createDynamicNode(feature,KeyedRow(result)) 246 result = {} 247 # Extract values 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 # Create split 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
284 - def makeScale(self):
285 scale = gtk.HScale() 286 scale.set_range(-1.,1.) 287 return scale
288
289 - def addKeys(self,keyList):
290 pass
291
292 - def error(self,msg):
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
303 -def main():
304 gtk.main()
305 306 if __name__ == "__main__": 307 from teamwork.examples.Cortina import violence 308 ## import violence 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