ctree_draw.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #! /usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. """
  4. This module contains classes to draw constituency tree.
  5. Version 0.1 (12-Feb-2015)
  6. ConstTreeDrawer, CTDCairoContext, DrawConstTree and DrawConstNode are added.
  7. """
  8. import cairo
  9. import parse
  10. class ConstTreeDrawer():
  11. '''
  12. Class for drawing constituency tree
  13. '''
  14. def __init__(self, pOutFilename, pFontSize = 10):
  15. '''
  16. Constructor
  17. '''
  18. self.tree = None
  19. # drawing attributes
  20. self.width = 0
  21. self.height = 0
  22. self.branchHeight = 50
  23. # number of spaces between terminals
  24. self.terminalSpaceCount = 4
  25. self.margins = 10
  26. self.surface = cairo.PDFSurface(pOutFilename, self.width, self.height)
  27. self.context = CTDCairoContext(self.surface)
  28. self.context.setFontSize(pFontSize)
  29. self.context.setRGB(0, 0, 0)
  30. self.context.setLineWidth(.25)
  31. def _createRoot(self):
  32. '''
  33. Creates and returns the root node
  34. '''
  35. return ConstNodeDraw()
  36. def draw(self, pCTree):
  37. '''
  38. Draws a given constituency tree
  39. The tree can be provided as a string in bracketing format or as
  40. parse.ConstTree type. The string bracketing format can contain
  41. color information or can be plain. The ConstTree object can be of
  42. either ConstTree or DrawConstTree type.
  43. '''
  44. # preparing the tree
  45. if isinstance(pCTree, parse.ConstTree):
  46. self.tree = DrawConstTree()
  47. self.tree.loadPTBTree(pCTree.getPTBFormat(), pflgExpandTerminal = True)
  48. elif isinstance(pCTree, basestring):
  49. self.tree = DrawConstTree()
  50. self.tree.loadPTBTree(pCTree, pflgExpandTerminal = True)
  51. else:
  52. raise Exception("Unknown constituency tree format!")
  53. # presetting of drawing attributes of the tree
  54. self.tree.presetDrawAttrs(self.context)
  55. # moving the position to the top left corner of the draw area
  56. self.context.move_to(self.margins, self.height + self.margins)
  57. # setting the surface size
  58. self.setSurfaceSize()
  59. # actual drawing
  60. #self.tree.draw(pCanvas = self.context, pBranchHeight = self.branchHeight, pTerminalSpaceCount = self.terminalSpaceCount)
  61. self.context.show_text(' '.join(self.tree.getTerminals()))
  62. # finishing the draw by applying it on the surface
  63. self.surface.finish()
  64. def setSurfaceSize(self):
  65. '''
  66. Sets the size of the drawing surface
  67. '''
  68. # caculating the tree area
  69. self.width = self.tree.getDrawWidth() + (2 * self.margins)
  70. self.height = self.tree.getDrawHeight + (2 * self.margins)
  71. self.surface.set_size(self.width, self.height)
  72. class CTDCairoContext(cairo.Context):
  73. '''
  74. A customized Cairo Context class for drawing constituency tree
  75. '''
  76. def __init__(self, pCairoSurface):
  77. '''
  78. Constructor
  79. '''
  80. cairo.Context.__init__(self, pCairoSurface)
  81. self.fontSize = None
  82. def setFontSize(self, pFontSize):
  83. '''
  84. Sets the font size of the context
  85. '''
  86. self.set_font_size(pFontSize)
  87. self.fontSize = pFontSize
  88. def getFontSize(self):
  89. '''
  90. Returns the value of the font size
  91. '''
  92. return self.fontSize
  93. def setRGB(self, pR, pG, pB):
  94. '''
  95. Sets the RGB color of the context
  96. '''
  97. self.set_source_rgb(pR, pG, pB)
  98. self.RGB = (pR, pG, pB)
  99. def getRGB(self):
  100. '''
  101. Returns the value of the RGB color of the context
  102. '''
  103. return self.RGB
  104. def setLineWidth(self, pLineWidth):
  105. '''
  106. Sets the line width of the context
  107. '''
  108. self.set_line_width(pLineWidth)
  109. self.lineWidth = pLineWidth
  110. def getLineWidth(self):
  111. '''
  112. Returns the value of the line width of the context
  113. '''
  114. return self.lineWidth
  115. class DrawConstTree(parse.ConstTree):
  116. '''
  117. Class for constituency tree with drawing features
  118. '''
  119. def __init__(self):
  120. '''
  121. Constructor
  122. '''
  123. parse.ConstTree.__init__(self)
  124. self.drawWidth = 0
  125. self.drawHeight = 0
  126. def _createRoot(self):
  127. '''
  128. Creates and returns the root node
  129. '''
  130. return DrawConstNode()
  131. def presetDrawAttrs(self, pCTDContext):
  132. '''
  133. Presets the drawing attributes of the tree and its nodes
  134. '''
  135. self.root.presetDrawAttrs(pCTDContext)
  136. self.drawWidth
  137. self.drawHeight
  138. def draw(self, pCanvas, pBranchHeight, pTerminalSpaceCount):
  139. '''
  140. Draws the tree on the given canvas with the provided drawing
  141. attributes
  142. '''
  143. self.root.draw(pCanvas = pCanvas, pBranchHeight = pBranchHeight, pTerminalSpaceCount = pTerminalSpaceCount, pLevel = 0)
  144. class DrawConstNode(parse.ConstNode):
  145. '''
  146. Class for constituency tree node with drawing features
  147. '''
  148. def __init__(self):
  149. '''
  150. Constructor
  151. '''
  152. parse.ConstNode.__init__(self)
  153. self.textWidth = 0
  154. self.textHeight = 0
  155. self.drawWidth = 0
  156. self.drawHeight = 0
  157. def _getNewNode(self):
  158. '''
  159. Creates and returns a node
  160. '''
  161. return DrawConstNode()
  162. def presetDrawAttrs(self, pCTDContext):
  163. '''
  164. Presets the drawing attributes of the nodes and the subtree itself
  165. '''
  166. if self.isTerminal():
  167. ######
  168. vTextExtent = pCTDContext.text_extents(self.surface)
  169. self.drawWidth = vTokensExtent[2]
  170. self.drawHeight = vTokensExtent[3]
  171. ######
  172. return self.drawWidth, self.drawHeight
  173. else:
  174. vTextExtent = pCTDContext.text_extents(self.getLabel())
  175. self.textWidth = vTokensExtent[2]
  176. self.textHeight = vTokensExtent[3]
  177. vChildrenDrawWidth = 0
  178. vChildrenDrawHeight = 0
  179. for vChild in self.getChildren():
  180. vChildDrawWidth, vChildDrawHeight = vChild.presetDrawAttrs(pCTDContext)
  181. vChildrenDrawWidth += vChildDrawWidth
  182. vChildrenDrawHeight += vChildDrawHeight
  183. if self.textWidth >
  184. def draw(self, pCanvas, pBranchHeight, pTerminalSpaceCount, pLevel):
  185. '''
  186. Draws the subtree rooted at the node on the given canvas with the
  187. provided drawing attributes
  188. pLevel identifies the level or depth of the node in the tree. The
  189. root node level is 0.
  190. '''
  191. # depth first drawing: children first
  192. for vChild in self.getChildren():
  193. vChild.draw(pCanvas = pCanvas, pBranchHeight = pBranchHeight, pTerminalSpaceCount = pTerminalSpaceCount, pLevel = pLevel + 1)
  194. # setting text position
  195. vText = (' ' * pTerminalSpaceCount).join(self.getTerminals())
  196. pCanvas.show_text(vText)
  197. print vText
  198. pCanvas.rel_move_to(0, pBranchHeight * pLevel)
  199. # writing the text
  200. if self.isTerminal():
  201. pCanvas.show_text(vText)
  202. else:
  203. pCanvas.show_text(self.getSynTag())