nltk 3.2__zip → 3.3__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (406) hide show
  1. {nltk-3.2 → nltk-3.3}/INSTALL.txt +6 -6
  2. {nltk-3.2 → nltk-3.3}/LICENSE.txt +13 -13
  3. {nltk-3.2 → nltk-3.3}/MANIFEST.in +6 -6
  4. {nltk-3.2/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
  5. nltk-3.2/README.txt → nltk-3.3/README.md +49 -48
  6. nltk-3.3/nltk/VERSION +1 -0
  7. {nltk-3.2 → nltk-3.3}/nltk/__init__.py +185 -185
  8. {nltk-3.2 → nltk-3.3}/nltk/app/__init__.py +52 -53
  9. {nltk-3.2 → nltk-3.3}/nltk/app/chartparser_app.py +2276 -2276
  10. {nltk-3.2 → nltk-3.3}/nltk/app/chunkparser_app.py +1262 -1264
  11. {nltk-3.2 → nltk-3.3}/nltk/app/collocations_app.py +347 -350
  12. {nltk-3.2 → nltk-3.3}/nltk/app/concordance_app.py +568 -570
  13. {nltk-3.2 → nltk-3.3}/nltk/app/nemo_app.py +156 -155
  14. {nltk-3.2 → nltk-3.3}/nltk/app/rdparser_app.py +892 -894
  15. {nltk-3.2 → nltk-3.3}/nltk/app/srparser_app.py +809 -809
  16. {nltk-3.2 → nltk-3.3}/nltk/app/wordfreq_app.py +32 -32
  17. {nltk-3.2 → nltk-3.3}/nltk/app/wordnet_app.py +968 -968
  18. {nltk-3.2 → nltk-3.3}/nltk/book.py +91 -90
  19. {nltk-3.2 → nltk-3.3}/nltk/ccg/__init__.py +22 -22
  20. {nltk-3.2 → nltk-3.3}/nltk/ccg/api.py +359 -335
  21. {nltk-3.2 → nltk-3.3}/nltk/ccg/chart.py +394 -361
  22. {nltk-3.2 → nltk-3.3}/nltk/ccg/combinator.py +343 -312
  23. {nltk-3.2 → nltk-3.3}/nltk/ccg/lexicon.py +328 -290
  24. nltk-3.3/nltk/ccg/logic.py +46 -0
  25. {nltk-3.2 → nltk-3.3}/nltk/chat/__init__.py +49 -49
  26. {nltk-3.2 → nltk-3.3}/nltk/chat/eliza.py +244 -244
  27. {nltk-3.2 → nltk-3.3}/nltk/chat/iesha.py +140 -140
  28. {nltk-3.2 → nltk-3.3}/nltk/chat/rude.py +92 -92
  29. {nltk-3.2 → nltk-3.3}/nltk/chat/suntsu.py +117 -117
  30. {nltk-3.2 → nltk-3.3}/nltk/chat/util.py +122 -120
  31. {nltk-3.2 → nltk-3.3}/nltk/chat/zen.py +282 -282
  32. {nltk-3.2 → nltk-3.3}/nltk/chunk/__init__.py +190 -190
  33. {nltk-3.2 → nltk-3.3}/nltk/chunk/api.py +51 -51
  34. {nltk-3.2 → nltk-3.3}/nltk/chunk/named_entity.py +331 -331
  35. {nltk-3.2 → nltk-3.3}/nltk/chunk/regexp.py +1390 -1384
  36. {nltk-3.2 → nltk-3.3}/nltk/chunk/util.py +600 -600
  37. {nltk-3.2 → nltk-3.3}/nltk/classify/__init__.py +98 -98
  38. {nltk-3.2 → nltk-3.3}/nltk/classify/api.py +193 -193
  39. {nltk-3.2 → nltk-3.3}/nltk/classify/decisiontree.py +295 -295
  40. {nltk-3.2 → nltk-3.3}/nltk/classify/maxent.py +1510 -1492
  41. {nltk-3.2 → nltk-3.3}/nltk/classify/megam.py +179 -178
  42. {nltk-3.2 → nltk-3.3}/nltk/classify/naivebayes.py +245 -242
  43. {nltk-3.2 → nltk-3.3}/nltk/classify/positivenaivebayes.py +170 -170
  44. {nltk-3.2 → nltk-3.3}/nltk/classify/rte_classify.py +160 -191
  45. {nltk-3.2 → nltk-3.3}/nltk/classify/scikitlearn.py +153 -151
  46. {nltk-3.2 → nltk-3.3}/nltk/classify/senna.py +183 -181
  47. {nltk-3.2 → nltk-3.3}/nltk/classify/svm.py +15 -15
  48. {nltk-3.2 → nltk-3.3}/nltk/classify/tadm.py +113 -112
  49. {nltk-3.2 → nltk-3.3}/nltk/classify/textcat.py +193 -193
  50. {nltk-3.2 → nltk-3.3}/nltk/classify/util.py +324 -312
  51. {nltk-3.2 → nltk-3.3}/nltk/classify/weka.py +346 -345
  52. {nltk-3.2 → nltk-3.3}/nltk/cluster/__init__.py +86 -86
  53. {nltk-3.2 → nltk-3.3}/nltk/cluster/api.py +74 -70
  54. {nltk-3.2 → nltk-3.3}/nltk/cluster/em.py +247 -247
  55. {nltk-3.2 → nltk-3.3}/nltk/cluster/gaac.py +168 -168
  56. {nltk-3.2 → nltk-3.3}/nltk/cluster/kmeans.py +221 -221
  57. {nltk-3.2 → nltk-3.3}/nltk/cluster/util.py +304 -289
  58. nltk-3.3/nltk/collections.py +640 -0
  59. {nltk-3.2 → nltk-3.3}/nltk/collocations.py +388 -388
  60. nltk-3.3/nltk/compat.py +365 -0
  61. {nltk-3.2 → nltk-3.3}/nltk/corpus/__init__.py +341 -320
  62. {nltk-3.2 → nltk-3.3}/nltk/corpus/europarl_raw.py +44 -44
  63. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/__init__.py +147 -145
  64. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/aligned.py +115 -114
  65. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/api.py +448 -446
  66. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bnc.py +252 -252
  67. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +227 -227
  68. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +179 -178
  69. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chasen.py +140 -139
  70. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/childes.py +522 -494
  71. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chunked.py +212 -212
  72. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/cmudict.py +97 -95
  73. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +280 -278
  74. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/conll.py +528 -521
  75. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/crubadan.py +116 -116
  76. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/dependency.py +101 -101
  77. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/framenet.py +3059 -2093
  78. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ieer.py +112 -111
  79. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/indian.py +85 -86
  80. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ipipan.py +332 -331
  81. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/knbc.py +187 -187
  82. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/lin.py +156 -156
  83. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/mte.py +311 -310
  84. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nkjp.py +429 -428
  85. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nombank.py +421 -421
  86. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +73 -73
  87. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +115 -115
  88. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +165 -165
  89. nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
  90. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/plaintext.py +232 -233
  91. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ppattach.py +96 -95
  92. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/propbank.py +479 -481
  93. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +128 -126
  94. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/reviews.py +330 -328
  95. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/rte.py +144 -146
  96. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/semcor.py +256 -256
  97. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/senseval.py +203 -201
  98. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +137 -137
  99. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +75 -75
  100. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/string_category.py +60 -59
  101. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/switchboard.py +119 -119
  102. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/tagged.py +295 -294
  103. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/timit.py +452 -450
  104. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/toolbox.py +68 -68
  105. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/twitter.py +155 -157
  106. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/udhr.py +80 -80
  107. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/util.py +804 -800
  108. nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
  109. nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
  110. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/wordnet.py +2108 -2036
  111. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +392 -387
  112. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ycoe.py +243 -242
  113. {nltk-3.2 → nltk-3.3}/nltk/corpus/util.py +144 -127
  114. {nltk-3.2 → nltk-3.3}/nltk/data.py +1487 -1451
  115. {nltk-3.2 → nltk-3.3}/nltk/decorators.py +219 -215
  116. {nltk-3.2 → nltk-3.3}/nltk/downloader.py +2278 -2274
  117. {nltk-3.2 → nltk-3.3}/nltk/draw/__init__.py +27 -27
  118. {nltk-3.2 → nltk-3.3}/nltk/draw/cfg.py +774 -777
  119. {nltk-3.2 → nltk-3.3}/nltk/draw/dispersion.py +58 -58
  120. {nltk-3.2 → nltk-3.3}/nltk/draw/table.py +1098 -1098
  121. {nltk-3.2 → nltk-3.3}/nltk/draw/tree.py +963 -966
  122. {nltk-3.2 → nltk-3.3}/nltk/draw/util.py +2356 -2356
  123. {nltk-3.2 → nltk-3.3}/nltk/featstruct.py +2617 -2500
  124. {nltk-3.2 → nltk-3.3}/nltk/grammar.py +1559 -1516
  125. {nltk-3.2 → nltk-3.3}/nltk/help.py +56 -56
  126. {nltk-3.2 → nltk-3.3}/nltk/inference/__init__.py +20 -20
  127. {nltk-3.2 → nltk-3.3}/nltk/inference/api.py +597 -589
  128. {nltk-3.2 → nltk-3.3}/nltk/inference/discourse.py +612 -608
  129. {nltk-3.2 → nltk-3.3}/nltk/inference/mace.py +311 -311
  130. {nltk-3.2 → nltk-3.3}/nltk/inference/nonmonotonic.py +509 -509
  131. {nltk-3.2 → nltk-3.3}/nltk/inference/prover9.py +431 -431
  132. {nltk-3.2 → nltk-3.3}/nltk/inference/resolution.py +687 -687
  133. {nltk-3.2 → nltk-3.3}/nltk/inference/tableau.py +607 -607
  134. {nltk-3.2 → nltk-3.3}/nltk/internals.py +982 -982
  135. {nltk-3.2 → nltk-3.3}/nltk/jsontags.py +63 -63
  136. {nltk-3.2 → nltk-3.3}/nltk/lazyimport.py +142 -142
  137. {nltk-3.2 → nltk-3.3}/nltk/metrics/__init__.py +30 -29
  138. {nltk-3.2 → nltk-3.3}/nltk/metrics/agreement.py +421 -401
  139. nltk-3.3/nltk/metrics/aline.py +607 -0
  140. {nltk-3.2 → nltk-3.3}/nltk/metrics/association.py +414 -410
  141. {nltk-3.2 → nltk-3.3}/nltk/metrics/confusionmatrix.py +206 -206
  142. {nltk-3.2 → nltk-3.3}/nltk/metrics/distance.py +207 -202
  143. {nltk-3.2 → nltk-3.3}/nltk/metrics/paice.py +381 -381
  144. {nltk-3.2 → nltk-3.3}/nltk/metrics/scores.py +228 -228
  145. {nltk-3.2 → nltk-3.3}/nltk/metrics/segmentation.py +231 -232
  146. {nltk-3.2 → nltk-3.3}/nltk/metrics/spearman.py +69 -69
  147. {nltk-3.2 → nltk-3.3}/nltk/misc/__init__.py +11 -11
  148. {nltk-3.2 → nltk-3.3}/nltk/misc/babelfish.py +10 -10
  149. {nltk-3.2 → nltk-3.3}/nltk/misc/chomsky.py +135 -133
  150. {nltk-3.2 → nltk-3.3}/nltk/misc/minimalset.py +83 -83
  151. {nltk-3.2 → nltk-3.3}/nltk/misc/sort.py +157 -157
  152. {nltk-3.2 → nltk-3.3}/nltk/misc/wordfinder.py +129 -129
  153. {nltk-3.2 → nltk-3.3}/nltk/parse/__init__.py +81 -80
  154. {nltk-3.2 → nltk-3.3}/nltk/parse/api.py +66 -66
  155. {nltk-3.2 → nltk-3.3}/nltk/parse/bllip.py +282 -282
  156. {nltk-3.2 → nltk-3.3}/nltk/parse/chart.py +1682 -1681
  157. nltk-3.3/nltk/parse/corenlp.py +780 -0
  158. {nltk-3.2 → nltk-3.3}/nltk/parse/dependencygraph.py +760 -758
  159. {nltk-3.2 → nltk-3.3}/nltk/parse/earleychart.py +452 -451
  160. {nltk-3.2 → nltk-3.3}/nltk/parse/evaluate.py +129 -129
  161. {nltk-3.2 → nltk-3.3}/nltk/parse/featurechart.py +580 -578
  162. {nltk-3.2 → nltk-3.3}/nltk/parse/generate.py +87 -76
  163. {nltk-3.2 → nltk-3.3}/nltk/parse/malt.py +356 -356
  164. {nltk-3.2 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +783 -783
  165. {nltk-3.2 → nltk-3.3}/nltk/parse/pchart.py +522 -522
  166. {nltk-3.2 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +579 -578
  167. {nltk-3.2 → nltk-3.3}/nltk/parse/recursivedescent.py +655 -656
  168. {nltk-3.2 → nltk-3.3}/nltk/parse/shiftreduce.py +458 -459
  169. {nltk-3.2 → nltk-3.3}/nltk/parse/stanford.py +431 -406
  170. {nltk-3.2 → nltk-3.3}/nltk/parse/transitionparser.py +774 -772
  171. {nltk-3.2 → nltk-3.3}/nltk/parse/util.py +231 -231
  172. {nltk-3.2 → nltk-3.3}/nltk/parse/viterbi.py +401 -401
  173. {nltk-3.2 → nltk-3.3}/nltk/probability.py +2410 -2355
  174. {nltk-3.2 → nltk-3.3}/nltk/sem/__init__.py +61 -61
  175. {nltk-3.2 → nltk-3.3}/nltk/sem/boxer.py +1261 -1261
  176. {nltk-3.2 → nltk-3.3}/nltk/sem/chat80.py +782 -782
  177. {nltk-3.2 → nltk-3.3}/nltk/sem/cooper_storage.py +118 -118
  178. {nltk-3.2 → nltk-3.3}/nltk/sem/drt.py +1258 -1257
  179. {nltk-3.2 → nltk-3.3}/nltk/sem/drt_glue_demo.py +485 -489
  180. {nltk-3.2 → nltk-3.3}/nltk/sem/evaluate.py +790 -784
  181. {nltk-3.2 → nltk-3.3}/nltk/sem/glue.py +696 -694
  182. {nltk-3.2 → nltk-3.3}/nltk/sem/hole.py +386 -384
  183. {nltk-3.2 → nltk-3.3}/nltk/sem/lfg.py +210 -208
  184. {nltk-3.2 → nltk-3.3}/nltk/sem/linearlogic.py +451 -449
  185. {nltk-3.2 → nltk-3.3}/nltk/sem/logic.py +1910 -1910
  186. {nltk-3.2 → nltk-3.3}/nltk/sem/relextract.py +476 -483
  187. {nltk-3.2 → nltk-3.3}/nltk/sem/skolemize.py +101 -101
  188. {nltk-3.2 → nltk-3.3}/nltk/sem/util.py +249 -249
  189. {nltk-3.2 → nltk-3.3}/nltk/sentiment/__init__.py +14 -14
  190. {nltk-3.2 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +229 -229
  191. {nltk-3.2 → nltk-3.3}/nltk/sentiment/util.py +762 -752
  192. {nltk-3.2 → nltk-3.3}/nltk/sentiment/vader.py +443 -445
  193. {nltk-3.2 → nltk-3.3}/nltk/stem/__init__.py +31 -33
  194. {nltk-3.2 → nltk-3.3}/nltk/stem/api.py +28 -25
  195. nltk-3.3/nltk/stem/arlstem.py +369 -0
  196. {nltk-3.2 → nltk-3.3}/nltk/stem/isri.py +345 -345
  197. {nltk-3.2 → nltk-3.3}/nltk/stem/lancaster.py +337 -310
  198. nltk-3.3/nltk/stem/porter.py +710 -0
  199. {nltk-3.2 → nltk-3.3}/nltk/stem/regexp.py +61 -61
  200. {nltk-3.2 → nltk-3.3}/nltk/stem/rslp.py +142 -142
  201. {nltk-3.2 → nltk-3.3}/nltk/stem/snowball.py +4236 -3712
  202. {nltk-3.2 → nltk-3.3}/nltk/stem/util.py +22 -12
  203. {nltk-3.2 → nltk-3.3}/nltk/stem/wordnet.py +51 -51
  204. {nltk-3.2 → nltk-3.3}/nltk/tag/__init__.py +152 -127
  205. {nltk-3.2 → nltk-3.3}/nltk/tag/api.py +86 -81
  206. {nltk-3.2 → nltk-3.3}/nltk/tag/brill.py +424 -426
  207. {nltk-3.2 → nltk-3.3}/nltk/tag/brill_trainer.py +608 -608
  208. {nltk-3.2 → nltk-3.3}/nltk/tag/crf.py +204 -200
  209. {nltk-3.2 → nltk-3.3}/nltk/tag/hmm.py +1277 -1277
  210. {nltk-3.2 → nltk-3.3}/nltk/tag/hunpos.py +132 -132
  211. {nltk-3.2 → nltk-3.3}/nltk/tag/mapping.py +101 -101
  212. {nltk-3.2 → nltk-3.3}/nltk/tag/perceptron.py +329 -314
  213. {nltk-3.2 → nltk-3.3}/nltk/tag/senna.py +147 -145
  214. {nltk-3.2 → nltk-3.3}/nltk/tag/sequential.py +740 -736
  215. {nltk-3.2 → nltk-3.3}/nltk/tag/stanford.py +219 -196
  216. {nltk-3.2 → nltk-3.3}/nltk/tag/tnt.py +595 -604
  217. {nltk-3.2 → nltk-3.3}/nltk/tag/util.py +72 -72
  218. {nltk-3.2 → nltk-3.3}/nltk/tbl/__init__.py +28 -28
  219. {nltk-3.2 → nltk-3.3}/nltk/tbl/api.py +1 -1
  220. {nltk-3.2 → nltk-3.3}/nltk/tbl/demo.py +366 -366
  221. {nltk-3.2 → nltk-3.3}/nltk/tbl/erroranalysis.py +39 -39
  222. {nltk-3.2 → nltk-3.3}/nltk/tbl/feature.py +259 -261
  223. {nltk-3.2 → nltk-3.3}/nltk/tbl/rule.py +321 -321
  224. {nltk-3.2 → nltk-3.3}/nltk/tbl/template.py +303 -308
  225. {nltk-3.2 → nltk-3.3}/nltk/test/__init__.py +18 -18
  226. {nltk-3.2 → nltk-3.3}/nltk/test/all.py +24 -23
  227. {nltk-3.2 → nltk-3.3}/nltk/test/bleu.doctest +14 -14
  228. {nltk-3.2 → nltk-3.3}/nltk/test/bnc.doctest +60 -60
  229. {nltk-3.2 → nltk-3.3}/nltk/test/ccg.doctest +376 -395
  230. nltk-3.3/nltk/test/ccg_semantics.doctest +553 -0
  231. {nltk-3.2 → nltk-3.3}/nltk/test/chat80.doctest +234 -234
  232. {nltk-3.2 → nltk-3.3}/nltk/test/childes.doctest +184 -184
  233. {nltk-3.2 → nltk-3.3}/nltk/test/childes_fixt.py +14 -13
  234. {nltk-3.2 → nltk-3.3}/nltk/test/chunk.doctest +373 -373
  235. {nltk-3.2 → nltk-3.3}/nltk/test/classify.doctest +185 -185
  236. {nltk-3.2 → nltk-3.3}/nltk/test/classify_fixt.py +11 -10
  237. nltk-3.3/nltk/test/collections.doctest +20 -0
  238. {nltk-3.2 → nltk-3.3}/nltk/test/collocations.doctest +276 -276
  239. {nltk-3.2 → nltk-3.3}/nltk/test/compat.doctest +134 -138
  240. {nltk-3.2 → nltk-3.3}/nltk/test/compat_fixt.py +9 -8
  241. nltk-3.3/nltk/test/concordance.doctest +55 -0
  242. {nltk-3.2 → nltk-3.3}/nltk/test/corpus.doctest +2200 -2212
  243. {nltk-3.2 → nltk-3.3}/nltk/test/corpus_fixt.py +3 -3
  244. {nltk-3.2 → nltk-3.3}/nltk/test/crubadan.doctest +65 -65
  245. {nltk-3.2 → nltk-3.3}/nltk/test/data.doctest +379 -379
  246. {nltk-3.2 → nltk-3.3}/nltk/test/dependency.doctest +241 -241
  247. {nltk-3.2 → nltk-3.3}/nltk/test/discourse.doctest +546 -546
  248. {nltk-3.2 → nltk-3.3}/nltk/test/discourse_fixt.py +14 -13
  249. {nltk-3.2 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +159 -156
  250. {nltk-3.2 → nltk-3.3}/nltk/test/drt.doctest +517 -517
  251. {nltk-3.2 → nltk-3.3}/nltk/test/featgram.doctest +607 -607
  252. {nltk-3.2 → nltk-3.3}/nltk/test/featstruct.doctest +1229 -1230
  253. {nltk-3.2 → nltk-3.3}/nltk/test/framenet.doctest +288 -239
  254. {nltk-3.2 → nltk-3.3}/nltk/test/generate.doctest +67 -67
  255. {nltk-3.2 → nltk-3.3}/nltk/test/gensim.doctest +140 -141
  256. {nltk-3.2 → nltk-3.3}/nltk/test/gensim_fixt.py +10 -9
  257. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics.doctest +384 -386
  258. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +68 -68
  259. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +12 -11
  260. {nltk-3.2 → nltk-3.3}/nltk/test/grammar.doctest +48 -48
  261. {nltk-3.2 → nltk-3.3}/nltk/test/grammartestsuites.doctest +109 -109
  262. {nltk-3.2 → nltk-3.3}/nltk/test/index.doctest +100 -100
  263. {nltk-3.2 → nltk-3.3}/nltk/test/inference.doctest +534 -534
  264. {nltk-3.2 → nltk-3.3}/nltk/test/inference_fixt.py +12 -11
  265. {nltk-3.2 → nltk-3.3}/nltk/test/internals.doctest +140 -140
  266. {nltk-3.2 → nltk-3.3}/nltk/test/japanese.doctest +48 -48
  267. {nltk-3.2 → nltk-3.3}/nltk/test/logic.doctest +1098 -1098
  268. {nltk-3.2 → nltk-3.3}/nltk/test/metrics.doctest +270 -270
  269. {nltk-3.2 → nltk-3.3}/nltk/test/misc.doctest +118 -118
  270. {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic.doctest +286 -286
  271. {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +12 -11
  272. {nltk-3.2 → nltk-3.3}/nltk/test/paice.doctest +35 -35
  273. {nltk-3.2 → nltk-3.3}/nltk/test/parse.doctest +884 -884
  274. {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en.doctest +565 -565
  275. {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +16 -16
  276. {nltk-3.2 → nltk-3.3}/nltk/test/probability.doctest +304 -304
  277. {nltk-3.2 → nltk-3.3}/nltk/test/probability_fixt.py +13 -12
  278. {nltk-3.2 → nltk-3.3}/nltk/test/propbank.doctest +176 -176
  279. {nltk-3.2 → nltk-3.3}/nltk/test/relextract.doctest +263 -263
  280. {nltk-3.2 → nltk-3.3}/nltk/test/resolution.doctest +221 -221
  281. {nltk-3.2 → nltk-3.3}/nltk/test/runtests.py +86 -64
  282. {nltk-3.2 → nltk-3.3}/nltk/test/segmentation_fixt.py +10 -10
  283. {nltk-3.2 → nltk-3.3}/nltk/test/semantics.doctest +665 -665
  284. {nltk-3.2 → nltk-3.3}/nltk/test/semantics_fixt.py +7 -7
  285. {nltk-3.2 → nltk-3.3}/nltk/test/sentiment.doctest +233 -233
  286. {nltk-3.2 → nltk-3.3}/nltk/test/sentiwordnet.doctest +41 -41
  287. {nltk-3.2 → nltk-3.3}/nltk/test/simple.doctest +85 -85
  288. {nltk-3.2 → nltk-3.3}/nltk/test/stem.doctest +78 -78
  289. {nltk-3.2 → nltk-3.3}/nltk/test/tag.doctest +33 -33
  290. {nltk-3.2 → nltk-3.3}/nltk/test/tokenize.doctest +273 -166
  291. {nltk-3.2 → nltk-3.3}/nltk/test/toolbox.doctest +307 -307
  292. {nltk-3.2 → nltk-3.3}/nltk/test/translate.doctest +242 -242
  293. {nltk-3.2 → nltk-3.3}/nltk/test/translate_fixt.py +3 -3
  294. {nltk-3.2 → nltk-3.3}/nltk/test/tree.doctest +1101 -1101
  295. {nltk-3.2 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +127 -127
  296. {nltk-3.2 → nltk-3.3}/nltk/test/treetransforms.doctest +156 -156
  297. nltk-3.3/nltk/test/unit/test_2x_compat.py +63 -0
  298. nltk-3.3/nltk/test/unit/test_aline.py +52 -0
  299. nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
  300. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_classify.py +55 -53
  301. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_collocations.py +88 -79
  302. nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
  303. nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
  304. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpora.py +200 -183
  305. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +45 -45
  306. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_hmm.py +88 -88
  307. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +188 -187
  308. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +26 -26
  309. nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
  310. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +124 -124
  311. nltk-3.3/nltk/test/unit/test_senna.py +74 -0
  312. nltk-3.3/nltk/test/unit/test_stem.py +121 -0
  313. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tag.py +20 -20
  314. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tgrep.py +628 -626
  315. nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
  316. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +185 -185
  317. nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
  318. nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
  319. nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
  320. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +75 -75
  321. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +87 -87
  322. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +105 -105
  323. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +126 -126
  324. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +166 -166
  325. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +270 -270
  326. nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
  327. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +300 -300
  328. {nltk-3.2 → nltk-3.3}/nltk/test/unit/utils.py +41 -41
  329. {nltk-3.2 → nltk-3.3}/nltk/test/util.doctest +48 -48
  330. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet.doctest +595 -581
  331. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_fixt.py +7 -6
  332. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_lch.doctest +53 -53
  333. {nltk-3.2 → nltk-3.3}/nltk/test/wsd.doctest +68 -68
  334. {nltk-3.2 → nltk-3.3}/nltk/text.py +663 -610
  335. {nltk-3.2 → nltk-3.3}/nltk/tgrep.py +938 -937
  336. {nltk-3.2 → nltk-3.3}/nltk/tokenize/__init__.py +130 -107
  337. {nltk-3.2 → nltk-3.3}/nltk/tokenize/api.py +77 -78
  338. {nltk-3.2 → nltk-3.3}/nltk/tokenize/casual.py +343 -342
  339. {nltk-3.2 → nltk-3.3}/nltk/tokenize/mwe.py +120 -120
  340. nltk-3.3/nltk/tokenize/nist.py +173 -0
  341. {nltk-3.2 → nltk-3.3}/nltk/tokenize/punkt.py +1620 -1601
  342. {nltk-3.2 → nltk-3.3}/nltk/tokenize/regexp.py +208 -202
  343. nltk-3.3/nltk/tokenize/repp.py +151 -0
  344. {nltk-3.2 → nltk-3.3}/nltk/tokenize/sexpr.py +140 -142
  345. {nltk-3.2 → nltk-3.3}/nltk/tokenize/simple.py +138 -136
  346. {nltk-3.2 → nltk-3.3}/nltk/tokenize/stanford.py +117 -113
  347. nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
  348. {nltk-3.2 → nltk-3.3}/nltk/tokenize/texttiling.py +458 -460
  349. nltk-3.3/nltk/tokenize/toktok.py +155 -0
  350. nltk-3.3/nltk/tokenize/treebank.py +363 -0
  351. nltk-3.3/nltk/tokenize/util.py +261 -0
  352. {nltk-3.2 → nltk-3.3}/nltk/toolbox.py +499 -497
  353. {nltk-3.2 → nltk-3.3}/nltk/translate/__init__.py +24 -24
  354. {nltk-3.2 → nltk-3.3}/nltk/translate/api.py +331 -321
  355. {nltk-3.2 → nltk-3.3}/nltk/translate/bleu_score.py +615 -556
  356. nltk-3.3/nltk/translate/chrf_score.py +137 -0
  357. {nltk-3.2 → nltk-3.3}/nltk/translate/gale_church.py +248 -235
  358. {nltk-3.2 → nltk-3.3}/nltk/translate/gdfa.py +135 -131
  359. nltk-3.3/nltk/translate/gleu_score.py +193 -0
  360. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm1.py +250 -241
  361. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm2.py +308 -308
  362. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm3.py +337 -337
  363. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm4.py +467 -467
  364. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm5.py +639 -639
  365. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm_model.py +536 -533
  366. {nltk-3.2 → nltk-3.3}/nltk/translate/metrics.py +40 -40
  367. nltk-3.3/nltk/translate/nist_score.py +178 -0
  368. {nltk-3.2 → nltk-3.3}/nltk/translate/phrase_based.py +175 -175
  369. {nltk-3.2 → nltk-3.3}/nltk/translate/ribes_score.py +325 -325
  370. {nltk-3.2 → nltk-3.3}/nltk/translate/stack_decoder.py +499 -495
  371. {nltk-3.2 → nltk-3.3}/nltk/tree.py +1605 -1603
  372. {nltk-3.2 → nltk-3.3}/nltk/treeprettyprinter.py +564 -564
  373. {nltk-3.2 → nltk-3.3}/nltk/treetransforms.py +309 -309
  374. {nltk-3.2 → nltk-3.3}/nltk/twitter/__init__.py +28 -28
  375. {nltk-3.2 → nltk-3.3}/nltk/twitter/api.py +141 -136
  376. {nltk-3.2 → nltk-3.3}/nltk/twitter/common.py +264 -258
  377. {nltk-3.2 → nltk-3.3}/nltk/twitter/twitter_demo.py +288 -288
  378. {nltk-3.2 → nltk-3.3}/nltk/twitter/twitterclient.py +530 -530
  379. {nltk-3.2 → nltk-3.3}/nltk/twitter/util.py +147 -146
  380. nltk-3.3/nltk/util.py +751 -0
  381. {nltk-3.2 → nltk-3.3}/nltk/wsd.py +53 -53
  382. {nltk-3.2 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
  383. {nltk-3.2 → nltk-3.3}/nltk.egg-info/SOURCES.txt +26 -3
  384. nltk-3.3/nltk.egg-info/requires.txt +31 -0
  385. {nltk-3.2 → nltk-3.3}/setup.cfg +0 -1
  386. {nltk-3.2 → nltk-3.3}/setup.py +102 -75
  387. nltk-3.2/nltk/VERSION +0 -1
  388. nltk-3.2/nltk/compat.py +0 -680
  389. nltk-3.2/nltk/corpus/reader/pl196x.py +0 -278
  390. nltk-3.2/nltk/corpus/reader/verbnet.py +0 -408
  391. nltk-3.2/nltk/corpus/reader/wordlist.py +0 -37
  392. nltk-3.2/nltk/sentiment/vader_lexicon.txt +0 -7517
  393. nltk-3.2/nltk/six.py +0 -868
  394. nltk-3.2/nltk/stem/porter.py +0 -692
  395. nltk-3.2/nltk/test/unit/test_2x_compat.py +0 -26
  396. nltk-3.2/nltk/test/unit/test_stem.py +0 -36
  397. nltk-3.2/nltk/test/unit/test_tokenize.py +0 -23
  398. nltk-3.2/nltk/test/unit/translate/test_bleu.py +0 -84
  399. nltk-3.2/nltk/tokenize/treebank.py +0 -124
  400. nltk-3.2/nltk/tokenize/util.py +0 -90
  401. nltk-3.2/nltk/util.py +0 -1364
  402. {nltk-3.2 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
  403. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
  404. {nltk-3.2 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
  405. {nltk-3.2 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
  406. {nltk-3.2 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
@@ -1,966 +1,963 @@
1
- # Natural Language Toolkit: Graphical Representations for Trees
2
- #
3
- # Copyright (C) 2001-2015 NLTK Project
4
- # Author: Edward Loper <edloper@gmail.com>
5
- # URL: <http://nltk.org/>
6
- # For license information, see LICENSE.TXT
7
-
8
- """
9
- Graphically display a Tree.
10
- """
11
-
12
- import nltk.compat
13
- import sys
14
-
15
- from tkinter import IntVar, Menu, Tk
16
-
17
- from nltk.util import in_idle
18
- from nltk.tree import Tree
19
- from nltk.draw.util import (CanvasFrame, CanvasWidget, BoxWidget,
20
- TextWidget, ParenWidget, OvalWidget)
21
-
22
- ##//////////////////////////////////////////////////////
23
- ## Tree Segment
24
- ##//////////////////////////////////////////////////////
25
-
26
- class TreeSegmentWidget(CanvasWidget):
27
- """
28
- A canvas widget that displays a single segment of a hierarchical
29
- tree. Each ``TreeSegmentWidget`` connects a single "node widget"
30
- to a sequence of zero or more "subtree widgets". By default, the
31
- bottom of the node is connected to the top of each subtree by a
32
- single line. However, if the ``roof`` attribute is set, then a
33
- single triangular "roof" will connect the node to all of its
34
- children.
35
-
36
- Attributes:
37
- - ``roof``: What sort of connection to draw between the node and
38
- its subtrees. If ``roof`` is true, draw a single triangular
39
- "roof" over the subtrees. If ``roof`` is false, draw a line
40
- between each subtree and the node. Default value is false.
41
- - ``xspace``: The amount of horizontal space to leave between
42
- subtrees when managing this widget. Default value is 10.
43
- - ``yspace``: The amount of space to place between the node and
44
- its children when managing this widget. Default value is 15.
45
- - ``color``: The color of the lines connecting the node to its
46
- subtrees; and of the outline of the triangular roof. Default
47
- value is ``'#006060'``.
48
- - ``fill``: The fill color for the triangular roof. Default
49
- value is ``''`` (no fill).
50
- - ``width``: The width of the lines connecting the node to its
51
- subtrees; and of the outline of the triangular roof. Default
52
- value is 1.
53
- - ``orientation``: Determines whether the tree branches downwards
54
- or rightwards. Possible values are ``'horizontal'`` and
55
- ``'vertical'``. The default value is ``'vertical'`` (i.e.,
56
- branch downwards).
57
- - ``draggable``: whether the widget can be dragged by the user.
58
- """
59
- def __init__(self, canvas, label, subtrees, **attribs):
60
- """
61
- :type node:
62
- :type subtrees: list(CanvasWidgetI)
63
- """
64
- self._label = label
65
- self._subtrees = subtrees
66
-
67
- # Attributes
68
- self._horizontal = 0
69
- self._roof = 0
70
- self._xspace = 10
71
- self._yspace = 15
72
- self._ordered = False
73
-
74
- # Create canvas objects.
75
- self._lines = [canvas.create_line(0,0,0,0, fill='#006060')
76
- for c in subtrees]
77
- self._polygon = canvas.create_polygon(0,0, fill='', state='hidden',
78
- outline='#006060')
79
-
80
- # Register child widgets (label + subtrees)
81
- self._add_child_widget(label)
82
- for subtree in subtrees:
83
- self._add_child_widget(subtree)
84
-
85
- # Are we currently managing?
86
- self._managing = False
87
-
88
- CanvasWidget.__init__(self, canvas, **attribs)
89
-
90
- def __setitem__(self, attr, value):
91
- canvas = self.canvas()
92
- if attr == 'roof':
93
- self._roof = value
94
- if self._roof:
95
- for l in self._lines: canvas.itemconfig(l, state='hidden')
96
- canvas.itemconfig(self._polygon, state='normal')
97
- else:
98
- for l in self._lines: canvas.itemconfig(l, state='normal')
99
- canvas.itemconfig(self._polygon, state='hidden')
100
- elif attr == 'orientation':
101
- if value == 'horizontal': self._horizontal = 1
102
- elif value == 'vertical': self._horizontal = 0
103
- else:
104
- raise ValueError('orientation must be horizontal or vertical')
105
- elif attr == 'color':
106
- for l in self._lines: canvas.itemconfig(l, fill=value)
107
- canvas.itemconfig(self._polygon, outline=value)
108
- elif isinstance(attr, tuple) and attr[0] == 'color':
109
- # Set the color of an individual line.
110
- l = self._lines[int(attr[1])]
111
- canvas.itemconfig(l, fill=value)
112
- elif attr == 'fill':
113
- canvas.itemconfig(self._polygon, fill=value)
114
- elif attr == 'width':
115
- canvas.itemconfig(self._polygon, {attr:value})
116
- for l in self._lines: canvas.itemconfig(l, {attr:value})
117
- elif attr in ('xspace', 'yspace'):
118
- if attr == 'xspace': self._xspace = value
119
- elif attr == 'yspace': self._yspace = value
120
- self.update(self._label)
121
- elif attr == 'ordered':
122
- self._ordered = value
123
- else:
124
- CanvasWidget.__setitem__(self, attr, value)
125
-
126
- def __getitem__(self, attr):
127
- if attr == 'roof': return self._roof
128
- elif attr == 'width':
129
- return self.canvas().itemcget(self._polygon, attr)
130
- elif attr == 'color':
131
- return self.canvas().itemcget(self._polygon, 'outline')
132
- elif isinstance(attr, tuple) and attr[0] == 'color':
133
- l = self._lines[int(attr[1])]
134
- return self.canvas().itemcget(l, 'fill')
135
- elif attr == 'xspace': return self._xspace
136
- elif attr == 'yspace': return self._yspace
137
- elif attr == 'orientation':
138
- if self._horizontal: return 'horizontal'
139
- else: return 'vertical'
140
- elif attr == 'ordered':
141
- return self._ordered
142
- else:
143
- return CanvasWidget.__getitem__(self, attr)
144
-
145
- def label(self):
146
- return self._label
147
-
148
- def subtrees(self):
149
- return self._subtrees[:]
150
-
151
- def set_label(self, label):
152
- """
153
- Set the node label to ``label``.
154
- """
155
- self._remove_child_widget(self._label)
156
- self._add_child_widget(label)
157
- self._label = label
158
- self.update(self._label)
159
-
160
- def replace_child(self, oldchild, newchild):
161
- """
162
- Replace the child ``oldchild`` with ``newchild``.
163
- """
164
- index = self._subtrees.index(oldchild)
165
- self._subtrees[index] = newchild
166
- self._remove_child_widget(oldchild)
167
- self._add_child_widget(newchild)
168
- self.update(newchild)
169
-
170
- def remove_child(self, child):
171
- index = self._subtrees.index(child)
172
- del self._subtrees[index]
173
- self._remove_child_widget(child)
174
- self.canvas().delete(self._lines.pop())
175
- self.update(self._label)
176
-
177
- def insert_child(self, index, child):
178
- canvas = self.canvas()
179
- self._subtrees.insert(index, child)
180
- self._add_child_widget(child)
181
- self._lines.append(canvas.create_line(0,0,0,0, fill='#006060'))
182
- self.update(self._label)
183
-
184
- # but.. lines???
185
-
186
- def _tags(self):
187
- if self._roof:
188
- return [self._polygon]
189
- else:
190
- return self._lines
191
-
192
- def _subtree_top(self, child):
193
- if isinstance(child, TreeSegmentWidget):
194
- bbox = child.label().bbox()
195
- else:
196
- bbox = child.bbox()
197
- if self._horizontal:
198
- return (bbox[0], (bbox[1]+bbox[3])/2.0)
199
- else:
200
- return ((bbox[0]+bbox[2])/2.0, bbox[1])
201
-
202
- def _node_bottom(self):
203
- bbox = self._label.bbox()
204
- if self._horizontal:
205
- return (bbox[2], (bbox[1]+bbox[3])/2.0)
206
- else:
207
- return ((bbox[0]+bbox[2])/2.0, bbox[3])
208
-
209
- def _update(self, child):
210
- if len(self._subtrees) == 0: return
211
- if self._label.bbox() is None: return # [XX] ???
212
-
213
- # Which lines need to be redrawn?
214
- if child is self._label: need_update = self._subtrees
215
- else: need_update = [child]
216
-
217
- if self._ordered and not self._managing:
218
- need_update = self._maintain_order(child)
219
-
220
- # Update the polygon.
221
- (nodex, nodey) = self._node_bottom()
222
- (xmin, ymin, xmax, ymax) = self._subtrees[0].bbox()
223
- for subtree in self._subtrees[1:]:
224
- bbox = subtree.bbox()
225
- xmin = min(xmin, bbox[0])
226
- ymin = min(ymin, bbox[1])
227
- xmax = max(xmax, bbox[2])
228
- ymax = max(ymax, bbox[3])
229
-
230
- if self._horizontal:
231
- self.canvas().coords(self._polygon, nodex, nodey, xmin,
232
- ymin, xmin, ymax, nodex, nodey)
233
- else:
234
- self.canvas().coords(self._polygon, nodex, nodey, xmin,
235
- ymin, xmax, ymin, nodex, nodey)
236
-
237
- # Redraw all lines that need it.
238
- for subtree in need_update:
239
- (nodex, nodey) = self._node_bottom()
240
- line = self._lines[self._subtrees.index(subtree)]
241
- (subtreex, subtreey) = self._subtree_top(subtree)
242
- self.canvas().coords(line, nodex, nodey, subtreex, subtreey)
243
-
244
- def _maintain_order(self, child):
245
- if self._horizontal:
246
- return self._maintain_order_horizontal(child)
247
- else:
248
- return self._maintain_order_vertical(child)
249
-
250
- def _maintain_order_vertical(self, child):
251
- (left, top, right, bot) = child.bbox()
252
-
253
- if child is self._label:
254
- # Check all the leaves
255
- for subtree in self._subtrees:
256
- (x1, y1, x2, y2) = subtree.bbox()
257
- if bot+self._yspace > y1:
258
- subtree.move(0,bot+self._yspace-y1)
259
-
260
- return self._subtrees
261
- else:
262
- moved = [child]
263
- index = self._subtrees.index(child)
264
-
265
- # Check leaves to our right.
266
- x = right + self._xspace
267
- for i in range(index+1, len(self._subtrees)):
268
- (x1, y1, x2, y2) = self._subtrees[i].bbox()
269
- if x > x1:
270
- self._subtrees[i].move(x-x1, 0)
271
- x += x2-x1 + self._xspace
272
- moved.append(self._subtrees[i])
273
-
274
- # Check leaves to our left.
275
- x = left - self._xspace
276
- for i in range(index-1, -1, -1):
277
- (x1, y1, x2, y2) = self._subtrees[i].bbox()
278
- if x < x2:
279
- self._subtrees[i].move(x-x2, 0)
280
- x -= x2-x1 + self._xspace
281
- moved.append(self._subtrees[i])
282
-
283
- # Check the node
284
- (x1, y1, x2, y2) = self._label.bbox()
285
- if y2 > top-self._yspace:
286
- self._label.move(0, top-self._yspace-y2)
287
- moved = self._subtrees
288
-
289
- # Return a list of the nodes we moved
290
- return moved
291
-
292
- def _maintain_order_horizontal(self, child):
293
- (left, top, right, bot) = child.bbox()
294
-
295
- if child is self._label:
296
- # Check all the leaves
297
- for subtree in self._subtrees:
298
- (x1, y1, x2, y2) = subtree.bbox()
299
- if right+self._xspace > x1:
300
- subtree.move(right+self._xspace-x1)
301
-
302
- return self._subtrees
303
- else:
304
- moved = [child]
305
- index = self._subtrees.index(child)
306
-
307
- # Check leaves below us.
308
- y = bot + self._yspace
309
- for i in range(index+1, len(self._subtrees)):
310
- (x1, y1, x2, y2) = self._subtrees[i].bbox()
311
- if y > y1:
312
- self._subtrees[i].move(0, y-y1)
313
- y += y2-y1 + self._yspace
314
- moved.append(self._subtrees[i])
315
-
316
- # Check leaves above us
317
- y = top - self._yspace
318
- for i in range(index-1, -1, -1):
319
- (x1, y1, x2, y2) = self._subtrees[i].bbox()
320
- if y < y2:
321
- self._subtrees[i].move(0, y-y2)
322
- y -= y2-y1 + self._yspace
323
- moved.append(self._subtrees[i])
324
-
325
- # Check the node
326
- (x1, y1, x2, y2) = self._label.bbox()
327
- if x2 > left-self._xspace:
328
- self._label.move(left-self._xspace-x2, 0)
329
- moved = self._subtrees
330
-
331
- # Return a list of the nodes we moved
332
- return moved
333
-
334
- def _manage_horizontal(self):
335
- (nodex, nodey) = self._node_bottom()
336
-
337
- # Put the subtrees in a line.
338
- y = 20
339
- for subtree in self._subtrees:
340
- subtree_bbox = subtree.bbox()
341
- dx = nodex - subtree_bbox[0] + self._xspace
342
- dy = y - subtree_bbox[1]
343
- subtree.move(dx, dy)
344
- y += subtree_bbox[3] - subtree_bbox[1] + self._yspace
345
-
346
- # Find the center of their tops.
347
- center = 0.0
348
- for subtree in self._subtrees:
349
- center += self._subtree_top(subtree)[1]
350
- center /= len(self._subtrees)
351
-
352
- # Center the subtrees with the node.
353
- for subtree in self._subtrees:
354
- subtree.move(0, nodey-center)
355
-
356
- def _manage_vertical(self):
357
- (nodex, nodey) = self._node_bottom()
358
-
359
- # Put the subtrees in a line.
360
- x = 0
361
- for subtree in self._subtrees:
362
- subtree_bbox = subtree.bbox()
363
- dy = nodey - subtree_bbox[1] + self._yspace
364
- dx = x - subtree_bbox[0]
365
- subtree.move(dx, dy)
366
- x += subtree_bbox[2] - subtree_bbox[0] + self._xspace
367
-
368
- # Find the center of their tops.
369
- center = 0.0
370
- for subtree in self._subtrees:
371
- center += self._subtree_top(subtree)[0]/len(self._subtrees)
372
-
373
- # Center the subtrees with the node.
374
- for subtree in self._subtrees:
375
- subtree.move(nodex-center, 0)
376
-
377
- def _manage(self):
378
- self._managing = True
379
- (nodex, nodey) = self._node_bottom()
380
- if len(self._subtrees) == 0: return
381
-
382
- if self._horizontal: self._manage_horizontal()
383
- else: self._manage_vertical()
384
-
385
- # Update lines to subtrees.
386
- for subtree in self._subtrees:
387
- self._update(subtree)
388
-
389
- self._managing = False
390
-
391
- def __repr__(self):
392
- return '[TreeSeg %s: %s]' % (self._label, self._subtrees)
393
-
394
- def _tree_to_treeseg(canvas, t, make_node, make_leaf,
395
- tree_attribs, node_attribs,
396
- leaf_attribs, loc_attribs):
397
- if isinstance(t, Tree):
398
- label = make_node(canvas, t.label(), **node_attribs)
399
- subtrees = [_tree_to_treeseg(canvas, child, make_node, make_leaf,
400
- tree_attribs, node_attribs,
401
- leaf_attribs, loc_attribs)
402
- for child in t]
403
- return TreeSegmentWidget(canvas, label, subtrees, **tree_attribs)
404
- else:
405
- return make_leaf(canvas, t, **leaf_attribs)
406
-
407
- def tree_to_treesegment(canvas, t, make_node=TextWidget,
408
- make_leaf=TextWidget, **attribs):
409
- """
410
- Convert a Tree into a ``TreeSegmentWidget``.
411
-
412
- :param make_node: A ``CanvasWidget`` constructor or a function that
413
- creates ``CanvasWidgets``. ``make_node`` is used to convert
414
- the Tree's nodes into ``CanvasWidgets``. If no constructor
415
- is specified, then ``TextWidget`` will be used.
416
- :param make_leaf: A ``CanvasWidget`` constructor or a function that
417
- creates ``CanvasWidgets``. ``make_leaf`` is used to convert
418
- the Tree's leafs into ``CanvasWidgets``. If no constructor
419
- is specified, then ``TextWidget`` will be used.
420
- :param attribs: Attributes for the canvas widgets that make up the
421
- returned ``TreeSegmentWidget``. Any attribute beginning with
422
- ``'tree_'`` will be passed to all ``TreeSegmentWidgets`` (with
423
- the ``'tree_'`` prefix removed. Any attribute beginning with
424
- ``'node_'`` will be passed to all nodes. Any attribute
425
- beginning with ``'leaf_'`` will be passed to all leaves. And
426
- any attribute beginning with ``'loc_'`` will be passed to all
427
- text locations (for Trees).
428
- """
429
- # Process attribs.
430
- tree_attribs = {}
431
- node_attribs = {}
432
- leaf_attribs = {}
433
- loc_attribs = {}
434
-
435
- for (key, value) in list(attribs.items()):
436
- if key[:5] == 'tree_': tree_attribs[key[5:]] = value
437
- elif key[:5] == 'node_': node_attribs[key[5:]] = value
438
- elif key[:5] == 'leaf_': leaf_attribs[key[5:]] = value
439
- elif key[:4] == 'loc_': loc_attribs[key[4:]] = value
440
- else: raise ValueError('Bad attribute: %s' % key)
441
- return _tree_to_treeseg(canvas, t, make_node, make_leaf,
442
- tree_attribs, node_attribs,
443
- leaf_attribs, loc_attribs)
444
-
445
- ##//////////////////////////////////////////////////////
446
- ## Tree Widget
447
- ##//////////////////////////////////////////////////////
448
-
449
- class TreeWidget(CanvasWidget):
450
- """
451
- A canvas widget that displays a single Tree.
452
- ``TreeWidget`` manages a group of ``TreeSegmentWidgets`` that are
453
- used to display a Tree.
454
-
455
- Attributes:
456
-
457
- - ``node_attr``: Sets the attribute ``attr`` on all of the
458
- node widgets for this ``TreeWidget``.
459
- - ``node_attr``: Sets the attribute ``attr`` on all of the
460
- leaf widgets for this ``TreeWidget``.
461
- - ``loc_attr``: Sets the attribute ``attr`` on all of the
462
- location widgets for this ``TreeWidget`` (if it was built from
463
- a Tree). Note that a location widget is a ``TextWidget``.
464
-
465
- - ``xspace``: The amount of horizontal space to leave between
466
- subtrees when managing this widget. Default value is 10.
467
- - ``yspace``: The amount of space to place between the node and
468
- its children when managing this widget. Default value is 15.
469
-
470
- - ``line_color``: The color of the lines connecting each expanded
471
- node to its subtrees.
472
- - ``roof_color``: The color of the outline of the triangular roof
473
- for collapsed trees.
474
- - ``roof_fill``: The fill color for the triangular roof for
475
- collapsed trees.
476
- - ``width``
477
-
478
- - ``orientation``: Determines whether the tree branches downwards
479
- or rightwards. Possible values are ``'horizontal'`` and
480
- ``'vertical'``. The default value is ``'vertical'`` (i.e.,
481
- branch downwards).
482
-
483
- - ``shapeable``: whether the subtrees can be independently
484
- dragged by the user. THIS property simply sets the
485
- ``DRAGGABLE`` property on all of the ``TreeWidget``'s tree
486
- segments.
487
- - ``draggable``: whether the widget can be dragged by the user.
488
- """
489
- def __init__(self, canvas, t, make_node=TextWidget,
490
- make_leaf=TextWidget, **attribs):
491
- # Node & leaf canvas widget constructors
492
- self._make_node = make_node
493
- self._make_leaf = make_leaf
494
- self._tree = t
495
-
496
- # Attributes.
497
- self._nodeattribs = {}
498
- self._leafattribs = {}
499
- self._locattribs = {'color': '#008000'}
500
- self._line_color = '#008080'
501
- self._line_width = 1
502
- self._roof_color = '#008080'
503
- self._roof_fill = '#c0c0c0'
504
- self._shapeable = False
505
- self._xspace = 10
506
- self._yspace = 10
507
- self._orientation = 'vertical'
508
- self._ordered = False
509
-
510
- # Build trees.
511
- self._keys = {} # treeseg -> key
512
- self._expanded_trees = {}
513
- self._collapsed_trees = {}
514
- self._nodes = []
515
- self._leaves = []
516
- #self._locs = []
517
- self._make_collapsed_trees(canvas, t, ())
518
- self._treeseg = self._make_expanded_tree(canvas, t, ())
519
- self._add_child_widget(self._treeseg)
520
-
521
- CanvasWidget.__init__(self, canvas, **attribs)
522
-
523
- def expanded_tree(self, *path_to_tree):
524
- """
525
- Return the ``TreeSegmentWidget`` for the specified subtree.
526
-
527
- :param path_to_tree: A list of indices i1, i2, ..., in, where
528
- the desired widget is the widget corresponding to
529
- ``tree.children()[i1].children()[i2]....children()[in]``.
530
- For the root, the path is ``()``.
531
- """
532
- return self._expanded_trees[path_to_tree]
533
-
534
- def collapsed_tree(self, *path_to_tree):
535
- """
536
- Return the ``TreeSegmentWidget`` for the specified subtree.
537
-
538
- :param path_to_tree: A list of indices i1, i2, ..., in, where
539
- the desired widget is the widget corresponding to
540
- ``tree.children()[i1].children()[i2]....children()[in]``.
541
- For the root, the path is ``()``.
542
- """
543
- return self._collapsed_trees[path_to_tree]
544
-
545
- def bind_click_trees(self, callback, button=1):
546
- """
547
- Add a binding to all tree segments.
548
- """
549
- for tseg in list(self._expanded_trees.values()):
550
- tseg.bind_click(callback, button)
551
- for tseg in list(self._collapsed_trees.values()):
552
- tseg.bind_click(callback, button)
553
-
554
- def bind_drag_trees(self, callback, button=1):
555
- """
556
- Add a binding to all tree segments.
557
- """
558
- for tseg in list(self._expanded_trees.values()):
559
- tseg.bind_drag(callback, button)
560
- for tseg in list(self._collapsed_trees.values()):
561
- tseg.bind_drag(callback, button)
562
-
563
- def bind_click_leaves(self, callback, button=1):
564
- """
565
- Add a binding to all leaves.
566
- """
567
- for leaf in self._leaves: leaf.bind_click(callback, button)
568
- for leaf in self._leaves: leaf.bind_click(callback, button)
569
-
570
- def bind_drag_leaves(self, callback, button=1):
571
- """
572
- Add a binding to all leaves.
573
- """
574
- for leaf in self._leaves: leaf.bind_drag(callback, button)
575
- for leaf in self._leaves: leaf.bind_drag(callback, button)
576
-
577
- def bind_click_nodes(self, callback, button=1):
578
- """
579
- Add a binding to all nodes.
580
- """
581
- for node in self._nodes: node.bind_click(callback, button)
582
- for node in self._nodes: node.bind_click(callback, button)
583
-
584
- def bind_drag_nodes(self, callback, button=1):
585
- """
586
- Add a binding to all nodes.
587
- """
588
- for node in self._nodes: node.bind_drag(callback, button)
589
- for node in self._nodes: node.bind_drag(callback, button)
590
-
591
- def _make_collapsed_trees(self, canvas, t, key):
592
- if not isinstance(t, Tree): return
593
- make_node = self._make_node
594
- make_leaf = self._make_leaf
595
-
596
- node = make_node(canvas, t.label(), **self._nodeattribs)
597
- self._nodes.append(node)
598
- leaves = [make_leaf(canvas, l, **self._leafattribs)
599
- for l in t.leaves()]
600
- self._leaves += leaves
601
- treeseg = TreeSegmentWidget(canvas, node, leaves, roof=1,
602
- color=self._roof_color,
603
- fill=self._roof_fill,
604
- width=self._line_width)
605
-
606
- self._collapsed_trees[key] = treeseg
607
- self._keys[treeseg] = key
608
- #self._add_child_widget(treeseg)
609
- treeseg.hide()
610
-
611
- # Build trees for children.
612
- for i in range(len(t)):
613
- child = t[i]
614
- self._make_collapsed_trees(canvas, child, key + (i,))
615
-
616
- def _make_expanded_tree(self, canvas, t, key):
617
- make_node = self._make_node
618
- make_leaf = self._make_leaf
619
-
620
- if isinstance(t, Tree):
621
- node = make_node(canvas, t.label(), **self._nodeattribs)
622
- self._nodes.append(node)
623
- children = t
624
- subtrees = [self._make_expanded_tree(canvas, children[i], key+(i,))
625
- for i in range(len(children))]
626
- treeseg = TreeSegmentWidget(canvas, node, subtrees,
627
- color=self._line_color,
628
- width=self._line_width)
629
- self._expanded_trees[key] = treeseg
630
- self._keys[treeseg] = key
631
- return treeseg
632
- else:
633
- leaf = make_leaf(canvas, t, **self._leafattribs)
634
- self._leaves.append(leaf)
635
- return leaf
636
-
637
- def __setitem__(self, attr, value):
638
- if attr[:5] == 'node_':
639
- for node in self._nodes: node[attr[5:]] = value
640
- elif attr[:5] == 'leaf_':
641
- for leaf in self._leaves: leaf[attr[5:]] = value
642
- elif attr == 'line_color':
643
- self._line_color = value
644
- for tseg in list(self._expanded_trees.values()): tseg['color'] = value
645
- elif attr == 'line_width':
646
- self._line_width = value
647
- for tseg in list(self._expanded_trees.values()): tseg['width'] = value
648
- for tseg in list(self._collapsed_trees.values()): tseg['width'] = value
649
- elif attr == 'roof_color':
650
- self._roof_color = value
651
- for tseg in list(self._collapsed_trees.values()): tseg['color'] = value
652
- elif attr == 'roof_fill':
653
- self._roof_fill = value
654
- for tseg in list(self._collapsed_trees.values()): tseg['fill'] = value
655
- elif attr == 'shapeable':
656
- self._shapeable = value
657
- for tseg in list(self._expanded_trees.values()):
658
- tseg['draggable'] = value
659
- for tseg in list(self._collapsed_trees.values()):
660
- tseg['draggable'] = value
661
- for leaf in self._leaves: leaf['draggable'] = value
662
- elif attr == 'xspace':
663
- self._xspace = value
664
- for tseg in list(self._expanded_trees.values()):
665
- tseg['xspace'] = value
666
- for tseg in list(self._collapsed_trees.values()):
667
- tseg['xspace'] = value
668
- self.manage()
669
- elif attr == 'yspace':
670
- self._yspace = value
671
- for tseg in list(self._expanded_trees.values()):
672
- tseg['yspace'] = value
673
- for tseg in list(self._collapsed_trees.values()):
674
- tseg['yspace'] = value
675
- self.manage()
676
- elif attr == 'orientation':
677
- self._orientation = value
678
- for tseg in list(self._expanded_trees.values()):
679
- tseg['orientation'] = value
680
- for tseg in list(self._collapsed_trees.values()):
681
- tseg['orientation'] = value
682
- self.manage()
683
- elif attr == 'ordered':
684
- self._ordered = value
685
- for tseg in list(self._expanded_trees.values()):
686
- tseg['ordered'] = value
687
- for tseg in list(self._collapsed_trees.values()):
688
- tseg['ordered'] = value
689
- else: CanvasWidget.__setitem__(self, attr, value)
690
-
691
- def __getitem__(self, attr):
692
- if attr[:5] == 'node_':
693
- return self._nodeattribs.get(attr[5:], None)
694
- elif attr[:5] == 'leaf_':
695
- return self._leafattribs.get(attr[5:], None)
696
- elif attr[:4] == 'loc_':
697
- return self._locattribs.get(attr[4:], None)
698
- elif attr == 'line_color': return self._line_color
699
- elif attr == 'line_width': return self._line_width
700
- elif attr == 'roof_color': return self._roof_color
701
- elif attr == 'roof_fill': return self._roof_fill
702
- elif attr == 'shapeable': return self._shapeable
703
- elif attr == 'xspace': return self._xspace
704
- elif attr == 'yspace': return self._yspace
705
- elif attr == 'orientation': return self._orientation
706
- else: return CanvasWidget.__getitem__(self, attr)
707
-
708
- def _tags(self): return []
709
-
710
- def _manage(self):
711
- segs = list(self._expanded_trees.values()) + list(self._collapsed_trees.values())
712
- for tseg in segs:
713
- if tseg.hidden():
714
- tseg.show()
715
- tseg.manage()
716
- tseg.hide()
717
-
718
- def toggle_collapsed(self, treeseg):
719
- """
720
- Collapse/expand a tree.
721
- """
722
- old_treeseg = treeseg
723
- if old_treeseg['roof']:
724
- new_treeseg = self._expanded_trees[self._keys[old_treeseg]]
725
- else:
726
- new_treeseg = self._collapsed_trees[self._keys[old_treeseg]]
727
-
728
- # Replace the old tree with the new tree.
729
- if old_treeseg.parent() is self:
730
- self._remove_child_widget(old_treeseg)
731
- self._add_child_widget(new_treeseg)
732
- self._treeseg = new_treeseg
733
- else:
734
- old_treeseg.parent().replace_child(old_treeseg, new_treeseg)
735
-
736
- # Move the new tree to where the old tree was. Show it first,
737
- # so we can find its bounding box.
738
- new_treeseg.show()
739
- (newx, newy) = new_treeseg.label().bbox()[:2]
740
- (oldx, oldy) = old_treeseg.label().bbox()[:2]
741
- new_treeseg.move(oldx-newx, oldy-newy)
742
-
743
- # Hide the old tree
744
- old_treeseg.hide()
745
-
746
- # We could do parent.manage() here instead, if we wanted.
747
- new_treeseg.parent().update(new_treeseg)
748
-
749
- ##//////////////////////////////////////////////////////
750
- ## draw_trees
751
- ##//////////////////////////////////////////////////////
752
-
753
- class TreeView(object):
754
- def __init__(self, *trees):
755
- from math import sqrt, ceil
756
-
757
- self._trees = trees
758
-
759
- self._top = Tk()
760
- self._top.title('NLTK')
761
- self._top.bind('<Control-x>', self.destroy)
762
- self._top.bind('<Control-q>', self.destroy)
763
-
764
- cf = self._cframe = CanvasFrame(self._top)
765
- self._top.bind('<Control-p>', self._cframe.print_to_file)
766
-
767
- # Size is variable.
768
- self._size = IntVar(self._top)
769
- self._size.set(12)
770
- bold = ('helvetica', -self._size.get(), 'bold')
771
- helv = ('helvetica', -self._size.get())
772
-
773
- # Lay the trees out in a square.
774
- self._width = int(ceil(sqrt(len(trees))))
775
- self._widgets = []
776
- for i in range(len(trees)):
777
- widget = TreeWidget(cf.canvas(), trees[i], node_font=bold,
778
- leaf_color='#008040', node_color='#004080',
779
- roof_color='#004040', roof_fill='white',
780
- line_color='#004040', draggable=1,
781
- leaf_font=helv)
782
- widget.bind_click_trees(widget.toggle_collapsed)
783
- self._widgets.append(widget)
784
- cf.add_widget(widget, 0, 0)
785
-
786
- self._layout()
787
- self._cframe.pack(expand=1, fill='both')
788
- self._init_menubar()
789
-
790
- def _layout(self):
791
- i = x = y = ymax = 0
792
- width = self._width
793
- for i in range(len(self._widgets)):
794
- widget = self._widgets[i]
795
- (oldx, oldy) = widget.bbox()[:2]
796
- if i % width == 0:
797
- y = ymax
798
- x = 0
799
- widget.move(x-oldx, y-oldy)
800
- x = widget.bbox()[2] + 10
801
- ymax = max(ymax, widget.bbox()[3] + 10)
802
-
803
- def _init_menubar(self):
804
- menubar = Menu(self._top)
805
-
806
- filemenu = Menu(menubar, tearoff=0)
807
- filemenu.add_command(label='Print to Postscript', underline=0,
808
- command=self._cframe.print_to_file,
809
- accelerator='Ctrl-p')
810
- filemenu.add_command(label='Exit', underline=1,
811
- command=self.destroy, accelerator='Ctrl-x')
812
- menubar.add_cascade(label='File', underline=0, menu=filemenu)
813
-
814
- zoommenu = Menu(menubar, tearoff=0)
815
- zoommenu.add_radiobutton(label='Tiny', variable=self._size,
816
- underline=0, value=10, command=self.resize)
817
- zoommenu.add_radiobutton(label='Small', variable=self._size,
818
- underline=0, value=12, command=self.resize)
819
- zoommenu.add_radiobutton(label='Medium', variable=self._size,
820
- underline=0, value=14, command=self.resize)
821
- zoommenu.add_radiobutton(label='Large', variable=self._size,
822
- underline=0, value=28, command=self.resize)
823
- zoommenu.add_radiobutton(label='Huge', variable=self._size,
824
- underline=0, value=50, command=self.resize)
825
- menubar.add_cascade(label='Zoom', underline=0, menu=zoommenu)
826
-
827
- self._top.config(menu=menubar)
828
-
829
- def resize(self, *e):
830
- bold = ('helvetica', -self._size.get(), 'bold')
831
- helv = ('helvetica', -self._size.get())
832
- xspace = self._size.get()
833
- yspace = self._size.get()
834
- for widget in self._widgets:
835
- widget['node_font'] = bold
836
- widget['leaf_font'] = helv
837
- widget['xspace'] = xspace
838
- widget['yspace'] = yspace
839
- if self._size.get() < 20: widget['line_width'] = 1
840
- elif self._size.get() < 30: widget['line_width'] = 2
841
- else: widget['line_width'] = 3
842
- self._layout()
843
-
844
- def destroy(self, *e):
845
- if self._top is None: return
846
- self._top.destroy()
847
- self._top = None
848
-
849
- def mainloop(self, *args, **kwargs):
850
- """
851
- Enter the Tkinter mainloop. This function must be called if
852
- this demo is created from a non-interactive program (e.g.
853
- from a secript); otherwise, the demo will close as soon as
854
- the script completes.
855
- """
856
- if in_idle(): return
857
- self._top.mainloop(*args, **kwargs)
858
-
859
- def draw_trees(*trees):
860
- """
861
- Open a new window containing a graphical diagram of the given
862
- trees.
863
-
864
- :rtype: None
865
- """
866
- TreeView(*trees).mainloop()
867
- return
868
-
869
- ##//////////////////////////////////////////////////////
870
- ## Demo Code
871
- ##//////////////////////////////////////////////////////
872
-
873
- def demo():
874
- import random
875
- def fill(cw):
876
- cw['fill'] = '#%06d' % random.randint(0,999999)
877
-
878
- cf = CanvasFrame(width=550, height=450, closeenough=2)
879
-
880
- t = Tree.fromstring('''
881
- (S (NP the very big cat)
882
- (VP (Adv sorta) (V saw) (NP (Det the) (N dog))))''')
883
-
884
- tc = TreeWidget(cf.canvas(), t, draggable=1,
885
- node_font=('helvetica', -14, 'bold'),
886
- leaf_font=('helvetica', -12, 'italic'),
887
- roof_fill='white', roof_color='black',
888
- leaf_color='green4', node_color='blue2')
889
- cf.add_widget(tc,10,10)
890
-
891
- def boxit(canvas, text):
892
- big = ('helvetica', -16, 'bold')
893
- return BoxWidget(canvas, TextWidget(canvas, text,
894
- font=big), fill='green')
895
- def ovalit(canvas, text):
896
- return OvalWidget(canvas, TextWidget(canvas, text),
897
- fill='cyan')
898
-
899
- treetok = Tree.fromstring('(S (NP this tree) (VP (V is) (AdjP shapeable)))')
900
- tc2 = TreeWidget(cf.canvas(), treetok, boxit, ovalit, shapeable=1)
901
-
902
- def color(node):
903
- node['color'] = '#%04d00' % random.randint(0,9999)
904
- def color2(treeseg):
905
- treeseg.label()['fill'] = '#%06d' % random.randint(0,9999)
906
- treeseg.label().child()['color'] = 'white'
907
-
908
- tc.bind_click_trees(tc.toggle_collapsed)
909
- tc2.bind_click_trees(tc2.toggle_collapsed)
910
- tc.bind_click_nodes(color, 3)
911
- tc2.expanded_tree(1).bind_click(color2, 3)
912
- tc2.expanded_tree().bind_click(color2, 3)
913
-
914
- paren = ParenWidget(cf.canvas(), tc2)
915
- cf.add_widget(paren, tc.bbox()[2]+10, 10)
916
-
917
- tree3 = Tree.fromstring('''
918
- (S (NP this tree) (AUX was)
919
- (VP (V built) (PP (P with) (NP (N tree_to_treesegment)))))''')
920
- tc3 = tree_to_treesegment(cf.canvas(), tree3, tree_color='green4',
921
- tree_xspace=2, tree_width=2)
922
- tc3['draggable'] = 1
923
- cf.add_widget(tc3, 10, tc.bbox()[3]+10)
924
-
925
- def orientswitch(treewidget):
926
- if treewidget['orientation'] == 'horizontal':
927
- treewidget.expanded_tree(1,1).subtrees()[0].set_text('vertical')
928
- treewidget.collapsed_tree(1,1).subtrees()[0].set_text('vertical')
929
- treewidget.collapsed_tree(1).subtrees()[1].set_text('vertical')
930
- treewidget.collapsed_tree().subtrees()[3].set_text('vertical')
931
- treewidget['orientation'] = 'vertical'
932
- else:
933
- treewidget.expanded_tree(1,1).subtrees()[0].set_text('horizontal')
934
- treewidget.collapsed_tree(1,1).subtrees()[0].set_text('horizontal')
935
- treewidget.collapsed_tree(1).subtrees()[1].set_text('horizontal')
936
- treewidget.collapsed_tree().subtrees()[3].set_text('horizontal')
937
- treewidget['orientation'] = 'horizontal'
938
-
939
- text = """
940
- Try clicking, right clicking, and dragging
941
- different elements of each of the trees.
942
- The top-left tree is a TreeWidget built from
943
- a Tree. The top-right is a TreeWidget built
944
- from a Tree, using non-default widget
945
- constructors for the nodes & leaves (BoxWidget
946
- and OvalWidget). The bottom-left tree is
947
- built from tree_to_treesegment."""
948
- twidget = TextWidget(cf.canvas(), text.strip())
949
- textbox = BoxWidget(cf.canvas(), twidget, fill='white', draggable=1)
950
- cf.add_widget(textbox, tc3.bbox()[2]+10, tc2.bbox()[3]+10)
951
-
952
- tree4 = Tree.fromstring('(S (NP this tree) (VP (V is) (Adj horizontal)))')
953
- tc4 = TreeWidget(cf.canvas(), tree4, draggable=1,
954
- line_color='brown2', roof_color='brown2',
955
- node_font=('helvetica', -12, 'bold'),
956
- node_color='brown4', orientation='horizontal')
957
- tc4.manage()
958
- cf.add_widget(tc4, tc3.bbox()[2]+10, textbox.bbox()[3]+10)
959
- tc4.bind_click(orientswitch)
960
- tc4.bind_click_trees(tc4.toggle_collapsed, 3)
961
-
962
- # Run mainloop
963
- cf.mainloop()
964
-
965
- if __name__ == '__main__':
966
- demo()
1
+ # Natural Language Toolkit: Graphical Representations for Trees
2
+ #
3
+ # Copyright (C) 2001-2018 NLTK Project
4
+ # Author: Edward Loper <edloper@gmail.com>
5
+ # URL: <http://nltk.org/>
6
+ # For license information, see LICENSE.TXT
7
+
8
+ """
9
+ Graphically display a Tree.
10
+ """
11
+
12
+ from six.moves.tkinter import IntVar, Menu, Tk
13
+
14
+ from nltk.util import in_idle
15
+ from nltk.tree import Tree
16
+ from nltk.draw.util import (CanvasFrame, CanvasWidget, BoxWidget,
17
+ TextWidget, ParenWidget, OvalWidget)
18
+
19
+ ##//////////////////////////////////////////////////////
20
+ ## Tree Segment
21
+ ##//////////////////////////////////////////////////////
22
+
23
+ class TreeSegmentWidget(CanvasWidget):
24
+ """
25
+ A canvas widget that displays a single segment of a hierarchical
26
+ tree. Each ``TreeSegmentWidget`` connects a single "node widget"
27
+ to a sequence of zero or more "subtree widgets". By default, the
28
+ bottom of the node is connected to the top of each subtree by a
29
+ single line. However, if the ``roof`` attribute is set, then a
30
+ single triangular "roof" will connect the node to all of its
31
+ children.
32
+
33
+ Attributes:
34
+ - ``roof``: What sort of connection to draw between the node and
35
+ its subtrees. If ``roof`` is true, draw a single triangular
36
+ "roof" over the subtrees. If ``roof`` is false, draw a line
37
+ between each subtree and the node. Default value is false.
38
+ - ``xspace``: The amount of horizontal space to leave between
39
+ subtrees when managing this widget. Default value is 10.
40
+ - ``yspace``: The amount of space to place between the node and
41
+ its children when managing this widget. Default value is 15.
42
+ - ``color``: The color of the lines connecting the node to its
43
+ subtrees; and of the outline of the triangular roof. Default
44
+ value is ``'#006060'``.
45
+ - ``fill``: The fill color for the triangular roof. Default
46
+ value is ``''`` (no fill).
47
+ - ``width``: The width of the lines connecting the node to its
48
+ subtrees; and of the outline of the triangular roof. Default
49
+ value is 1.
50
+ - ``orientation``: Determines whether the tree branches downwards
51
+ or rightwards. Possible values are ``'horizontal'`` and
52
+ ``'vertical'``. The default value is ``'vertical'`` (i.e.,
53
+ branch downwards).
54
+ - ``draggable``: whether the widget can be dragged by the user.
55
+ """
56
+ def __init__(self, canvas, label, subtrees, **attribs):
57
+ """
58
+ :type node:
59
+ :type subtrees: list(CanvasWidgetI)
60
+ """
61
+ self._label = label
62
+ self._subtrees = subtrees
63
+
64
+ # Attributes
65
+ self._horizontal = 0
66
+ self._roof = 0
67
+ self._xspace = 10
68
+ self._yspace = 15
69
+ self._ordered = False
70
+
71
+ # Create canvas objects.
72
+ self._lines = [canvas.create_line(0,0,0,0, fill='#006060')
73
+ for c in subtrees]
74
+ self._polygon = canvas.create_polygon(0,0, fill='', state='hidden',
75
+ outline='#006060')
76
+
77
+ # Register child widgets (label + subtrees)
78
+ self._add_child_widget(label)
79
+ for subtree in subtrees:
80
+ self._add_child_widget(subtree)
81
+
82
+ # Are we currently managing?
83
+ self._managing = False
84
+
85
+ CanvasWidget.__init__(self, canvas, **attribs)
86
+
87
+ def __setitem__(self, attr, value):
88
+ canvas = self.canvas()
89
+ if attr == 'roof':
90
+ self._roof = value
91
+ if self._roof:
92
+ for l in self._lines: canvas.itemconfig(l, state='hidden')
93
+ canvas.itemconfig(self._polygon, state='normal')
94
+ else:
95
+ for l in self._lines: canvas.itemconfig(l, state='normal')
96
+ canvas.itemconfig(self._polygon, state='hidden')
97
+ elif attr == 'orientation':
98
+ if value == 'horizontal': self._horizontal = 1
99
+ elif value == 'vertical': self._horizontal = 0
100
+ else:
101
+ raise ValueError('orientation must be horizontal or vertical')
102
+ elif attr == 'color':
103
+ for l in self._lines: canvas.itemconfig(l, fill=value)
104
+ canvas.itemconfig(self._polygon, outline=value)
105
+ elif isinstance(attr, tuple) and attr[0] == 'color':
106
+ # Set the color of an individual line.
107
+ l = self._lines[int(attr[1])]
108
+ canvas.itemconfig(l, fill=value)
109
+ elif attr == 'fill':
110
+ canvas.itemconfig(self._polygon, fill=value)
111
+ elif attr == 'width':
112
+ canvas.itemconfig(self._polygon, {attr:value})
113
+ for l in self._lines: canvas.itemconfig(l, {attr:value})
114
+ elif attr in ('xspace', 'yspace'):
115
+ if attr == 'xspace': self._xspace = value
116
+ elif attr == 'yspace': self._yspace = value
117
+ self.update(self._label)
118
+ elif attr == 'ordered':
119
+ self._ordered = value
120
+ else:
121
+ CanvasWidget.__setitem__(self, attr, value)
122
+
123
+ def __getitem__(self, attr):
124
+ if attr == 'roof': return self._roof
125
+ elif attr == 'width':
126
+ return self.canvas().itemcget(self._polygon, attr)
127
+ elif attr == 'color':
128
+ return self.canvas().itemcget(self._polygon, 'outline')
129
+ elif isinstance(attr, tuple) and attr[0] == 'color':
130
+ l = self._lines[int(attr[1])]
131
+ return self.canvas().itemcget(l, 'fill')
132
+ elif attr == 'xspace': return self._xspace
133
+ elif attr == 'yspace': return self._yspace
134
+ elif attr == 'orientation':
135
+ if self._horizontal: return 'horizontal'
136
+ else: return 'vertical'
137
+ elif attr == 'ordered':
138
+ return self._ordered
139
+ else:
140
+ return CanvasWidget.__getitem__(self, attr)
141
+
142
+ def label(self):
143
+ return self._label
144
+
145
+ def subtrees(self):
146
+ return self._subtrees[:]
147
+
148
+ def set_label(self, label):
149
+ """
150
+ Set the node label to ``label``.
151
+ """
152
+ self._remove_child_widget(self._label)
153
+ self._add_child_widget(label)
154
+ self._label = label
155
+ self.update(self._label)
156
+
157
+ def replace_child(self, oldchild, newchild):
158
+ """
159
+ Replace the child ``oldchild`` with ``newchild``.
160
+ """
161
+ index = self._subtrees.index(oldchild)
162
+ self._subtrees[index] = newchild
163
+ self._remove_child_widget(oldchild)
164
+ self._add_child_widget(newchild)
165
+ self.update(newchild)
166
+
167
+ def remove_child(self, child):
168
+ index = self._subtrees.index(child)
169
+ del self._subtrees[index]
170
+ self._remove_child_widget(child)
171
+ self.canvas().delete(self._lines.pop())
172
+ self.update(self._label)
173
+
174
+ def insert_child(self, index, child):
175
+ canvas = self.canvas()
176
+ self._subtrees.insert(index, child)
177
+ self._add_child_widget(child)
178
+ self._lines.append(canvas.create_line(0,0,0,0, fill='#006060'))
179
+ self.update(self._label)
180
+
181
+ # but.. lines???
182
+
183
+ def _tags(self):
184
+ if self._roof:
185
+ return [self._polygon]
186
+ else:
187
+ return self._lines
188
+
189
+ def _subtree_top(self, child):
190
+ if isinstance(child, TreeSegmentWidget):
191
+ bbox = child.label().bbox()
192
+ else:
193
+ bbox = child.bbox()
194
+ if self._horizontal:
195
+ return (bbox[0], (bbox[1]+bbox[3])/2.0)
196
+ else:
197
+ return ((bbox[0]+bbox[2])/2.0, bbox[1])
198
+
199
+ def _node_bottom(self):
200
+ bbox = self._label.bbox()
201
+ if self._horizontal:
202
+ return (bbox[2], (bbox[1]+bbox[3])/2.0)
203
+ else:
204
+ return ((bbox[0]+bbox[2])/2.0, bbox[3])
205
+
206
+ def _update(self, child):
207
+ if len(self._subtrees) == 0: return
208
+ if self._label.bbox() is None: return # [XX] ???
209
+
210
+ # Which lines need to be redrawn?
211
+ if child is self._label: need_update = self._subtrees
212
+ else: need_update = [child]
213
+
214
+ if self._ordered and not self._managing:
215
+ need_update = self._maintain_order(child)
216
+
217
+ # Update the polygon.
218
+ (nodex, nodey) = self._node_bottom()
219
+ (xmin, ymin, xmax, ymax) = self._subtrees[0].bbox()
220
+ for subtree in self._subtrees[1:]:
221
+ bbox = subtree.bbox()
222
+ xmin = min(xmin, bbox[0])
223
+ ymin = min(ymin, bbox[1])
224
+ xmax = max(xmax, bbox[2])
225
+ ymax = max(ymax, bbox[3])
226
+
227
+ if self._horizontal:
228
+ self.canvas().coords(self._polygon, nodex, nodey, xmin,
229
+ ymin, xmin, ymax, nodex, nodey)
230
+ else:
231
+ self.canvas().coords(self._polygon, nodex, nodey, xmin,
232
+ ymin, xmax, ymin, nodex, nodey)
233
+
234
+ # Redraw all lines that need it.
235
+ for subtree in need_update:
236
+ (nodex, nodey) = self._node_bottom()
237
+ line = self._lines[self._subtrees.index(subtree)]
238
+ (subtreex, subtreey) = self._subtree_top(subtree)
239
+ self.canvas().coords(line, nodex, nodey, subtreex, subtreey)
240
+
241
+ def _maintain_order(self, child):
242
+ if self._horizontal:
243
+ return self._maintain_order_horizontal(child)
244
+ else:
245
+ return self._maintain_order_vertical(child)
246
+
247
+ def _maintain_order_vertical(self, child):
248
+ (left, top, right, bot) = child.bbox()
249
+
250
+ if child is self._label:
251
+ # Check all the leaves
252
+ for subtree in self._subtrees:
253
+ (x1, y1, x2, y2) = subtree.bbox()
254
+ if bot+self._yspace > y1:
255
+ subtree.move(0,bot+self._yspace-y1)
256
+
257
+ return self._subtrees
258
+ else:
259
+ moved = [child]
260
+ index = self._subtrees.index(child)
261
+
262
+ # Check leaves to our right.
263
+ x = right + self._xspace
264
+ for i in range(index+1, len(self._subtrees)):
265
+ (x1, y1, x2, y2) = self._subtrees[i].bbox()
266
+ if x > x1:
267
+ self._subtrees[i].move(x-x1, 0)
268
+ x += x2-x1 + self._xspace
269
+ moved.append(self._subtrees[i])
270
+
271
+ # Check leaves to our left.
272
+ x = left - self._xspace
273
+ for i in range(index-1, -1, -1):
274
+ (x1, y1, x2, y2) = self._subtrees[i].bbox()
275
+ if x < x2:
276
+ self._subtrees[i].move(x-x2, 0)
277
+ x -= x2-x1 + self._xspace
278
+ moved.append(self._subtrees[i])
279
+
280
+ # Check the node
281
+ (x1, y1, x2, y2) = self._label.bbox()
282
+ if y2 > top-self._yspace:
283
+ self._label.move(0, top-self._yspace-y2)
284
+ moved = self._subtrees
285
+
286
+ # Return a list of the nodes we moved
287
+ return moved
288
+
289
+ def _maintain_order_horizontal(self, child):
290
+ (left, top, right, bot) = child.bbox()
291
+
292
+ if child is self._label:
293
+ # Check all the leaves
294
+ for subtree in self._subtrees:
295
+ (x1, y1, x2, y2) = subtree.bbox()
296
+ if right+self._xspace > x1:
297
+ subtree.move(right+self._xspace-x1)
298
+
299
+ return self._subtrees
300
+ else:
301
+ moved = [child]
302
+ index = self._subtrees.index(child)
303
+
304
+ # Check leaves below us.
305
+ y = bot + self._yspace
306
+ for i in range(index+1, len(self._subtrees)):
307
+ (x1, y1, x2, y2) = self._subtrees[i].bbox()
308
+ if y > y1:
309
+ self._subtrees[i].move(0, y-y1)
310
+ y += y2-y1 + self._yspace
311
+ moved.append(self._subtrees[i])
312
+
313
+ # Check leaves above us
314
+ y = top - self._yspace
315
+ for i in range(index-1, -1, -1):
316
+ (x1, y1, x2, y2) = self._subtrees[i].bbox()
317
+ if y < y2:
318
+ self._subtrees[i].move(0, y-y2)
319
+ y -= y2-y1 + self._yspace
320
+ moved.append(self._subtrees[i])
321
+
322
+ # Check the node
323
+ (x1, y1, x2, y2) = self._label.bbox()
324
+ if x2 > left-self._xspace:
325
+ self._label.move(left-self._xspace-x2, 0)
326
+ moved = self._subtrees
327
+
328
+ # Return a list of the nodes we moved
329
+ return moved
330
+
331
+ def _manage_horizontal(self):
332
+ (nodex, nodey) = self._node_bottom()
333
+
334
+ # Put the subtrees in a line.
335
+ y = 20
336
+ for subtree in self._subtrees:
337
+ subtree_bbox = subtree.bbox()
338
+ dx = nodex - subtree_bbox[0] + self._xspace
339
+ dy = y - subtree_bbox[1]
340
+ subtree.move(dx, dy)
341
+ y += subtree_bbox[3] - subtree_bbox[1] + self._yspace
342
+
343
+ # Find the center of their tops.
344
+ center = 0.0
345
+ for subtree in self._subtrees:
346
+ center += self._subtree_top(subtree)[1]
347
+ center /= len(self._subtrees)
348
+
349
+ # Center the subtrees with the node.
350
+ for subtree in self._subtrees:
351
+ subtree.move(0, nodey-center)
352
+
353
+ def _manage_vertical(self):
354
+ (nodex, nodey) = self._node_bottom()
355
+
356
+ # Put the subtrees in a line.
357
+ x = 0
358
+ for subtree in self._subtrees:
359
+ subtree_bbox = subtree.bbox()
360
+ dy = nodey - subtree_bbox[1] + self._yspace
361
+ dx = x - subtree_bbox[0]
362
+ subtree.move(dx, dy)
363
+ x += subtree_bbox[2] - subtree_bbox[0] + self._xspace
364
+
365
+ # Find the center of their tops.
366
+ center = 0.0
367
+ for subtree in self._subtrees:
368
+ center += self._subtree_top(subtree)[0]/len(self._subtrees)
369
+
370
+ # Center the subtrees with the node.
371
+ for subtree in self._subtrees:
372
+ subtree.move(nodex-center, 0)
373
+
374
+ def _manage(self):
375
+ self._managing = True
376
+ (nodex, nodey) = self._node_bottom()
377
+ if len(self._subtrees) == 0: return
378
+
379
+ if self._horizontal: self._manage_horizontal()
380
+ else: self._manage_vertical()
381
+
382
+ # Update lines to subtrees.
383
+ for subtree in self._subtrees:
384
+ self._update(subtree)
385
+
386
+ self._managing = False
387
+
388
+ def __repr__(self):
389
+ return '[TreeSeg %s: %s]' % (self._label, self._subtrees)
390
+
391
+ def _tree_to_treeseg(canvas, t, make_node, make_leaf,
392
+ tree_attribs, node_attribs,
393
+ leaf_attribs, loc_attribs):
394
+ if isinstance(t, Tree):
395
+ label = make_node(canvas, t.label(), **node_attribs)
396
+ subtrees = [_tree_to_treeseg(canvas, child, make_node, make_leaf,
397
+ tree_attribs, node_attribs,
398
+ leaf_attribs, loc_attribs)
399
+ for child in t]
400
+ return TreeSegmentWidget(canvas, label, subtrees, **tree_attribs)
401
+ else:
402
+ return make_leaf(canvas, t, **leaf_attribs)
403
+
404
+ def tree_to_treesegment(canvas, t, make_node=TextWidget,
405
+ make_leaf=TextWidget, **attribs):
406
+ """
407
+ Convert a Tree into a ``TreeSegmentWidget``.
408
+
409
+ :param make_node: A ``CanvasWidget`` constructor or a function that
410
+ creates ``CanvasWidgets``. ``make_node`` is used to convert
411
+ the Tree's nodes into ``CanvasWidgets``. If no constructor
412
+ is specified, then ``TextWidget`` will be used.
413
+ :param make_leaf: A ``CanvasWidget`` constructor or a function that
414
+ creates ``CanvasWidgets``. ``make_leaf`` is used to convert
415
+ the Tree's leafs into ``CanvasWidgets``. If no constructor
416
+ is specified, then ``TextWidget`` will be used.
417
+ :param attribs: Attributes for the canvas widgets that make up the
418
+ returned ``TreeSegmentWidget``. Any attribute beginning with
419
+ ``'tree_'`` will be passed to all ``TreeSegmentWidgets`` (with
420
+ the ``'tree_'`` prefix removed. Any attribute beginning with
421
+ ``'node_'`` will be passed to all nodes. Any attribute
422
+ beginning with ``'leaf_'`` will be passed to all leaves. And
423
+ any attribute beginning with ``'loc_'`` will be passed to all
424
+ text locations (for Trees).
425
+ """
426
+ # Process attribs.
427
+ tree_attribs = {}
428
+ node_attribs = {}
429
+ leaf_attribs = {}
430
+ loc_attribs = {}
431
+
432
+ for (key, value) in list(attribs.items()):
433
+ if key[:5] == 'tree_': tree_attribs[key[5:]] = value
434
+ elif key[:5] == 'node_': node_attribs[key[5:]] = value
435
+ elif key[:5] == 'leaf_': leaf_attribs[key[5:]] = value
436
+ elif key[:4] == 'loc_': loc_attribs[key[4:]] = value
437
+ else: raise ValueError('Bad attribute: %s' % key)
438
+ return _tree_to_treeseg(canvas, t, make_node, make_leaf,
439
+ tree_attribs, node_attribs,
440
+ leaf_attribs, loc_attribs)
441
+
442
+ ##//////////////////////////////////////////////////////
443
+ ## Tree Widget
444
+ ##//////////////////////////////////////////////////////
445
+
446
+ class TreeWidget(CanvasWidget):
447
+ """
448
+ A canvas widget that displays a single Tree.
449
+ ``TreeWidget`` manages a group of ``TreeSegmentWidgets`` that are
450
+ used to display a Tree.
451
+
452
+ Attributes:
453
+
454
+ - ``node_attr``: Sets the attribute ``attr`` on all of the
455
+ node widgets for this ``TreeWidget``.
456
+ - ``node_attr``: Sets the attribute ``attr`` on all of the
457
+ leaf widgets for this ``TreeWidget``.
458
+ - ``loc_attr``: Sets the attribute ``attr`` on all of the
459
+ location widgets for this ``TreeWidget`` (if it was built from
460
+ a Tree). Note that a location widget is a ``TextWidget``.
461
+
462
+ - ``xspace``: The amount of horizontal space to leave between
463
+ subtrees when managing this widget. Default value is 10.
464
+ - ``yspace``: The amount of space to place between the node and
465
+ its children when managing this widget. Default value is 15.
466
+
467
+ - ``line_color``: The color of the lines connecting each expanded
468
+ node to its subtrees.
469
+ - ``roof_color``: The color of the outline of the triangular roof
470
+ for collapsed trees.
471
+ - ``roof_fill``: The fill color for the triangular roof for
472
+ collapsed trees.
473
+ - ``width``
474
+
475
+ - ``orientation``: Determines whether the tree branches downwards
476
+ or rightwards. Possible values are ``'horizontal'`` and
477
+ ``'vertical'``. The default value is ``'vertical'`` (i.e.,
478
+ branch downwards).
479
+
480
+ - ``shapeable``: whether the subtrees can be independently
481
+ dragged by the user. THIS property simply sets the
482
+ ``DRAGGABLE`` property on all of the ``TreeWidget``'s tree
483
+ segments.
484
+ - ``draggable``: whether the widget can be dragged by the user.
485
+ """
486
+ def __init__(self, canvas, t, make_node=TextWidget,
487
+ make_leaf=TextWidget, **attribs):
488
+ # Node & leaf canvas widget constructors
489
+ self._make_node = make_node
490
+ self._make_leaf = make_leaf
491
+ self._tree = t
492
+
493
+ # Attributes.
494
+ self._nodeattribs = {}
495
+ self._leafattribs = {}
496
+ self._locattribs = {'color': '#008000'}
497
+ self._line_color = '#008080'
498
+ self._line_width = 1
499
+ self._roof_color = '#008080'
500
+ self._roof_fill = '#c0c0c0'
501
+ self._shapeable = False
502
+ self._xspace = 10
503
+ self._yspace = 10
504
+ self._orientation = 'vertical'
505
+ self._ordered = False
506
+
507
+ # Build trees.
508
+ self._keys = {} # treeseg -> key
509
+ self._expanded_trees = {}
510
+ self._collapsed_trees = {}
511
+ self._nodes = []
512
+ self._leaves = []
513
+ #self._locs = []
514
+ self._make_collapsed_trees(canvas, t, ())
515
+ self._treeseg = self._make_expanded_tree(canvas, t, ())
516
+ self._add_child_widget(self._treeseg)
517
+
518
+ CanvasWidget.__init__(self, canvas, **attribs)
519
+
520
+ def expanded_tree(self, *path_to_tree):
521
+ """
522
+ Return the ``TreeSegmentWidget`` for the specified subtree.
523
+
524
+ :param path_to_tree: A list of indices i1, i2, ..., in, where
525
+ the desired widget is the widget corresponding to
526
+ ``tree.children()[i1].children()[i2]....children()[in]``.
527
+ For the root, the path is ``()``.
528
+ """
529
+ return self._expanded_trees[path_to_tree]
530
+
531
+ def collapsed_tree(self, *path_to_tree):
532
+ """
533
+ Return the ``TreeSegmentWidget`` for the specified subtree.
534
+
535
+ :param path_to_tree: A list of indices i1, i2, ..., in, where
536
+ the desired widget is the widget corresponding to
537
+ ``tree.children()[i1].children()[i2]....children()[in]``.
538
+ For the root, the path is ``()``.
539
+ """
540
+ return self._collapsed_trees[path_to_tree]
541
+
542
+ def bind_click_trees(self, callback, button=1):
543
+ """
544
+ Add a binding to all tree segments.
545
+ """
546
+ for tseg in list(self._expanded_trees.values()):
547
+ tseg.bind_click(callback, button)
548
+ for tseg in list(self._collapsed_trees.values()):
549
+ tseg.bind_click(callback, button)
550
+
551
+ def bind_drag_trees(self, callback, button=1):
552
+ """
553
+ Add a binding to all tree segments.
554
+ """
555
+ for tseg in list(self._expanded_trees.values()):
556
+ tseg.bind_drag(callback, button)
557
+ for tseg in list(self._collapsed_trees.values()):
558
+ tseg.bind_drag(callback, button)
559
+
560
+ def bind_click_leaves(self, callback, button=1):
561
+ """
562
+ Add a binding to all leaves.
563
+ """
564
+ for leaf in self._leaves: leaf.bind_click(callback, button)
565
+ for leaf in self._leaves: leaf.bind_click(callback, button)
566
+
567
+ def bind_drag_leaves(self, callback, button=1):
568
+ """
569
+ Add a binding to all leaves.
570
+ """
571
+ for leaf in self._leaves: leaf.bind_drag(callback, button)
572
+ for leaf in self._leaves: leaf.bind_drag(callback, button)
573
+
574
+ def bind_click_nodes(self, callback, button=1):
575
+ """
576
+ Add a binding to all nodes.
577
+ """
578
+ for node in self._nodes: node.bind_click(callback, button)
579
+ for node in self._nodes: node.bind_click(callback, button)
580
+
581
+ def bind_drag_nodes(self, callback, button=1):
582
+ """
583
+ Add a binding to all nodes.
584
+ """
585
+ for node in self._nodes: node.bind_drag(callback, button)
586
+ for node in self._nodes: node.bind_drag(callback, button)
587
+
588
+ def _make_collapsed_trees(self, canvas, t, key):
589
+ if not isinstance(t, Tree): return
590
+ make_node = self._make_node
591
+ make_leaf = self._make_leaf
592
+
593
+ node = make_node(canvas, t.label(), **self._nodeattribs)
594
+ self._nodes.append(node)
595
+ leaves = [make_leaf(canvas, l, **self._leafattribs)
596
+ for l in t.leaves()]
597
+ self._leaves += leaves
598
+ treeseg = TreeSegmentWidget(canvas, node, leaves, roof=1,
599
+ color=self._roof_color,
600
+ fill=self._roof_fill,
601
+ width=self._line_width)
602
+
603
+ self._collapsed_trees[key] = treeseg
604
+ self._keys[treeseg] = key
605
+ #self._add_child_widget(treeseg)
606
+ treeseg.hide()
607
+
608
+ # Build trees for children.
609
+ for i in range(len(t)):
610
+ child = t[i]
611
+ self._make_collapsed_trees(canvas, child, key + (i,))
612
+
613
+ def _make_expanded_tree(self, canvas, t, key):
614
+ make_node = self._make_node
615
+ make_leaf = self._make_leaf
616
+
617
+ if isinstance(t, Tree):
618
+ node = make_node(canvas, t.label(), **self._nodeattribs)
619
+ self._nodes.append(node)
620
+ children = t
621
+ subtrees = [self._make_expanded_tree(canvas, children[i], key+(i,))
622
+ for i in range(len(children))]
623
+ treeseg = TreeSegmentWidget(canvas, node, subtrees,
624
+ color=self._line_color,
625
+ width=self._line_width)
626
+ self._expanded_trees[key] = treeseg
627
+ self._keys[treeseg] = key
628
+ return treeseg
629
+ else:
630
+ leaf = make_leaf(canvas, t, **self._leafattribs)
631
+ self._leaves.append(leaf)
632
+ return leaf
633
+
634
+ def __setitem__(self, attr, value):
635
+ if attr[:5] == 'node_':
636
+ for node in self._nodes: node[attr[5:]] = value
637
+ elif attr[:5] == 'leaf_':
638
+ for leaf in self._leaves: leaf[attr[5:]] = value
639
+ elif attr == 'line_color':
640
+ self._line_color = value
641
+ for tseg in list(self._expanded_trees.values()): tseg['color'] = value
642
+ elif attr == 'line_width':
643
+ self._line_width = value
644
+ for tseg in list(self._expanded_trees.values()): tseg['width'] = value
645
+ for tseg in list(self._collapsed_trees.values()): tseg['width'] = value
646
+ elif attr == 'roof_color':
647
+ self._roof_color = value
648
+ for tseg in list(self._collapsed_trees.values()): tseg['color'] = value
649
+ elif attr == 'roof_fill':
650
+ self._roof_fill = value
651
+ for tseg in list(self._collapsed_trees.values()): tseg['fill'] = value
652
+ elif attr == 'shapeable':
653
+ self._shapeable = value
654
+ for tseg in list(self._expanded_trees.values()):
655
+ tseg['draggable'] = value
656
+ for tseg in list(self._collapsed_trees.values()):
657
+ tseg['draggable'] = value
658
+ for leaf in self._leaves: leaf['draggable'] = value
659
+ elif attr == 'xspace':
660
+ self._xspace = value
661
+ for tseg in list(self._expanded_trees.values()):
662
+ tseg['xspace'] = value
663
+ for tseg in list(self._collapsed_trees.values()):
664
+ tseg['xspace'] = value
665
+ self.manage()
666
+ elif attr == 'yspace':
667
+ self._yspace = value
668
+ for tseg in list(self._expanded_trees.values()):
669
+ tseg['yspace'] = value
670
+ for tseg in list(self._collapsed_trees.values()):
671
+ tseg['yspace'] = value
672
+ self.manage()
673
+ elif attr == 'orientation':
674
+ self._orientation = value
675
+ for tseg in list(self._expanded_trees.values()):
676
+ tseg['orientation'] = value
677
+ for tseg in list(self._collapsed_trees.values()):
678
+ tseg['orientation'] = value
679
+ self.manage()
680
+ elif attr == 'ordered':
681
+ self._ordered = value
682
+ for tseg in list(self._expanded_trees.values()):
683
+ tseg['ordered'] = value
684
+ for tseg in list(self._collapsed_trees.values()):
685
+ tseg['ordered'] = value
686
+ else: CanvasWidget.__setitem__(self, attr, value)
687
+
688
+ def __getitem__(self, attr):
689
+ if attr[:5] == 'node_':
690
+ return self._nodeattribs.get(attr[5:], None)
691
+ elif attr[:5] == 'leaf_':
692
+ return self._leafattribs.get(attr[5:], None)
693
+ elif attr[:4] == 'loc_':
694
+ return self._locattribs.get(attr[4:], None)
695
+ elif attr == 'line_color': return self._line_color
696
+ elif attr == 'line_width': return self._line_width
697
+ elif attr == 'roof_color': return self._roof_color
698
+ elif attr == 'roof_fill': return self._roof_fill
699
+ elif attr == 'shapeable': return self._shapeable
700
+ elif attr == 'xspace': return self._xspace
701
+ elif attr == 'yspace': return self._yspace
702
+ elif attr == 'orientation': return self._orientation
703
+ else: return CanvasWidget.__getitem__(self, attr)
704
+
705
+ def _tags(self): return []
706
+
707
+ def _manage(self):
708
+ segs = list(self._expanded_trees.values()) + list(self._collapsed_trees.values())
709
+ for tseg in segs:
710
+ if tseg.hidden():
711
+ tseg.show()
712
+ tseg.manage()
713
+ tseg.hide()
714
+
715
+ def toggle_collapsed(self, treeseg):
716
+ """
717
+ Collapse/expand a tree.
718
+ """
719
+ old_treeseg = treeseg
720
+ if old_treeseg['roof']:
721
+ new_treeseg = self._expanded_trees[self._keys[old_treeseg]]
722
+ else:
723
+ new_treeseg = self._collapsed_trees[self._keys[old_treeseg]]
724
+
725
+ # Replace the old tree with the new tree.
726
+ if old_treeseg.parent() is self:
727
+ self._remove_child_widget(old_treeseg)
728
+ self._add_child_widget(new_treeseg)
729
+ self._treeseg = new_treeseg
730
+ else:
731
+ old_treeseg.parent().replace_child(old_treeseg, new_treeseg)
732
+
733
+ # Move the new tree to where the old tree was. Show it first,
734
+ # so we can find its bounding box.
735
+ new_treeseg.show()
736
+ (newx, newy) = new_treeseg.label().bbox()[:2]
737
+ (oldx, oldy) = old_treeseg.label().bbox()[:2]
738
+ new_treeseg.move(oldx-newx, oldy-newy)
739
+
740
+ # Hide the old tree
741
+ old_treeseg.hide()
742
+
743
+ # We could do parent.manage() here instead, if we wanted.
744
+ new_treeseg.parent().update(new_treeseg)
745
+
746
+ ##//////////////////////////////////////////////////////
747
+ ## draw_trees
748
+ ##//////////////////////////////////////////////////////
749
+
750
+ class TreeView(object):
751
+ def __init__(self, *trees):
752
+ from math import sqrt, ceil
753
+
754
+ self._trees = trees
755
+
756
+ self._top = Tk()
757
+ self._top.title('NLTK')
758
+ self._top.bind('<Control-x>', self.destroy)
759
+ self._top.bind('<Control-q>', self.destroy)
760
+
761
+ cf = self._cframe = CanvasFrame(self._top)
762
+ self._top.bind('<Control-p>', self._cframe.print_to_file)
763
+
764
+ # Size is variable.
765
+ self._size = IntVar(self._top)
766
+ self._size.set(12)
767
+ bold = ('helvetica', -self._size.get(), 'bold')
768
+ helv = ('helvetica', -self._size.get())
769
+
770
+ # Lay the trees out in a square.
771
+ self._width = int(ceil(sqrt(len(trees))))
772
+ self._widgets = []
773
+ for i in range(len(trees)):
774
+ widget = TreeWidget(cf.canvas(), trees[i], node_font=bold,
775
+ leaf_color='#008040', node_color='#004080',
776
+ roof_color='#004040', roof_fill='white',
777
+ line_color='#004040', draggable=1,
778
+ leaf_font=helv)
779
+ widget.bind_click_trees(widget.toggle_collapsed)
780
+ self._widgets.append(widget)
781
+ cf.add_widget(widget, 0, 0)
782
+
783
+ self._layout()
784
+ self._cframe.pack(expand=1, fill='both')
785
+ self._init_menubar()
786
+
787
+ def _layout(self):
788
+ i = x = y = ymax = 0
789
+ width = self._width
790
+ for i in range(len(self._widgets)):
791
+ widget = self._widgets[i]
792
+ (oldx, oldy) = widget.bbox()[:2]
793
+ if i % width == 0:
794
+ y = ymax
795
+ x = 0
796
+ widget.move(x-oldx, y-oldy)
797
+ x = widget.bbox()[2] + 10
798
+ ymax = max(ymax, widget.bbox()[3] + 10)
799
+
800
+ def _init_menubar(self):
801
+ menubar = Menu(self._top)
802
+
803
+ filemenu = Menu(menubar, tearoff=0)
804
+ filemenu.add_command(label='Print to Postscript', underline=0,
805
+ command=self._cframe.print_to_file,
806
+ accelerator='Ctrl-p')
807
+ filemenu.add_command(label='Exit', underline=1,
808
+ command=self.destroy, accelerator='Ctrl-x')
809
+ menubar.add_cascade(label='File', underline=0, menu=filemenu)
810
+
811
+ zoommenu = Menu(menubar, tearoff=0)
812
+ zoommenu.add_radiobutton(label='Tiny', variable=self._size,
813
+ underline=0, value=10, command=self.resize)
814
+ zoommenu.add_radiobutton(label='Small', variable=self._size,
815
+ underline=0, value=12, command=self.resize)
816
+ zoommenu.add_radiobutton(label='Medium', variable=self._size,
817
+ underline=0, value=14, command=self.resize)
818
+ zoommenu.add_radiobutton(label='Large', variable=self._size,
819
+ underline=0, value=28, command=self.resize)
820
+ zoommenu.add_radiobutton(label='Huge', variable=self._size,
821
+ underline=0, value=50, command=self.resize)
822
+ menubar.add_cascade(label='Zoom', underline=0, menu=zoommenu)
823
+
824
+ self._top.config(menu=menubar)
825
+
826
+ def resize(self, *e):
827
+ bold = ('helvetica', -self._size.get(), 'bold')
828
+ helv = ('helvetica', -self._size.get())
829
+ xspace = self._size.get()
830
+ yspace = self._size.get()
831
+ for widget in self._widgets:
832
+ widget['node_font'] = bold
833
+ widget['leaf_font'] = helv
834
+ widget['xspace'] = xspace
835
+ widget['yspace'] = yspace
836
+ if self._size.get() < 20: widget['line_width'] = 1
837
+ elif self._size.get() < 30: widget['line_width'] = 2
838
+ else: widget['line_width'] = 3
839
+ self._layout()
840
+
841
+ def destroy(self, *e):
842
+ if self._top is None: return
843
+ self._top.destroy()
844
+ self._top = None
845
+
846
+ def mainloop(self, *args, **kwargs):
847
+ """
848
+ Enter the Tkinter mainloop. This function must be called if
849
+ this demo is created from a non-interactive program (e.g.
850
+ from a secript); otherwise, the demo will close as soon as
851
+ the script completes.
852
+ """
853
+ if in_idle(): return
854
+ self._top.mainloop(*args, **kwargs)
855
+
856
+ def draw_trees(*trees):
857
+ """
858
+ Open a new window containing a graphical diagram of the given
859
+ trees.
860
+
861
+ :rtype: None
862
+ """
863
+ TreeView(*trees).mainloop()
864
+ return
865
+
866
+ ##//////////////////////////////////////////////////////
867
+ ## Demo Code
868
+ ##//////////////////////////////////////////////////////
869
+
870
+ def demo():
871
+ import random
872
+ def fill(cw):
873
+ cw['fill'] = '#%06d' % random.randint(0,999999)
874
+
875
+ cf = CanvasFrame(width=550, height=450, closeenough=2)
876
+
877
+ t = Tree.fromstring('''
878
+ (S (NP the very big cat)
879
+ (VP (Adv sorta) (V saw) (NP (Det the) (N dog))))''')
880
+
881
+ tc = TreeWidget(cf.canvas(), t, draggable=1,
882
+ node_font=('helvetica', -14, 'bold'),
883
+ leaf_font=('helvetica', -12, 'italic'),
884
+ roof_fill='white', roof_color='black',
885
+ leaf_color='green4', node_color='blue2')
886
+ cf.add_widget(tc,10,10)
887
+
888
+ def boxit(canvas, text):
889
+ big = ('helvetica', -16, 'bold')
890
+ return BoxWidget(canvas, TextWidget(canvas, text,
891
+ font=big), fill='green')
892
+ def ovalit(canvas, text):
893
+ return OvalWidget(canvas, TextWidget(canvas, text),
894
+ fill='cyan')
895
+
896
+ treetok = Tree.fromstring('(S (NP this tree) (VP (V is) (AdjP shapeable)))')
897
+ tc2 = TreeWidget(cf.canvas(), treetok, boxit, ovalit, shapeable=1)
898
+
899
+ def color(node):
900
+ node['color'] = '#%04d00' % random.randint(0,9999)
901
+ def color2(treeseg):
902
+ treeseg.label()['fill'] = '#%06d' % random.randint(0,9999)
903
+ treeseg.label().child()['color'] = 'white'
904
+
905
+ tc.bind_click_trees(tc.toggle_collapsed)
906
+ tc2.bind_click_trees(tc2.toggle_collapsed)
907
+ tc.bind_click_nodes(color, 3)
908
+ tc2.expanded_tree(1).bind_click(color2, 3)
909
+ tc2.expanded_tree().bind_click(color2, 3)
910
+
911
+ paren = ParenWidget(cf.canvas(), tc2)
912
+ cf.add_widget(paren, tc.bbox()[2]+10, 10)
913
+
914
+ tree3 = Tree.fromstring('''
915
+ (S (NP this tree) (AUX was)
916
+ (VP (V built) (PP (P with) (NP (N tree_to_treesegment)))))''')
917
+ tc3 = tree_to_treesegment(cf.canvas(), tree3, tree_color='green4',
918
+ tree_xspace=2, tree_width=2)
919
+ tc3['draggable'] = 1
920
+ cf.add_widget(tc3, 10, tc.bbox()[3]+10)
921
+
922
+ def orientswitch(treewidget):
923
+ if treewidget['orientation'] == 'horizontal':
924
+ treewidget.expanded_tree(1,1).subtrees()[0].set_text('vertical')
925
+ treewidget.collapsed_tree(1,1).subtrees()[0].set_text('vertical')
926
+ treewidget.collapsed_tree(1).subtrees()[1].set_text('vertical')
927
+ treewidget.collapsed_tree().subtrees()[3].set_text('vertical')
928
+ treewidget['orientation'] = 'vertical'
929
+ else:
930
+ treewidget.expanded_tree(1,1).subtrees()[0].set_text('horizontal')
931
+ treewidget.collapsed_tree(1,1).subtrees()[0].set_text('horizontal')
932
+ treewidget.collapsed_tree(1).subtrees()[1].set_text('horizontal')
933
+ treewidget.collapsed_tree().subtrees()[3].set_text('horizontal')
934
+ treewidget['orientation'] = 'horizontal'
935
+
936
+ text = """
937
+ Try clicking, right clicking, and dragging
938
+ different elements of each of the trees.
939
+ The top-left tree is a TreeWidget built from
940
+ a Tree. The top-right is a TreeWidget built
941
+ from a Tree, using non-default widget
942
+ constructors for the nodes & leaves (BoxWidget
943
+ and OvalWidget). The bottom-left tree is
944
+ built from tree_to_treesegment."""
945
+ twidget = TextWidget(cf.canvas(), text.strip())
946
+ textbox = BoxWidget(cf.canvas(), twidget, fill='white', draggable=1)
947
+ cf.add_widget(textbox, tc3.bbox()[2]+10, tc2.bbox()[3]+10)
948
+
949
+ tree4 = Tree.fromstring('(S (NP this tree) (VP (V is) (Adj horizontal)))')
950
+ tc4 = TreeWidget(cf.canvas(), tree4, draggable=1,
951
+ line_color='brown2', roof_color='brown2',
952
+ node_font=('helvetica', -12, 'bold'),
953
+ node_color='brown4', orientation='horizontal')
954
+ tc4.manage()
955
+ cf.add_widget(tc4, tc3.bbox()[2]+10, textbox.bbox()[3]+10)
956
+ tc4.bind_click(orientswitch)
957
+ tc4.bind_click_trees(tc4.toggle_collapsed, 3)
958
+
959
+ # Run mainloop
960
+ cf.mainloop()
961
+
962
+ if __name__ == '__main__':
963
+ demo()