14

有谁知道任何 Python 库可以让您简单快速地为其提供嵌套到任意级别的对象,例如按照您在此 gist中找到的内容的 dict 树,它可以吐出一个可行的树图形文件?

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

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


(来源:rubyforge.org

4

5 回答 5

5

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

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 可以读取的文件。

于 2013-01-25T17:50:16.910 回答
2

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

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

  2. 输出格式是 HTML 或 SVG,而不是某些特定语言格式的对象

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

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

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

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

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

{"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字典表示,我如上所述将其转换为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 中呈现的 python 字典:

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

于 2013-01-25T18:41:36.787 回答
1

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字段)的示例。

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

于 2020-04-27T07:59:28.970 回答
0

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

希望以下代码片段对其他人有所帮助:

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     |           |             |         
于 2018-09-25T13:15:47.483 回答
-2

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

于 2013-04-07T17:02:40.693 回答