# Natural Language Toolkit: GUI Demo for Glue Semantics with Discourse
# Representation Theory (DRT) as meaning language
#
# Author: Dan Garrette <dhgarrette@gmail.com>
#
# Copyright (C) 2001-2013 NLTK Project
# URL: <http://nltk.org/>
# For license information, see LICENSE.TXT
from nltk import compat # this fixes tkinter imports for Python 2.x
from tkinter.font import Font
from tkinter import (Button, Frame, IntVar, Label,
Listbox, Menu, Scrollbar, Tk)
from nltk.draw.util import CanvasFrame, ShowText
from nltk.util import in_idle
from nltk.tag import RegexpTagger
from nltk.parse import MaltParser
from nltk.sem.logic import Variable
from nltk.sem.drt import DrsDrawer, DrtVariableExpression
from nltk.sem.glue import DrtGlue
[docs]class DrtGlueDemo(object):
def __init__(self, examples):
# Set up the main window.
self._top = Tk()
self._top.title('DRT Glue Demo')
# Set up key bindings.
self._init_bindings()
# Initialize the fonts.self._error = None
self._init_fonts(self._top)
self._examples = examples
self._readingCache = [None for example in examples]
# The user can hide the grammar.
self._show_grammar = IntVar(self._top)
self._show_grammar.set(1)
# Set the data to None
self._curExample = -1
self._readings = []
self._drs = None
self._drsWidget = None
self._error = None
self._init_glue()
# Create the basic frames.
self._init_menubar(self._top)
self._init_buttons(self._top)
self._init_exampleListbox(self._top)
self._init_readingListbox(self._top)
self._init_canvas(self._top)
# Resize callback
self._canvas.bind('<Configure>', self._configure)
#########################################
## Initialization Helpers
#########################################
def _init_glue(self):
tagger = RegexpTagger(
[('^(David|Mary|John)$', 'NNP'),
('^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$', 'VB'),
('^(go|order|vanish|find|approach)$', 'VB'),
('^(a)$', 'ex_quant'),
('^(every)$', 'univ_quant'),
('^(sandwich|man|dog|pizza|unicorn|cat|senator)$', 'NN'),
('^(big|gray|former)$', 'JJ'),
('^(him|himself)$', 'PRP')
])
depparser = MaltParser(tagger=tagger)
self._glue = DrtGlue(depparser=depparser, remove_duplicates=False)
def _init_fonts(self, root):
# See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
self._sysfont = Font(font=Button()["font"])
root.option_add("*Font", self._sysfont)
# TWhat's our font size (default=same as sysfont)
self._size = IntVar(root)
self._size.set(self._sysfont.cget('size'))
self._boldfont = Font(family='helvetica', weight='bold',
size=self._size.get())
self._font = Font(family='helvetica',
size=self._size.get())
if self._size.get() < 0: big = self._size.get()-2
else: big = self._size.get()+2
self._bigfont = Font(family='helvetica', weight='bold',
size=big)
def _init_exampleListbox(self, parent):
self._exampleFrame = listframe = Frame(parent)
self._exampleFrame.pack(fill='both', side='left', padx=2)
self._exampleList_label = Label(self._exampleFrame, font=self._boldfont,
text='Examples')
self._exampleList_label.pack()
self._exampleList = Listbox(self._exampleFrame, selectmode='single',
relief='groove', background='white',
foreground='#909090', font=self._font,
selectforeground='#004040',
selectbackground='#c0f0c0')
self._exampleList.pack(side='right', fill='both', expand=1)
for example in self._examples:
self._exampleList.insert('end', (' %s' % example))
self._exampleList.config(height=min(len(self._examples), 25), width=40)
# Add a scrollbar if there are more than 25 examples.
if len(self._examples) > 25:
listscroll = Scrollbar(self._exampleFrame,
orient='vertical')
self._exampleList.config(yscrollcommand = listscroll.set)
listscroll.config(command=self._exampleList.yview)
listscroll.pack(side='left', fill='y')
# If they select a example, apply it.
self._exampleList.bind('<<ListboxSelect>>', self._exampleList_select)
def _init_readingListbox(self, parent):
self._readingFrame = listframe = Frame(parent)
self._readingFrame.pack(fill='both', side='left', padx=2)
self._readingList_label = Label(self._readingFrame, font=self._boldfont,
text='Readings')
self._readingList_label.pack()
self._readingList = Listbox(self._readingFrame, selectmode='single',
relief='groove', background='white',
foreground='#909090', font=self._font,
selectforeground='#004040',
selectbackground='#c0f0c0')
self._readingList.pack(side='right', fill='both', expand=1)
# Add a scrollbar if there are more than 25 examples.
listscroll = Scrollbar(self._readingFrame,
orient='vertical')
self._readingList.config(yscrollcommand = listscroll.set)
listscroll.config(command=self._readingList.yview)
listscroll.pack(side='right', fill='y')
self._populate_readingListbox()
def _populate_readingListbox(self):
# Populate the listbox with integers
self._readingList.delete(0, 'end')
for i in range(len(self._readings)):
self._readingList.insert('end', (' %s' % (i+1)))
self._readingList.config(height=min(len(self._readings), 25), width=5)
# If they select a example, apply it.
self._readingList.bind('<<ListboxSelect>>', self._readingList_select)
def _init_bindings(self):
# Key bindings are a good thing.
self._top.bind('<Control-q>', self.destroy)
self._top.bind('<Control-x>', self.destroy)
self._top.bind('<Escape>', self.destroy)
self._top.bind('n', self.next)
self._top.bind('<space>', self.next)
self._top.bind('p', self.prev)
self._top.bind('<BackSpace>', self.prev)
def _init_buttons(self, parent):
# Set up the frames.
self._buttonframe = buttonframe = Frame(parent)
buttonframe.pack(fill='none', side='bottom', padx=3, pady=2)
Button(buttonframe, text='Prev',
background='#90c0d0', foreground='black',
command=self.prev,).pack(side='left')
Button(buttonframe, text='Next',
background='#90c0d0', foreground='black',
command=self.next,).pack(side='left')
def _configure(self, event):
self._autostep = 0
(x1, y1, x2, y2) = self._cframe.scrollregion()
y2 = event.height - 6
self._canvas['scrollregion'] = '%d %d %d %d' % (x1,y1,x2,y2)
self._redraw()
def _init_canvas(self, parent):
self._cframe = CanvasFrame(parent, background='white',
#width=525, height=250,
closeenough=10,
border=2, relief='sunken')
self._cframe.pack(expand=1, fill='both', side='top', pady=2)
canvas = self._canvas = self._cframe.canvas()
# Initially, there's no tree or text
self._tree = None
self._textwidgets = []
self._textline = None
def _init_menubar(self, parent):
menubar = Menu(parent)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label='Exit', underline=1,
command=self.destroy, accelerator='q')
menubar.add_cascade(label='File', underline=0, menu=filemenu)
actionmenu = Menu(menubar, tearoff=0)
actionmenu.add_command(label='Next', underline=0,
command=self.next, accelerator='n, Space')
actionmenu.add_command(label='Previous', underline=0,
command=self.prev, accelerator='p, Backspace')
menubar.add_cascade(label='Action', underline=0, menu=actionmenu)
optionmenu = Menu(menubar, tearoff=0)
optionmenu.add_checkbutton(label='Remove Duplicates', underline=0,
variable=self._glue.remove_duplicates,
command=self._toggle_remove_duplicates,
accelerator='r')
menubar.add_cascade(label='Options', underline=0, menu=optionmenu)
viewmenu = Menu(menubar, tearoff=0)
viewmenu.add_radiobutton(label='Tiny', variable=self._size,
underline=0, value=10, command=self.resize)
viewmenu.add_radiobutton(label='Small', variable=self._size,
underline=0, value=12, command=self.resize)
viewmenu.add_radiobutton(label='Medium', variable=self._size,
underline=0, value=14, command=self.resize)
viewmenu.add_radiobutton(label='Large', variable=self._size,
underline=0, value=18, command=self.resize)
viewmenu.add_radiobutton(label='Huge', variable=self._size,
underline=0, value=24, command=self.resize)
menubar.add_cascade(label='View', underline=0, menu=viewmenu)
helpmenu = Menu(menubar, tearoff=0)
helpmenu.add_command(label='About', underline=0,
command=self.about)
menubar.add_cascade(label='Help', underline=0, menu=helpmenu)
parent.config(menu=menubar)
#########################################
## Main draw procedure
#########################################
def _redraw(self):
canvas = self._canvas
# Delete the old DRS, widgets, etc.
if self._drsWidget is not None:
self._drsWidget.clear()
if self._drs:
self._drsWidget = DrsWidget( self._canvas, self._drs )
self._drsWidget.draw()
if self._error:
self._drsWidget = DrsWidget( self._canvas, self._error )
self._drsWidget.draw()
#########################################
## Button Callbacks
#########################################
[docs] def destroy(self, *e):
self._autostep = 0
if self._top is None: return
self._top.destroy()
self._top = None
[docs] def prev(self, *e):
selection = self._readingList.curselection()
readingListSize = self._readingList.size()
# there are readings
if readingListSize > 0:
# if one reading is currently selected
if len(selection) == 1:
index = int(selection[0])
# if it's on (or before) the first item
if index <= 0:
self._select_previous_example()
else:
self._readingList_store_selection(index-1)
else:
#select its first reading
self._readingList_store_selection(readingListSize-1)
else:
self._select_previous_example()
def _select_previous_example(self):
#if the current example is not the first example
if self._curExample > 0:
self._exampleList_store_selection(self._curExample-1)
else:
#go to the last example
self._exampleList_store_selection(len(self._examples)-1)
[docs] def next(self, *e):
selection = self._readingList.curselection()
readingListSize = self._readingList.size()
# if there are readings
if readingListSize > 0:
# if one reading is currently selected
if len(selection) == 1:
index = int(selection[0])
# if it's on (or past) the last item
if index >= (readingListSize-1):
self._select_next_example()
else:
self._readingList_store_selection(index+1)
else:
#select its first reading
self._readingList_store_selection(0)
else:
self._select_next_example()
def _select_next_example(self):
#if the current example is not the last example
if self._curExample < len(self._examples)-1:
self._exampleList_store_selection(self._curExample+1)
else:
#go to the first example
self._exampleList_store_selection(0)
[docs] def about(self, *e):
ABOUT = ("NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n"+
"Written by Daniel H. Garrette")
TITLE = 'About: NLTK DRT Glue Demo'
try:
from tkMessageBox import Message
Message(message=ABOUT, title=TITLE).show()
except:
ShowText(self._top, TITLE, ABOUT)
[docs] def postscript(self, *e):
self._autostep = 0
self._cframe.print_to_file()
[docs] def mainloop(self, *args, **kwargs):
"""
Enter the Tkinter mainloop. This function must be called if
this demo is created from a non-interactive program (e.g.
from a secript); otherwise, the demo will close as soon as
the script completes.
"""
if in_idle(): return
self._top.mainloop(*args, **kwargs)
[docs] def resize(self, size=None):
if size is not None: self._size.set(size)
size = self._size.get()
self._font.configure(size=-(abs(size)))
self._boldfont.configure(size=-(abs(size)))
self._sysfont.configure(size=-(abs(size)))
self._bigfont.configure(size=-(abs(size+2)))
self._redraw()
def _toggle_remove_duplicates(self):
self._glue.remove_duplicates = not self._glue.remove_duplicates
self._exampleList.selection_clear(0, 'end')
self._readings = []
self._populate_readingListbox()
self._readingCache = [None for ex in self._examples]
self._curExample = -1
self._error = None
self._drs = None
self._redraw()
def _exampleList_select(self, event):
selection = self._exampleList.curselection()
if len(selection) != 1: return
self._exampleList_store_selection(int(selection[0]))
def _exampleList_store_selection(self, index):
self._curExample = index
example = self._examples[index]
self._exampleList.selection_clear(0, 'end')
if example:
cache = self._readingCache[index]
if cache:
if isinstance(cache, list):
self._readings = cache
self._error = None
else:
self._readings = []
self._error = cache
else:
try:
self._readings = self._glue.parse_to_meaning(example)
self._error = None
self._readingCache[index] = self._readings
except Exception as e:
self._readings = []
self._error = DrtVariableExpression(Variable('Error: ' + str(e)))
self._readingCache[index] = self._error
#add a star to the end of the example
self._exampleList.delete(index)
self._exampleList.insert(index, (' %s *' % example))
self._exampleList.config(height=min(len(self._examples), 25), width=40)
self._populate_readingListbox()
self._exampleList.selection_set(index)
self._drs = None
self._redraw()
def _readingList_select(self, event):
selection = self._readingList.curselection()
if len(selection) != 1: return
self._readingList_store_selection(int(selection[0]))
def _readingList_store_selection(self, index):
reading = self._readings[index]
self._readingList.selection_clear(0, 'end')
if reading:
self._readingList.selection_set(index)
self._drs = reading.simplify().normalize().resolve_anaphora()
self._redraw()
[docs]def demo():
examples = ['John walks',
'David sees Mary',
'David eats a sandwich',
'every man chases a dog',
# 'every man believes a dog yawns',
# 'John gives David a sandwich',
'John chases himself',
# 'John persuades David to order a pizza',
# 'John tries to go',
# 'John tries to find a unicorn',
# 'John seems to vanish',
# 'a unicorn seems to approach',
# 'every big cat leaves',
# 'every gray cat leaves',
# 'every big gray cat leaves',
# 'a former senator leaves',
# 'John likes a cat',
# 'John likes every cat',
# 'he walks',
# 'John walks and he leaves'
]
DrtGlueDemo(examples).mainloop()
if __name__ == '__main__': demo()