Reputation: 17072
Does anyone know of any Python libraries that allow you to simply and quickly feed it an object nested to arbitrary levels, like for example a dict tree along the lines of what you'd find in this gist, and it can spit out a workable tree graph file?
Simplicity is key, here, since I have to be able to work with people who are not technically minded.
What I mean by "graph tree" is something along the lines of the following, where I could feed it a nested dictionary of values and it would then create the tree structure:
(source: rubyforge.org)
Upvotes: 16
Views: 28671
Reputation: 11
D3.js is a library for visualization mostly...
As far as I know, it does not provide a convenient tools for traversing graphs and mathematical operations with them. But they are in Python networkX package:
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']
This is an example of creating from structure an identical D3.js (with id
and children
fields).
Graph can also be created iteratively with recursion, as well as read and write with a variety of formats: https://networkx.github.io/documentation/stable/reference/readwrite/index.html
Upvotes: 1
Reputation: 734
I was looking for a similar problem: printing keys of a dict with nested dicts, where the key structure is very periodic. Therefore I wrote a recursive function that prints the keys of every dict and nested dicts, but for a single branch.
Hope the following code snippet helps other people:
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={};
Here an example:
mydict = { 'topLv':{'secLv':{'thirdLv':{'item1':42,'item2':'foo'}}},
'topLvItem':[1,2,3],
'topLvOther':{'notPrinted':':('}
}
dictPrintKeysTopBranch(mydict)
Output:
topLv -->\ secLv -->\ thirdLv -->\ item1
topLvItem | | | item2
topLvOther | | |
Upvotes: 0
Reputation: 70068
so the library i recommend and use for my code snippet in this answer is not a python library, but it is a python-friendly library, by which i mean that code using this library can be inserted into a python module for processing data and this foreign code will connect to extant python code on both ends, ie, both input and output, and i suspect, although of course i don't know, that's all that's really meant by the "python library" criterion. So if you are writing a web app, this code would be client-side. In other words, this library is not python, but it works with python.
its input is (nearly) raw python dicts, more specifically, json.load(a_python_dict) returns a json array or object, a format which this javascript library can of course recognize; and
the output format is either HTML or SVG, not objects in some language-specific format
You can use d3.js. It has a class specifically for rendering trees:
var tree = d3.layout.tree().size([h, w]);
There is also a couple of examples of trees (working code) in the example folder in the d3 source, which you can clone/download form the link i provided above.
Because d3 is a javascript library, its native data format is JSON.
The basic structure is a nested dictionary, each dictionary representing a single node with two values, the node's name and its children (stored in an array), keyed to names and children, respectively:
{"name": "a_root_node", "children": ["B", "C"]}
and of course it's simple to convert between python dictionaries and JSON:
>>> d = {"name": 'A', "children": ['B', 'C']}
>>> import json as JSON
>>> dj = JSON.dumps(d)
>>> dj
'{"name": "A", "children": ["B", "C"]}'
here's a python dictionary representation of a larger tree (a dozen or so nodes) which i converted to json as above, and then rendered in d3 as the tree shown in the image below:
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}]}]}]}
note: d3 renders in the browser; the image above is just a screen shot of my browser window.
Upvotes: 4
Reputation: 1
Depending on what you need, but if you only need it to view the content easily, you can use the online tool for that - "Python dict formatter and viewer" can render a dict as a tree.
Upvotes: -2
Reputation: 645
I'm not sure that this is quite what you have in mind, but it's the first thing that comes to mind.
blockdiag is mainly intended to be used as a standalone file processor similar to Graphviz (for which there exists a Python interface). It accepts a text file as input with a drop-dead simple syntax, and produces images as output.
You should be able to write a simple shim to output your recursive dict structure formatted for input to the standalone blockdiag script, or import the necessary innards of the blockdiag package and drive the output directly.
If this sounds promising, I'll see if I can whip up some example code.
EDIT Example code:
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('}')
This will output a file that blockdiag can read.
Upvotes: 5