如何使用 Cairo 和 Python 在 PDF 中打印树 table 可视化?
How to print tree table visualization in PDF use Cairo and Python?
追问:
Tree plotting in Python
我想使用 Cairo 和 Python 在 PDF 中可视化树 table(层次结构)。
我修改了代码如下:
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")
它给了我这个:
但我想要:
如果我能在循环中得到树叶的层数,我设置矩形高度=“(这个层的叶子)*textH”,绘制table。
我添加了一些函数(get_leaf_nodes)来获取所有叶子并计算当前网格的高度。
reference this question 来自阿尔瓦罗·富恩特斯
网格高度是对的now.I不得不说Stack Overflow是great.Always给我想要的
结果是:
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")
追问:
Tree plotting in Python
我想使用 Cairo 和 Python 在 PDF 中可视化树 table(层次结构)。
我修改了代码如下:
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")
它给了我这个:
但我想要:
如果我能在循环中得到树叶的层数,我设置矩形高度=“(这个层的叶子)*textH”,绘制table。
我添加了一些函数(get_leaf_nodes)来获取所有叶子并计算当前网格的高度。
reference this question 来自阿尔瓦罗·富恩特斯
网格高度是对的now.I不得不说Stack Overflow是great.Always给我想要的
结果是:
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")