[英]How to print tree table visualization in PDF use Cairo and Python?
Following the question: 跟随问题:
Tree plotting in Python Python中的树图
I want to visualize the tree table (hierarchical structure) in PDF using Cairo and Python. 我想使用Cairo和Python可视化PDF中的树表(分层结构)。
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. 如果我可以在循环中获取树叶的级别编号,则将矩形高度设置为“(此级别的叶子)* textH”,绘制表格。
I have added some functions (get_leaf_nodes) to get all the leaf and computing the height of current grid. 我添加了一些函数(get_leaf_nodes)以获取所有叶子并计算当前网格的高度。
reference this question from Alvaro Fuentes 从Alvaro Fuentes 引用此问题
The grid height is right now.I have to say that Stack Overflow is great.Always give me what my want. 网格高度现在是正确的,我不得不说Stack Overflow很棒,总能给我我想要的东西。
And result is : 结果是:
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.leafs = []
self.nodes = []
def get_leaf_nodes(self, position):
"""get all leafs"""
self.leafs = []
self._collect_leaf_nodes(position)
return self.leafs
def _collect_leaf_nodes(self, position):
queue = self[position].fpointer
if queue == []:
self.leafs.append(self[position])
else:
for n in queue:
self._collect_leaf_nodes(n)
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 - 0.8 * self.textH, w, h)
self._context.stroke()
def show(self, position, level=_ROOT):
queue = self[position].fpointer
# get all the children
h = self.textH * len(self.get_leaf_nodes(position))
if level == _ROOT:
s1 = "{0} [{1}]".format(self[position].name,
self[position].identifier)
self.ShowRectText(self._colx, self._coly, self.textW, h, s1)
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)
if queue==[]:
self._coly = self._coly + self.textH
self._colx = self._colx - self.textW * level
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
# http://www.quesucede.com/page/show/id/python-3-tree-implementation
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")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.