用于从嵌套的 Python 对象 (dicts) 创建树形图的 Python 库

Posted

技术标签:

【中文标题】用于从嵌套的 Python 对象 (dicts) 创建树形图的 Python 库【英文标题】:Python library for creating tree graphs out of nested Python objects (dicts) 【发布时间】:2013-01-25 17:18:59 【问题描述】:

有没有人知道任何 Python 库可以让你简单快速地为它提供一个嵌套到任意级别的对象,例如一个字典树,就像你在 this gist 中找到的那样,它可以吐出出一个可行的树图文件?

在这里,简单是关键,因为我必须能够与没有技术头脑的人一起工作。

我所说的“图树”是指以下内容,我可以为它提供一个嵌套的值字典,然后它会创建树结构:

(来源:rubyforge.org)

【问题讨论】:

见ETE package。 【参考方案1】:

我不确定这是否是您的想法,但这是您首先想到的。

blockdiag 主要用作类似于Graphviz 的独立文件处理器(存在Python 接口)。它接受一个文本文件作为输入,语法非常简单,并生成图像作为输出。

您应该能够编写一个简单的 shim 来输出您的递归 dict 结构,该结构已格式化为独立 blockdiag 脚本的输入,或者导入 blockdiag 包的必要内部结构并直接驱动输出。

如果这听起来很有希望,我会看看是否可以编写一些示例代码。

编辑示例代码:

def print_blockdiag(tree, parent=None):
    if not parent: print('blockdiag  orientation = portrait')
    for key in tree:
        if parent: print('    -> ;'.format(parent, key))
        print_blockdiag(tree[key], key)
    if not parent: print('')

这将输出一个blockdiag可以读取的文件。

【讨论】:

【参考方案2】:

所以我在这个答案中为我的代码 sn-p 推荐和使用的库 不是 python 库,但它是一个 python 友好的库,我的意思是使用这个库的代码可以插入到 python 模块中来处理数据,这个 foreign 代码将连接到两端现存的 python 代码,即输入和输出,我怀疑,虽然我当然不知道,这就是“python 库”标准的真正含义。因此,如果您正在编写 Web 应用程序,则此代码将是客户端的。换句话说,这个库不是python,但它可以与python一起使用。

    它的输入是(几乎)原始的 python dicts,更具体地说,json.load(a_python_dict) 返回一个 json 数组或对象,这种格式javascript库当然可以识别;和

    输出格式是 html 或 SVG,而不是某些对象 特定语言格式

您可以使用d3.js。它有一个class 专门用于渲染树:

var tree = d3.layout.tree().size([h, w]);

d3 源的 example 文件夹 中还有几个树的示例(工作代码),您可以从我提供的链接中克隆/下载它们以上。

因为d3是一个javascript库,它的原生数据格式是JSON

基本结构是一个嵌套字典,每个字典代表一个具有两个值的单个节点,节点的名称及其子节点(存储在一个数组中),键为 names儿童

"name": "a_root_node", "children": ["B", "C"]

当然,在 python 字典和 JSON 之间转换也很简单:

>>> d = "name": 'A', "children": ['B', 'C']
>>> import json as JSON
>>> dj = JSON.dumps(d)
>>> dj
    '"name": "A", "children": ["B", "C"]'

这是一个较大的树(十几个节点)的python dictionary 表示,我如上所述将其转换为 json,然后在 d3 中呈现为所示的树在下图中:

tree = 'name': 'root', 'children': ['name': 'node 2', 'children': 
       ['name': 'node 4', 'children': ['name': 'node 10', 'size': 7500, 
       'name': 'node 11', 'size': 12000], 'name': 'node 5', 'children': 
       ['name': 'node 12', 'children': ['name': 'node 16', 'size': 10000, 
       'name': 'node 17', 'size': 12000], 'name': 'node 13', 'size': 5000]], 
       'name': 'node 3', 'children': ['name': 'node 6', 'children': 
       ['name': 'node 14', 'size': 8000, 'name': 'node 15', 'size': 9000], 
       'name': 'node 7', 'children': ['name': 'node 8', 'size': 10000, 
       'name': 'node 9', 'size': 12000]]]

注意:d3在浏览器中渲染;上图只是我的浏览器窗口的屏幕截图。

