用于从嵌套的 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 的示例(带有 id
和 children
字段)。
图形也可以通过递归迭代创建,以及以多种格式读写: 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、list)的嵌套 JSON 编码