在python中可视化嵌套函数调用
我需要一种在python中可视化嵌套函数调用的方法,最好是在树状结构中。因此,如果我有一个字符串包含在python中可视化嵌套函数调用,python,tree,genetic-programming,deap,Python,Tree,Genetic Programming,Deap,我需要一种在python中可视化嵌套函数调用的方法,最好是在树状结构中。因此,如果我有一个字符串包含f(g(x,h(y)),我想创建一个树,使这些级别更具可读性。例如: f() | g() / \ x h() | y 或者,当然,更好的是,像sklearn.tree.plot\u tree创建的那样的树形图 这似乎是一个问题,有人可能早就解决了,但它迄今为止一直抵制我的努力找到它。仅供参考,这是用于可视化遗传编
f(g(x,h(y))
,我想创建一个树,使这些级别更具可读性。例如:
f()
|
g()
/ \
x h()
|
y
或者,当然,更好的是,像sklearn.tree.plot\u tree
创建的那样的树形图
这似乎是一个问题,有人可能早就解决了,但它迄今为止一直抵制我的努力找到它。仅供参考,这是用于可视化遗传编程输出的,这些输出往往具有非常复杂的字符串
谢谢
更新:
toytree和toyplot离得很近,但不是很近:
这是通过以下方式生成的:
import toytree, toyplot
mystyle = {"layout": 'down','node_labels':True}
s = '((x,(y)));'
toytree.tree(s).draw(**mystyle);
很接近,但节点标签不是字符串
更新2:
我找到了另一个可能的解决方案,它可以让我更接近文本形式:
其结果如下:
没错,但我必须手动将字符串转换为
drawTree2
函数所需的节点符号 这里有一个使用pyparsing和ascitree的解决方案。这可以用于解析任何内容,并生成绘图所需的任何数据结构。在这种情况下,代码会生成适合输入到asciitree的嵌套字典
#!/usr/bin/env python3
from collections import OrderedDict
from asciitree import LeftAligned
from pyparsing import Suppress, Word, alphas, Forward, delimitedList, ParseException, Optional
def grammar():
lpar = Suppress('(')
rpar = Suppress(')')
identifier = Word(alphas).setParseAction(lambda t: (t[0], {}))
function_name = Word(alphas)
expr = Forward()
function_arg = delimitedList(expr)
function = (function_name + lpar + Optional(function_arg) + rpar).setParseAction(lambda t: (t[0] + '()', OrderedDict(t[1:])))
expr << (function | identifier)
return function
def parse(expr):
g = grammar()
try:
parsed = g.parseString(expr, parseAll=True)
except ParseException as e:
print()
print(expr)
print(' ' * e.loc + '^')
print(e.msg)
raise
return dict([parsed[0]])
if __name__ == '__main__':
expr = 'f(g(x,h(y)))'
tree = parse(expr)
print(LeftAligned()(tree))
编辑
通过一些调整,您可以构建一个适合在您喜爱的图形库(下面的IGRAPHE示例)中打印的边列表
#/usr/bin/env蟒蛇3
导入图
从pyparsing导入抑制、Word、alphas、Forward、delimitedList、ParseException、可选
类GraphBuilder(对象):
定义初始化(自):
self.labels={}
self.edges=[]
def添加_边(自身、源、目标):
对于目标中的目标:
自我添加边缘(源、目标)
返回源
def添加_边缘(自身、源、目标):
x=self.labels.setdefault(源,len(self.labels))
y=self.labels.setdefault(目标,len(self.labels))
self.edges.append((x,y))
def生成(自):
g=igraph.Graph()
g、 添加_顶点(len(self.labels))
g、 vs['label']=sorted(self.labels.keys(),key=lambda l:self.labels[l])
g、 添加_边(自边)
返回g
定义语法(gb):
lpar=Suppress('(')
rpar=Suppress('))
标识符=单词(字母)
function_name=Word(alphas).setParseAction(lambda t:t[0]+'()')
expr=Forward()
函数参数=分隔符列表(expr)
function=(function_name+lpar+可选(function_arg)+rpar).setParseAction(lambda t:gb.add_edges(t[0],t[1:]))
expr这比我找到的解决方案要好-谢谢!是否有一个库或函数可以使用plotly或matplotlib将asciitree输出可视化为图像?@BurntUmber我知道没有直接的方法,但请参阅我的编辑以了解如何实现这一点。这真是太棒了,非常感谢!最后一个细节——当它将浮点数视为函数的参数时,如何让它传递数字?我用整数(字符0-9)实现了这一点,但它不喜欢浮点数。你可以做一些类似于numeric=combined(Word(nums)+可选('.+Word(nums))|'.+Word(nums))
的事情,然后将numeric
添加到expr
术语中。
#!/usr/bin/env python3
from collections import OrderedDict
from asciitree import LeftAligned
from pyparsing import Suppress, Word, alphas, Forward, delimitedList, ParseException, Optional
def grammar():
lpar = Suppress('(')
rpar = Suppress(')')
identifier = Word(alphas).setParseAction(lambda t: (t[0], {}))
function_name = Word(alphas)
expr = Forward()
function_arg = delimitedList(expr)
function = (function_name + lpar + Optional(function_arg) + rpar).setParseAction(lambda t: (t[0] + '()', OrderedDict(t[1:])))
expr << (function | identifier)
return function
def parse(expr):
g = grammar()
try:
parsed = g.parseString(expr, parseAll=True)
except ParseException as e:
print()
print(expr)
print(' ' * e.loc + '^')
print(e.msg)
raise
return dict([parsed[0]])
if __name__ == '__main__':
expr = 'f(g(x,h(y)))'
tree = parse(expr)
print(LeftAligned()(tree))
f()
+-- g()
+-- x
+-- h()
+-- y
#!/usr/bin/env python3
import igraph
from pyparsing import Suppress, Word, alphas, Forward, delimitedList, ParseException, Optional
class GraphBuilder(object):
def __init__(self):
self.labels = {}
self.edges = []
def add_edges(self, source, targets):
for target in targets:
self.add_edge(source, target)
return source
def add_edge(self, source, target):
x = self.labels.setdefault(source, len(self.labels))
y = self.labels.setdefault(target, len(self.labels))
self.edges.append((x, y))
def build(self):
g = igraph.Graph()
g.add_vertices(len(self.labels))
g.vs['label'] = sorted(self.labels.keys(), key=lambda l: self.labels[l])
g.add_edges(self.edges)
return g
def grammar(gb):
lpar = Suppress('(')
rpar = Suppress(')')
identifier = Word(alphas)
function_name = Word(alphas).setParseAction(lambda t: t[0] + '()')
expr = Forward()
function_arg = delimitedList(expr)
function = (function_name + lpar + Optional(function_arg) + rpar).setParseAction(lambda t: gb.add_edges(t[0], t[1:]))
expr << (function | identifier)
return function
def parse(expr, gb):
g = grammar(gb)
g.parseString(expr, parseAll=True)
if __name__ == '__main__':
expr = 'f(g(x,h(y)))'
gb = GraphBuilder()
parse(expr, gb)
g = gb.build()
layout = g.layout('tree', root=len(gb.labels)-1)
igraph.plot(g, layout=layout, vertex_size=30, vertex_color='white')