【讨论】:

-1:D3 非常棒,但它是一个 Javascript 工具,而不是 Python。如果您正在编写 Python 代码,它并没有真正的帮助。 喜欢这个答案。最后,我有一种简洁的方式来显示 python 脚本的输出!【参考方案3】:

D3.js 是一个主要用于可视化的库...

据我所知,它没有提供用于遍历图形和对其进行数学运算的便捷工具。 但它们在 Python networkX 包中:

import networkx as nx

graph_data = 
    'id': 'root',
    'children': [
        
            'id': 'A',
            'children': [
                
                    'id': 'B', 'children': ['id': 'B1', 'id': 'B2']
                ,
                
                    'id': 'C'
                
            ]
        
    ]


G = nx.readwrite.json_graph.tree_graph(graph_data)

print('EDGES: ', G.edges())
# EDGES: [('root', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B1'), ('B', 'B2')]
print('NODES: ', G.nodes())
# NODES: ['root', 'A', 'B', 'B1', 'B2', 'C']

这是一个从结构创建相同 D3.js 的示例(带有 idchildren 字段)。

图形也可以通过递归迭代创建,以及以多种格式读写: https://networkx.github.io/documentation/stable/reference/readwrite/index.html

【讨论】:

【参考方案4】:

我一直在寻找类似的问题:使用嵌套字典打印字典的键,其中键结构非常周期性。 因此,我编写了一个递归函数,用于打印每个字典和嵌套字典的键,用于单个分支

希望以下代码 sn-p 对其他人有所帮助:

from itertools import zip_longest

def dictPrintKeysTopBranch(dic):
    #track recursive depth
    depth=dictPrintKeysTopBranch.data.get('depth',-1)+1;
    dictPrintKeysTopBranch.data['depth']=depth;

    #accumalte keys from nested dicts
    if type(dic) is type(dict()):
        listKeys=sorted(list(dic.keys()));

        #save keys of current depth
        dictPrintKeysTopBranch.data['listKeysDepth'.format(depth)]=listKeys;

        #repeat for top branch
        dictPrintKeysTopBranch(dic[listKeys[0]]);

    #print accumalated list of keys
    else: 
        #pad lists 
        lists=[];
        maxlen=[];
        for d in range(depth):
            l=dictPrintKeysTopBranch.data['listKeysDepth'.format(d)];
            lists.append(l);

            lens = [len(s) for s in l];
            maxlen.append(max(lens)+1);

        i=-1;
        for zipped in zip_longest(*lists, fillvalue=' '):
            i=i+1;
            #print(x)
            row = '';
            j=-1;
            for z in zipped:
                j=j+1;
                if i==0:
                    row = row+ ((' : <'+str(maxlen[j])+' -->\\').format(z));
                else :
                    row = row+ ((' : <'+str(maxlen[j])+'    |').format(z));
            print(row.strip('\\|->'));

    dictPrintKeysTopBranch.data=;
dictPrintKeysTopBranch.data=;

这里是一个例子:

mydict =  'topLv':'secLv':'thirdLv':'item1':42,'item2':'foo', 
           'topLvItem':[1,2,3], 
           'topLvOther':'notPrinted':':('
         
dictPrintKeysTopBranch(mydict)

输出:

topLv       -->\ secLv  -->\ thirdLv  -->\ item1  
topLvItem      |           |             | item2     
topLvOther     |           |             |         

【讨论】:

【参考方案5】:

根据您的需要,但如果您只需要它来轻松查看内容,您可以使用在线工具 - "Python dict formatter and viewer" 可以将 dict 呈现为树。

【讨论】:

以上是关于用于从嵌套的 Python 对象 (dicts) 创建树形图的 Python 库的主要内容,如果未能解决你的问题,请参考以下文章

python 递归地将嵌套的dicts转换为嵌套的namedtuples,为您提供类似于不可变对象文字的东西

Python 自动将dict-list嵌套数据 转换成 带类型定义的对象

将嵌套dict的值赋给python中的列表

覆盖继承的默认支持对象(如 dict、list)的嵌套 JSON 编码

从嵌套的dict中选择一个随机值,并在另一个嵌套的dict中更新它

嵌套 dict 和 pybind11