我有以下形式的分层树:
(((A,B),(C,D)),E)
有没有一种简单的方法来重新安排/绘制这个(例如Python)?
答案 0 :(得分:2)
运行此系列替换:
(
- &gt; <ul><li>
)
- &gt; </ul></li>
,
- &gt; </li><li>
然后在浏览器中打开它
或者如果它是python对象,请使用pprint:
>>> x = ((("A","B"),("C","D")),"E")
>>> from pprint import pprint
>>> pprint(x, width=1)
((('A',
'B'),
('C',
'D')),
'E')
或自定义python解决方案:
from itertools import izip
def first_then(first, then):
yield first
while True:
yield then
def tree_lines(x):
if type(x) is tuple:
if len(x) == 1:
# singular tuple
for p, l in izip(first_then('--', ' '), tree_lines(x[0])):
yield p + l
else:
first, rest, last = x[0], x[1:-1], x[-1]
# first entry
for p, l in izip(first_then('T-', '| '), tree_lines(first)):
yield p + l
# middle entries
for y in rest:
for p, l in izip(first_then('>-', '| '), tree_lines(y)):
yield p + l
# last entries
for p, l in izip(first_then('L-', ' '), tree_lines(last)):
yield p + l
else:
yield str(x)
x = ((('A','B'),('C','D')),'E')
for l in tree_lines(x):
print(l)
答案 1 :(得分:1)
前段时间我写了一些用于制作树木文字表示的东西。它可能适合这里。
class Node:
def __init__(self, value):
self.value = value
self.children = []
pipe = chr(179)
t = chr(195)
l = chr(192)
backwards_r = chr(191)
def printable(node, seq_is_last_child = []):
"""returns a string representation of the given node"""
ret = ""
if seq_is_last_child:
for b in seq_is_last_child[:-1]:
if b:
ret = ret + " "
else:
ret = ret + pipe + " "
if seq_is_last_child[-1]:
ret = ret + l + " "
else:
ret = ret + t + " "
ret = ret + node.value
for idx, c in enumerate(node.children):
ret = ret + "\n" + printable(c, seq_is_last_child + [idx == len(node.children)-1])
return ret
def make_node(t):
"""creates a Node system from a nested tuple"""
ret = Node(backwards_r)
for child in t:
if isinstance(child, str):
ret.children.append(Node(child))
else:
ret.children.append(make_node(child))
return ret
x = ((('A','B'),('C','D')),'E')
print printable(make_node(x))
结果:
┐
├ ┐
│ ├ ┐
│ │ ├ A
│ │ └ B
│ └ ┐
│ ├ C
│ └ D
└ E
编辑:Unicode版本:
class Node:
def __init__(self, value):
self.value = value
self.children = []
def printable(node, seq_is_last_child = []):
"""returns a string representation of the given node"""
ret = ""
if seq_is_last_child:
for b in seq_is_last_child[:-1]:
if b:
ret = ret + " "
else:
ret = ret + "│ "
if seq_is_last_child[-1]:
ret = ret + "└ "
else:
ret = ret + "├ "
ret = ret + node.value
for idx, c in enumerate(node.children):
ret = ret + "\n" + printable(c, seq_is_last_child + [idx == len(node.children)-1])
return ret
def make_node(t):
"""creates a Node system from a nested tuple"""
ret = Node("┐")
for child in t:
if isinstance(child, str):
ret.children.append(Node(child))
else:
ret.children.append(make_node(child))
return ret
x = ((('A','B'),('C','D')),'E')
print printable(make_node(x))
答案 2 :(得分:1)
您可以使用迭代函数找到每个点的depth
和height
:
def locate(xs, depth, cnt):
from functools import partial
if isinstance(xs, str):
return dict(depth=depth, height=- next(cnt), inner=None, txt=xs)
else:
fn = partial(locate, depth=depth+1, cnt=cnt)
loc = list(map(fn, xs))
height = np.mean([x['height'] for x in loc])
return dict(depth=depth, height=height, inner=loc, txt=None)
上面的函数返回一个字典,我们需要另一个遍历通过这个字典并绘制每个节点的函数:
def walk(loc, ax):
col, lw = 'DarkBlue', 2
x, y, inner, txt = map(loc.get, ['depth', 'height', 'inner', 'txt'])
if not inner:
ax.text(x, y, ' ' + txt, ha='left', va='center', size='large')
return y
else:
ys =[walk(t, ax) for t in inner]
for y1 in ys:
ax.plot([x, x+1], [y1, y1], color=col, linewidth=lw)
ax.plot([x, x], [min(ys), max(ys)], color=col, linewidth=lw)
return y
通过传递location
迭代器在顶层调用count
函数,并返回一个字典,其中包含绘制每个级别所需的所有信息:
from itertools import count
xs = ((('A','B'),('C','D')),'E',)
loc = locate(xs, 0, count())
字典和轴一起传递给walk
函数:
fig = plt.figure(figsize=(2, 3))
ax = fig.add_axes([.05, .05, .9, .9])
walk(loc, ax)
plt.axis('off')
xl, yl = ax.get_xlim(), ax.get_ylim()
ax.set_xlim(xl[0] - .05, xl[1] + .05)
ax.set_ylim(yl[0] - .05, yl[1] + .05)
结果将是:
另一个例子:
xs = ((('A','B','C','D'),('E'),('F1','F2'),'G'),(('H1','H2'),('I','J','K'),'L'))
答案 3 :(得分:1)
使用scipy&#39; cluster.hierarchy.dendrogram:
import re
import numpy as np
import matplotlib.pyplot as plt
import scipy.cluster.hierarchy as hier
import scipy.spatial.distance as dist
import itertools as IT
def parse_nested(text, left=r'[(]', right=r'[)]', sep=r','):
""" http://stackoverflow.com/a/17141899/190597 (falsetru) """
pat = r'({}|{}|{})'.format(left, right, sep)
tokens = re.split(pat, text)
stack = [[]]
for x in tokens:
if not x: continue
if re.match(sep, x): continue
if re.match(left, x):
stack[-1].append([])
stack.append(stack[-1][-1])
elif re.match(right, x):
stack.pop()
if not stack:
raise ValueError('error: opening bracket is missing')
else:
stack[-1].append(x)
if len(stack) > 1:
print(stack)
raise ValueError('error: closing bracket is missing')
return stack.pop()
def place_points(datalist, x=IT.count(), y=1):
retval = []
for item in datalist:
if isinstance(item, list):
next(x)
retval.extend(place_points(item, x=x, y=y*2.5))
else:
retval.append([item, (next(x), y)])
return retval
# data = '(((A,B,G),(C,D,F)),(E,(H,I,J,(K,L,M,N))))'
data = '((A,B),(C,D),E)'
labels, points = zip(*place_points(parse_nested(data)))
d = dist.pdist(points)
linkage_matrix = hier.linkage(d)
P = hier.dendrogram(linkage_matrix, labels=labels)
plt.show()