在python中可视化嵌套函数调用

2024-04-29 00:50:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要一种在python中可视化嵌套函数调用的方法,最好是在树状结构中。因此,如果我有一个包含f(g(x,h(y)))的字符串,我想创建一个树,使这些级别更具可读性。例如:

     f()
      |
     g()
     / \
    x  h()
        |
        y

或者,当然,更好的是,像sklearn.tree.plot_tree创建的树图

这似乎是一个很早以前就有人解决过的问题,但到目前为止,我一直无法找到它。仅供参考,这是用于可视化遗传编程输出的,这些输出往往具有非常复杂的字符串

谢谢

更新: toytree和toyplot离得很近,但不是很近: enter image description here

这是通过以下方式生成的:

 import toytree, toyplot
 mystyle = {"layout": 'down','node_labels':True}
 s = '((x,(y)));'
 toytree.tree(s).draw(**mystyle);

很接近,但节点标签不是字符串

更新2: 我找到了另一个可能的解决方案,它可以让我更接近文本形式: https://rosettacode.org/wiki/Visualize_a_tree#Python

tree2 = Node('f')([ 
            Node('g')([
                Node('x')([]),
                Node('h')([
                    Node('y')([])
                ])
            ])
        ])
print('\n\n'.join([drawTree2(True)(False)(tree2)]))

其结果如下:

enter image description here

没错,但我必须手动将字符串转换为drawTree2函数所需的节点表示法


Tags: 方法字符串nodetruetree节点可视化结构
1条回答
网友
1楼 · 发布于 2024-04-29 00:50:13

这里有一个使用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))

输出:

f()
 +  g()
     +  x
     +  h()
         +  y

编辑

通过一些调整,您可以构建一个适合在您喜爱的图形库(下面的IGRAPHE示例)中打印的边列表

#!/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')

Output plot

相关问题 更多 >