Package nltk :: Package sem :: Module drt_glue_demo
[hide private]
[frames] | no frames]

Source Code for Module nltk.sem.drt_glue_demo

  1  # Natural Language Toolkit: GUI Demo for Glue Semantics with Discourse  
  2  #                           Representation Theory (DRT) as meaning language  
  3  # 
  4  # Author: Dan Garrette <dhgarrette@gmail.com> 
  5  # 
  6  # Copyright (C) 2001-2011 NLTK Project 
  7  # URL: <http://www.nltk.org/> 
  8  # For license information, see LICENSE.TXT 
  9   
 10  from tkFont import Font 
 11   
 12  from nltk.draw import * 
 13  from nltk.tag import RegexpTagger 
 14  from nltk.parse.malt import MaltParser 
 15  from logic import Variable 
 16  from drt import DrsDrawer, DrtVariableExpression 
 17  from glue import DrtGlue 
 18   
19 -class DrtGlueDemo(object):
20 - def __init__(self, examples):
21 # Set up the main window. 22 self._top = Tk() 23 self._top.title('DRT Glue Demo') 24 25 # Set up key bindings. 26 self._init_bindings() 27 28 # Initialize the fonts.self._error = None 29 self._init_fonts(self._top) 30 31 self._examples = examples 32 self._readingCache = [None for example in examples] 33 34 # The user can hide the grammar. 35 self._show_grammar = IntVar(self._top) 36 self._show_grammar.set(1) 37 38 # Set the data to None 39 self._curExample = -1 40 self._readings = [] 41 self._drs = None 42 self._drsWidget = None 43 self._error = None 44 45 self._init_glue() 46 47 # Create the basic frames. 48 self._init_menubar(self._top) 49 self._init_buttons(self._top) 50 self._init_exampleListbox(self._top) 51 self._init_readingListbox(self._top) 52 self._init_canvas(self._top) 53 54 # Resize callback 55 self._canvas.bind('<Configure>', self._configure)
56 57 ######################################### 58 ## Initialization Helpers 59 ######################################### 60
61 - def _init_glue(self):
62 tagger = RegexpTagger( 63 [('^(David|Mary|John)$', 'NNP'), 64 ('^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$', 'VB'), 65 ('^(go|order|vanish|find|approach)$', 'VB'), 66 ('^(a)$', 'ex_quant'), 67 ('^(every)$', 'univ_quant'), 68 ('^(sandwich|man|dog|pizza|unicorn|cat|senator)$', 'NN'), 69 ('^(big|gray|former)$', 'JJ'), 70 ('^(him|himself)$', 'PRP') 71 ]) 72 73 depparser = MaltParser(tagger=tagger) 74 self._glue = DrtGlue(depparser=depparser, remove_duplicates=False)
75
76 - def _init_fonts(self, root):
77 # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html> 78 self._sysfont = Font(font=Button()["font"]) 79 root.option_add("*Font", self._sysfont) 80 81 # TWhat's our font size (default=same as sysfont) 82 self._size = IntVar(root) 83 self._size.set(self._sysfont.cget('size')) 84 85 self._boldfont = Font(family='helvetica', weight='bold', 86 size=self._size.get()) 87 self._font = Font(family='helvetica', 88 size=self._size.get()) 89 if self._size.get() < 0: big = self._size.get()-2 90 else: big = self._size.get()+2 91 self._bigfont = Font(family='helvetica', weight='bold', 92 size=big)
93
94 - def _init_exampleListbox(self, parent):
95 self._exampleFrame = listframe = Frame(parent) 96 self._exampleFrame.pack(fill='both', side='left', padx=2) 97 self._exampleList_label = Label(self._exampleFrame, font=self._boldfont, 98 text='Examples') 99 self._exampleList_label.pack() 100 self._exampleList = Listbox(self._exampleFrame, selectmode='single', 101 relief='groove', background='white', 102 foreground='#909090', font=self._font, 103 selectforeground='#004040', 104 selectbackground='#c0f0c0') 105 106 self._exampleList.pack(side='right', fill='both', expand=1) 107 108 for example in self._examples: 109 self._exampleList.insert('end', (' %s' % example)) 110 self._exampleList.config(height=min(len(self._examples), 25), width=40) 111 112 # Add a scrollbar if there are more than 25 examples. 113 if len(self._examples) > 25: 114 listscroll = Scrollbar(self._exampleFrame, 115 orient='vertical') 116 self._exampleList.config(yscrollcommand = listscroll.set) 117 listscroll.config(command=self._exampleList.yview) 118 listscroll.pack(side='left', fill='y') 119 120 # If they select a example, apply it. 121 self._exampleList.bind('<<ListboxSelect>>', self._exampleList_select)
122
123 - def _init_readingListbox(self, parent):
124 self._readingFrame = listframe = Frame(parent) 125 self._readingFrame.pack(fill='both', side='left', padx=2) 126 self._readingList_label = Label(self._readingFrame, font=self._boldfont, 127 text='Readings') 128 self._readingList_label.pack() 129 self._readingList = Listbox(self._readingFrame, selectmode='single', 130 relief='groove', background='white', 131 foreground='#909090', font=self._font, 132 selectforeground='#004040', 133 selectbackground='#c0f0c0') 134 135 self._readingList.pack(side='right', fill='both', expand=1) 136 137 # Add a scrollbar if there are more than 25 examples. 138 listscroll = Scrollbar(self._readingFrame, 139 orient='vertical') 140 self._readingList.config(yscrollcommand = listscroll.set) 141 listscroll.config(command=self._readingList.yview) 142 listscroll.pack(side='right', fill='y') 143 144 self._populate_readingListbox()
145
146 - def _populate_readingListbox(self):
147 # Populate the listbox with integers 148 self._readingList.delete(0, 'end') 149 for i in range(len(self._readings)): 150 self._readingList.insert('end', (' %s' % (i+1))) 151 self._readingList.config(height=min(len(self._readings), 25), width=5) 152 153 # If they select a example, apply it. 154 self._readingList.bind('<<ListboxSelect>>', self._readingList_select)
155
156 - def _init_bindings(self):
157 # Key bindings are a good thing. 158 self._top.bind('<Control-q>', self.destroy) 159 self._top.bind('<Control-x>', self.destroy) 160 self._top.bind('<Escape>', self.destroy) 161 self._top.bind('n', self.next) 162 self._top.bind('<space>', self.next) 163 self._top.bind('p', self.prev) 164 self._top.bind('<BackSpace>', self.prev)
165
166 - def _init_buttons(self, parent):
167 # Set up the frames. 168 self._buttonframe = buttonframe = Frame(parent) 169 buttonframe.pack(fill='none', side='bottom', padx=3, pady=2) 170 Button(buttonframe, text='Prev', 171 background='#90c0d0', foreground='black', 172 command=self.prev,).pack(side='left') 173 Button(buttonframe, text='Next', 174 background='#90c0d0', foreground='black', 175 command=self.next,).pack(side='left')
176
177 - def _configure(self, event):
178 self._autostep = 0 179 (x1, y1, x2, y2) = self._cframe.scrollregion() 180 y2 = event.height - 6 181 self._canvas['scrollregion'] = '%d %d %d %d' % (x1,y1,x2,y2) 182 self._redraw()
183
184 - def _init_canvas(self, parent):
185 self._cframe = CanvasFrame(parent, background='white', 186 #width=525, height=250, 187 closeenough=10, 188 border=2, relief='sunken') 189 self._cframe.pack(expand=1, fill='both', side='top', pady=2) 190 canvas = self._canvas = self._cframe.canvas() 191 192 # Initially, there's no tree or text 193 self._tree = None 194 self._textwidgets = [] 195 self._textline = None
196
197 - def _init_menubar(self, parent):
198 menubar = Menu(parent) 199 200 filemenu = Menu(menubar, tearoff=0) 201 filemenu.add_command(label='Exit', underline=1, 202 command=self.destroy, accelerator='q') 203 menubar.add_cascade(label='File', underline=0, menu=filemenu) 204 205 actionmenu = Menu(menubar, tearoff=0) 206 actionmenu.add_command(label='Next', underline=0, 207 command=self.next, accelerator='n, Space') 208 actionmenu.add_command(label='Previous', underline=0, 209 command=self.prev, accelerator='p, Backspace') 210 menubar.add_cascade(label='Action', underline=0, menu=actionmenu) 211 212 optionmenu = Menu(menubar, tearoff=0) 213 optionmenu.add_checkbutton(label='Remove Duplicates', underline=0, 214 variable=self._glue.remove_duplicates, 215 command=self._toggle_remove_duplicates, 216 accelerator='r') 217 menubar.add_cascade(label='Options', underline=0, menu=optionmenu) 218 219 viewmenu = Menu(menubar, tearoff=0) 220 viewmenu.add_radiobutton(label='Tiny', variable=self._size, 221 underline=0, value=10, command=self.resize) 222 viewmenu.add_radiobutton(label='Small', variable=self._size, 223 underline=0, value=12, command=self.resize) 224 viewmenu.add_radiobutton(label='Medium', variable=self._size, 225 underline=0, value=14, command=self.resize) 226 viewmenu.add_radiobutton(label='Large', variable=self._size, 227 underline=0, value=18, command=self.resize) 228 viewmenu.add_radiobutton(label='Huge', variable=self._size, 229 underline=0, value=24, command=self.resize) 230 menubar.add_cascade(label='View', underline=0, menu=viewmenu) 231 232 helpmenu = Menu(menubar, tearoff=0) 233 helpmenu.add_command(label='About', underline=0, 234 command=self.about) 235 menubar.add_cascade(label='Help', underline=0, menu=helpmenu) 236 237 parent.config(menu=menubar)
238 239 ######################################### 240 ## Main draw procedure 241 ######################################### 242
243 - def _redraw(self):
244 canvas = self._canvas 245 246 # Delete the old DRS, widgets, etc. 247 if self._drsWidget is not None: 248 self._drsWidget.clear() 249 250 if self._drs: 251 self._drsWidget = DrsWidget( self._canvas, self._drs ) 252 self._drsWidget.draw() 253 254 if self._error: 255 self._drsWidget = DrsWidget( self._canvas, self._error ) 256 self._drsWidget.draw()
257 258 ######################################### 259 ## Button Callbacks 260 ######################################### 261
262 - def destroy(self, *e):
263 self._autostep = 0 264 if self._top is None: return 265 self._top.destroy() 266 self._top = None
267
268 - def prev(self, *e):
269 selection = self._readingList.curselection() 270 readingListSize = self._readingList.size() 271 272 # there are readings 273 if readingListSize > 0: 274 # if one reading is currently selected 275 if len(selection) == 1: 276 index = int(selection[0]) 277 278 # if it's on (or before) the first item 279 if index <= 0: 280 self._select_previous_example() 281 else: 282 self._readingList_store_selection(index-1) 283 284 else: 285 #select its first reading 286 self._readingList_store_selection(readingListSize-1) 287 288 else: 289 self._select_previous_example()
290 291
292 - def _select_previous_example(self):
293 #if the current example is not the first example 294 if self._curExample > 0: 295 self._exampleList_store_selection(self._curExample-1) 296 else: 297 #go to the last example 298 self._exampleList_store_selection(len(self._examples)-1)
299
300 - def next(self, *e):
301 selection = self._readingList.curselection() 302 readingListSize = self._readingList.size() 303 304 # if there are readings 305 if readingListSize > 0: 306 # if one reading is currently selected 307 if len(selection) == 1: 308 index = int(selection[0]) 309 310 # if it's on (or past) the last item 311 if index >= (readingListSize-1): 312 self._select_next_example() 313 else: 314 self._readingList_store_selection(index+1) 315 316 else: 317 #select its first reading 318 self._readingList_store_selection(0) 319 320 else: 321 self._select_next_example()
322
323 - def _select_next_example(self):
324 #if the current example is not the last example 325 if self._curExample < len(self._examples)-1: 326 self._exampleList_store_selection(self._curExample+1) 327 else: 328 #go to the first example 329 self._exampleList_store_selection(0)
330 331
332 - def about(self, *e):
333 ABOUT = ("NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n"+ 334 "Written by Daniel H. Garrette") 335 TITLE = 'About: NLTK DRT Glue Demo' 336 try: 337 from tkMessageBox import Message 338 Message(message=ABOUT, title=TITLE).show() 339 except: 340 ShowText(self._top, TITLE, ABOUT)
341
342 - def postscript(self, *e):
343 self._autostep = 0 344 self._cframe.print_to_file()
345
346 - def mainloop(self, *args, **kwargs):
347 """ 348 Enter the Tkinter mainloop. This function must be called if 349 this demo is created from a non-interactive program (e.g. 350 from a secript); otherwise, the demo will close as soon as 351 the script completes. 352 """ 353 if in_idle(): return 354 self._top.mainloop(*args, **kwargs)
355
356 - def resize(self, size=None):
357 if size is not None: self._size.set(size) 358 size = self._size.get() 359 self._font.configure(size=-(abs(size))) 360 self._boldfont.configure(size=-(abs(size))) 361 self._sysfont.configure(size=-(abs(size))) 362 self._bigfont.configure(size=-(abs(size+2))) 363 self._redraw()
364
366 self._glue.remove_duplicates = not self._glue.remove_duplicates 367 368 self._exampleList.selection_clear(0, 'end') 369 self._readings = [] 370 self._populate_readingListbox() 371 self._readingCache = [None for ex in self._examples] 372 self._curExample = -1 373 self._error = None 374 375 self._drs = None 376 self._redraw()
377 378
379 - def _exampleList_select(self, event):
380 selection = self._exampleList.curselection() 381 if len(selection) != 1: return 382 self._exampleList_store_selection(int(selection[0]))
383
384 - def _exampleList_store_selection(self, index):
385 self._curExample = index 386 example = self._examples[index] 387 388 self._exampleList.selection_clear(0, 'end') 389 if example: 390 cache = self._readingCache[index] 391 if cache: 392 if isinstance(cache, list): 393 self._readings = cache 394 self._error = None 395 else: 396 self._readings = [] 397 self._error = cache 398 else: 399 try: 400 self._readings = self._glue.parse_to_meaning(example) 401 self._error = None 402 self._readingCache[index] = self._readings 403 except Exception, e: 404 self._readings = [] 405 self._error = DrtVariableExpression(Variable('Error: ' + str(e))) 406 self._readingCache[index] = self._error 407 408 #add a star to the end of the example 409 self._exampleList.delete(index) 410 self._exampleList.insert(index, (' %s *' % example)) 411 self._exampleList.config(height=min(len(self._examples), 25), width=40) 412 413 self._populate_readingListbox() 414 415 self._exampleList.selection_set(index) 416 417 self._drs = None 418 self._redraw()
419 420
421 - def _readingList_select(self, event):
422 selection = self._readingList.curselection() 423 if len(selection) != 1: return 424 self._readingList_store_selection(int(selection[0]))
425
426 - def _readingList_store_selection(self, index):
427 reading = self._readings[index] 428 429 self._readingList.selection_clear(0, 'end') 430 if reading: 431 self._readingList.selection_set(index) 432 433 self._drs = reading.simplify().normalize().resolve_anaphora() 434 435 self._redraw()
436 437
438 -class DrsWidget(object):
439 - def __init__(self, canvas, drs, **attribs):
440 self._drs = drs 441 self._canvas = canvas 442 canvas.font = Font(font=canvas.itemcget(canvas.create_text(0, 0, text=''), 'font')) 443 canvas._BUFFER = 3 444 self.bbox = (0, 0, 0, 0)
445
446 - def draw(self):
447 (right, bottom) = DrsDrawer(self._drs, canvas=self._canvas).draw(); 448 self.bbox = (0, 0, right+1, bottom+1)
449
450 - def clear(self):
451 self._canvas.create_rectangle(self.bbox, fill="white", width="0" )
452
453 -def demo():
454 examples = ['John walks', 455 'David sees Mary', 456 'David eats a sandwich', 457 'every man chases a dog', 458 # 'every man believes a dog yawns', 459 # 'John gives David a sandwich', 460 'John chases himself', 461 # 'John persuades David to order a pizza', 462 # 'John tries to go', 463 # 'John tries to find a unicorn', 464 # 'John seems to vanish', 465 # 'a unicorn seems to approach', 466 # 'every big cat leaves', 467 # 'every gray cat leaves', 468 # 'every big gray cat leaves', 469 # 'a former senator leaves', 470 # 'John likes a cat', 471 # 'John likes every cat', 472 # 'he walks', 473 # 'John walks and he leaves' 474 ] 475 DrtGlueDemo(examples).mainloop()
476 477 if __name__ == '__main__': demo() 478