Package teamwork :: Package widgets :: Module MatrixEditor
[hide private]
[frames] | no frames]

Source Code for Module teamwork.widgets.MatrixEditor

  1  from Tkinter import * 
  2  import tkMessageBox 
  3  import Pmw 
  4   
  5  from teamwork.math.KeyedVector import * 
  6  from teamwork.math.KeyedMatrix import * 
  7  from teamwork.math.KeyedTree import KeyedPlane 
  8  from teamwork.math.probability import Distribution 
  9   
10 -class MatrixEditor(Pmw.MegaWidget):
11 """ 12 Widget for editing dynamics trees 13 @cvar probBranch: label for probabilistic branch in type selector 14 @type probBranch: str 15 16 """ 17 probBranch = 'Probabilistic' 18
19 - def __init__(self,parent,**kw):
20 optiondefs = ( 21 ('states', {}, None), 22 ('roles', {}, None), 23 ('classes', {}, None), 24 ('relations', {}, None), 25 ('actions', {}, None), 26 ('selectorCount',3,None), 27 # The feature and key whose dynamics this tree is of 28 ('key', None, None), 29 ('feature', None, None), 30 # The discretization interval for real values 31 ('interval', 0.1, Pmw.INITOPT), 32 # The possible leaf nodes (if None, then use dynamics functions) 33 ('leaves', dynamicsTypes.keys(), None), 34 ) 35 self.defineoptions(kw, optiondefs) 36 Pmw.MegaWidget.__init__(self,parent) 37 self['leaves'].sort() 38 # Color info so that we can disable text entry in ComboBoxes, 39 # without making it look like the whole box is disabled 40 palette = Pmw.Color.getdefaultpalette(parent) 41 widget = self.createcomponent('type',(),None,Pmw.ComboBox, 42 (self.component('hull'),), 43 entry_state='disabled', 44 entry_disabledforeground=palette['foreground'], 45 entry_disabledbackground=palette['background'], 46 history=False) 47 widget.pack(side='top',fill='x') 48 # Possibly variable number of selectors 49 for index in range(self['selectorCount']): 50 widget = self.createcomponent('feature%d' % (index), 51 (),'feature',Pmw.ComboBox, 52 (self.component('hull'),), 53 entry_state='disabled', 54 entry_disabledforeground=palette['foreground'], 55 entry_disabledbackground=palette['background'], 56 history=False) 57 widget.pack_forget() 58 self.initialiseoptions()
59
60 - def getDynamics(self):
61 """ 62 @return: the dynamics matrix currently selected 63 """ 64 widget = self.component('type') 65 try: 66 cls = dynamicsTypes[widget.get()] 67 except KeyError: 68 # Non-dynamics leaves 69 return widget.get() 70 widget = self.component('feature0') 71 if cls.rowClass.keyClass is StateKey: 72 key = self['states'][widget.get()] 73 elif cls.rowClass.keyClass is ConstantKey: 74 key = keyConstant 75 elif cls.rowClass.keyClass is ActionKey: 76 for key in self['actions'].keys(): 77 if str(key) == widget.get(): 78 break 79 else: 80 raise NameError,'Unknown action condition: %s' % (widget.get()) 81 else: 82 raise NotImplementedError,'Unable to create %s leaves' % \ 83 (cls.__name__) 84 value = float(self.component('feature1').get()) 85 if self['key']: 86 # Use key if specified 87 return cls(source=self['key'],key=key,value=value) 88 else: 89 return cls(source=self['feature'],key=key,value=value)
90
91 - def getBranch(self):
92 """ 93 @return: the plane currently selected 94 """ 95 name = self.component('type').get() 96 if name == self.probBranch: 97 # Probabilistic branch 98 widget = self.component('feature%d' % (self['selectorCount']-1)) 99 threshold = float(widget.get()) 100 return Distribution({'then':threshold,'else':1.-threshold}) 101 else: 102 # PWL branch type 103 widget = self.component('type') 104 cls = slopeTypes[widget.get()] 105 newArgs = [] 106 for index in range(len(cls.args)): 107 arg = cls.args[index] 108 widget = self.component('feature%d' % (index)) 109 if arg['type'] is StateKey: 110 key = self['states'][widget.get()] 111 elif arg['type'] is ClassKey: 112 key = self['classes'][widget.get()] 113 elif arg['type'] is IdentityKey: 114 key = self['roles'][widget.get()] 115 elif arg['type'] is RelationshipKey: 116 key = self['relations'][widget.get()] 117 else: 118 raise NotImplementedError,'Cannot handle %s keys' % \ 119 arg['type'].__name__ 120 newArgs.append(key) 121 row = cls(keys=newArgs) 122 if cls.threshold is None: 123 widget = self.component('feature%d' % (self['selectorCount']-1)) 124 threshold = float(widget.get()) 125 else: 126 threshold = cls.threshold 127 return KeyedPlane(row,threshold,cls.relation)
128
129 - def setDynamics(self,rowType):
130 """Configures the menus for the given dynamics type 131 """ 132 try: 133 cls = dynamicsTypes[rowType] 134 except KeyError: 135 # Non-dynamics leaves 136 cls = None 137 if cls: 138 # Set up selector for the key 139 widget = self.component('feature0') 140 widget.pack(fill='x') 141 self.setMenuItems(cls.rowClass.keyClass,widget) 142 widget.configure(entry_state='disabled') 143 # Set up selector for the value 144 widget = self.component('feature1') 145 self.setMenuItems(float,widget) 146 widget.pack(fill='x',after=self.component('feature0')) 147 if cls is IdentityMatrix: 148 # We don't need the pulldowns if there's no change 149 last = 0 150 else: 151 last = 2 152 else: 153 # No change 154 last = 0 155 # Undraw any unused widgets 156 for index in range(last,self['selectorCount']): 157 widget = self.component('feature%d' % (index)) 158 widget.pack_forget()
159
160 - def setBranch(self,rowType):
161 """Configures the menus for the given branch type 162 """ 163 try: 164 noThreshold = not (slopeTypes[rowType].threshold is None) 165 except KeyError: 166 # Probably a TrueRow 167 noThreshold = False 168 last = None 169 for index in range(self['selectorCount']-1): 170 widget = self.component('feature%d' % (index)) 171 try: 172 arg = slopeTypes[rowType].args[index] 173 except IndexError: 174 arg = None 175 except KeyError: 176 arg = None 177 if arg: 178 self.setMenuItems(arg['type'],widget) 179 name = 'feature%d' % (self['selectorCount']-1) 180 widget.pack(fill='x') 181 last = widget 182 else: 183 # All required selectors already drawn 184 widget.pack_forget() 185 # Draw selector for threshold 186 widget = self.component('feature%d' % (self['selectorCount']-1)) 187 if rowType == self.probBranch: 188 self.setMenuItems(float,widget,0.) 189 else: 190 self.setMenuItems(float,widget) 191 widget.selectitem('0.0') 192 if noThreshold: 193 widget.pack_forget() 194 elif last is None: 195 widget.pack(fill='x') 196 else: 197 widget.pack(fill='x',after=last)
198
199 - def displayDynamics(self,matrix):
200 """Sets the menus to the given dynamics matrix 201 """ 202 self.component('type').setlist(map(str,self['leaves'])) 203 if isinstance(matrix,DynamicsMatrix): 204 current = matrix.__class__.rowClass.label 205 self.setDynamics(current) 206 self.component('type').selectitem(current) 207 row = matrix.values()[0] 208 key = row.deltaKey 209 if self['key']: 210 if key == self['key']: 211 value = row[key] - 1. 212 else: 213 value = row[key] 214 elif isinstance(key,StateKey) and \ 215 key['feature'] == self['feature'] and \ 216 key['entity'] == 'self': 217 value = row[key] - 1. 218 else: 219 value = row[key] 220 self.component('feature0').selectitem(key.simpleText()) 221 self.component('feature1_entryfield').setvalue('%5.3f' % (value)) 222 else: 223 self.setDynamics(matrix) 224 self.component('type').selectitem(matrix)
225 # tkMessageBox.showwarning('Warning', 226 # 'Unable to edit generic matrices') 227
228 - def displayBranch(self,plane):
229 """Sets the menus to the given plane 230 """ 231 names = self.getSlopes() 232 # Set up branch type selector 233 self.component('type').setlist(names) 234 if isinstance(plane,Distribution): 235 row = None 236 current = self.probBranch 237 threshold = dict.__getitem__(plane,'then') 238 else: 239 row = plane.weights 240 current = row.__class__.__name__[:-3] 241 threshold = plane.threshold 242 try: 243 self.component('type').selectitem(current) 244 except IndexError,msg: 245 if current == 'True': 246 self.setBranch(names[0]) 247 self.component('type').selectitem(names[0]) 248 else: 249 print 'Unable to handle branches of type:',current 250 return 251 self.setBranch(current) 252 if not isinstance(plane,Distribution): 253 # Set up rest of selectors 254 index = 0 255 keyList = row.keys()[:] 256 for arg in row.__class__.args: 257 widget = self.component('feature%d' % (index)) 258 for key in keyList: 259 if row[key] == arg['weight']: 260 break 261 else: 262 raise KeyError,'No key with weight %4.2f' % (arg['weight']) 263 widget.selectitem(key.simpleText()) 264 keyList.remove(key) 265 index += 1 266 if isinstance(plane,Distribution): 267 # Set threshold with a minimum of 0 268 widget = self.component('feature%d' % (self['selectorCount']-1)) 269 widget.selectitem(self.mapValue(threshold,0.)) 270 elif not isinstance(row,ClassRow) and not isinstance(row,TrueRow) \ 271 and not isinstance(row,RelationshipRow): 272 # Set threshold 273 widget = self.component('feature%d' % (self['selectorCount']-1)) 274 widget.selectitem(self.mapValue(threshold))
275
276 - def getSlopes(self):
277 """ 278 @return: the relevant set of possible branch types 279 @rtype: str[] 280 """ 281 names = slopeTypes.keys() 282 names.sort() 283 if not self['classes']: 284 names.remove('Class') 285 if not self['roles']: 286 names.remove('Identity') 287 if not self['relations']: 288 names.remove('Relationship') 289 names += [self.probBranch] 290 return names
291
292 - def getMenuItems(self,cls,minimum=None):
293 """ 294 @param minimum: optional floor value 295 @return: a list of possible values for a variable of the given class 296 @rtype: list 297 """ 298 if cls is StateKey: 299 keyList = self['states'].keys() 300 keyList.sort() 301 elif cls is ClassKey: 302 keyList = self['classes'].keys() 303 keyList.sort() 304 elif cls is float: 305 if minimum is None: 306 minimum = -1. 307 maximum = max(1.,minimum) 308 span = maximum - minimum 309 keyList = map(lambda x:'%3.1f' % (x*self['interval']+minimum), 310 range(int(span/self['interval'])+1)) 311 elif cls is ConstantKey: 312 keyList = [cls.keyType] 313 elif cls is IdentityKey: 314 keyList = self['roles'].keys() 315 keyList.sort() 316 elif cls is RelationshipKey: 317 keyList = self['relations'].keys() 318 keyList.sort() 319 elif cls is ActionKey: 320 keyList = map(str,self['actions'].keys()) 321 keyList.sort() 322 else: 323 raise NotImplementedError,'Cannot handle %s keys' % \ 324 cls.__name__ 325 return keyList
326
327 - def setMenuItems(self,cls,widget,minimum=None):
328 keyList = self.getMenuItems(cls,minimum) 329 widget.component('scrolledlist').setlist(keyList) 330 if len(keyList) > 0: 331 widget.selectitem(keyList[0]) 332 if cls is float: 333 widget.configure(entry_state='normal') 334 else: 335 widget.configure(entry_state='disabled')
336
337 - def mapValue(self,value,minimum=None):
338 """ 339 @return: index of value in the discretized number space 340 @rtype: int 341 """ 342 if minimum is None: 343 minimum = -1. 344 return int((value-minimum)/self['interval'])
345