Following the question:
I want to visualize the tree table (hierarchical structure) in PDF using Cairo and Python.
I have modified the code as follows:
import uuid
import cairo
def sanitize_id(id):
return id.strip().replace(" ", "")
(_ADD, _DELETE, _INSERT) = range(3)
(_ROOT, _DEPTH, _WIDTH) = range(3)
class Node:
def __init__(self, name, identifier=None, expanded=True):
self.__identifier = (str(uuid.uuid1()) if identifier is None else
sanitize_id(str(identifier)))
self.name = name
self.expanded = expanded
self.__bpointer = None
self.__fpointer = []
@property
def identifier(self):
return self.__identifier
@property
def bpointer(self):
return self.__bpointer
@bpointer.setter
def bpointer(self, value):
if value is not None:
self.__bpointer = sanitize_id(value)
@property
def fpointer(self):
return self.__fpointer
def update_fpointer(self, identifier, mode=_ADD):
if mode is _ADD:
self.__fpointer.append(sanitize_id(identifier))
elif mode is _DELETE:
self.__fpointer.remove(sanitize_id(identifier))
elif mode is _INSERT:
self.__fpointer = [sanitize_id(identifier)]
class Tree(object):
def __init__(self, cr):
self._context = cr
self._colx = 50.0
self._coly = 50.0
self.textW = 128.0
self.textH = 20.0
self.nodes = []
def get_index(self, position):
for index, node in enumerate(self.nodes):
if node.identifier == position:
break
return index
def create_node(self, name, identifier=None, parent=None):
node = Node(name, identifier)
self.nodes.append(node)
self.__update_fpointer(parent, node.identifier, _ADD)
node.bpointer = parent
return node
def ShowText(self, x, y, st):
self._context.move_to(x, y)
self._context.show_text(st)
self._context.stroke()
def ShowRectText(self, x, y, w, h, st):
self.ShowText(x, y, st)
self._context.rectangle(x - 5, y - self.textH, w, h)
self._context.stroke()
def show(self, position, level=_ROOT):
queue = self[position].fpointer
h = self.textH*self.__len__()
if level == _ROOT:
s1 = "{0} [{1}]".format(self[position].name,
self[position].identifier)
self.ShowRectText(self._colx, self._coly, self.textW, h, s1)
self._coly = self._coly + self.textH
else:
s2 = "{0} [{1}]".format(self[position].name, self[position].identifier)
self._colx = self._colx + self.textW * level
self.ShowRectText(self._colx, self._coly, self.textW, h, s2)
self._coly = self._coly + self.textH
self._colx = self._colx - self.textW * level
self._context.stroke()
if self[position].expanded:
level += 1
for element in queue:
self.show(element, level) # recursive call
def expand_tree(self, position, mode=_DEPTH):
# Python generator. Loosly based on an algorithm from 'Essential LISP' by
# John R. Anderson, Albert T. Corbett, and Brian J. Reiser, page 239-241
yield position
queue = self[position].fpointer
while queue:
yield queue[0]
expansion = self[queue[0]].fpointer
if mode is _DEPTH:
queue = expansion + queue[1:] # depth-first
elif mode is _WIDTH:
queue = queue[1:] + expansion # width-first
def is_branch(self, position):
return self[position].fpointer
def __update_fpointer(self, position, identifier, mode):
if position is None:
return
else:
self[position].update_fpointer(identifier, mode)
def __update_bpointer(self, position, identifier):
self[position].bpointer = identifier
def __getitem__(self, key):
return self.nodes[self.get_index(key)]
def __setitem__(self, key, item):
self.nodes[self.get_index(key)] = item
def __len__(self):
return len(self.nodes)
def __contains__(self, identifier):
return [node.identifier for node in self.nodes
if node.identifier is identifier]
if __name__ == "__main__":
surface = cairo.PDFSurface("cairo_tree_table_show.pdf", 1000, 800)
context = cairo.Context(surface)
tree = Tree(context)
tree.create_node("Harry", "harry") # root node
tree.create_node("Jane", "jane", parent="harry")
tree.create_node("Bill", "bill", parent="harry")
tree.create_node("Joe", "joe", parent="jane")
tree.create_node("Diane", "diane", parent="jane")
tree.create_node("George", "george", parent="diane")
tree.create_node("Mary", "mary", parent="diane")
tree.create_node("Jill", "jill", parent="george")
tree.create_node("Carol", "carol", parent="jill")
tree.create_node("Grace", "grace", parent="bill")
tree.create_node("Mark", "mark", parent="jane")
tree.show("harry")
It gives me this:
but I want as:
If I can get level number of the tree leaf in the loop,I set the rectangle height = "(this level's leaf)*textH" ,draw the table.