2

I am trying to use anytree to read a JSON file and export it as a png image using render tree graph. For a basic example where I create the node it works.

from anytree import RenderTree
from anytree import Node
from anytree.dotexport import RenderTreeGraph

root = Node("root")
s0 = Node("s0", parent=root)
s1 = Node("s1", parent=root)
t1 = Node("t1", parent=s0)

print(root)
RenderTreeGraph(root).to_picture("test.png")

Image generated by program

When I try importing a json file as per the docs

from anytree.importer import JsonImporter
from anytree import RenderTree
from anytree import Node
from anytree.dotexport import RenderTreeGraph
importer = JsonImporter()
path = open("config.json")

root = importer.read(path)
tree = RenderTree(root)
print(tree)

RenderTreeGraph(tree).to_picture("test.png")

I get the following error:

Traceback (most recent call last): File "pyth.py", line 20, in <module> DotExporter(tree).to_dotfile("tree.dot") File "/home/user/.local/lib/python3.5/site-packages/anytree/exporter/dotexporter.py", line 214, in to_dotfile for line in self: File "/home/user/.local/lib/python3.5/site-packages/anytree/exporter/dotexporter.py", line 160, in __iter for node in self.__iter_nodes(indent, nodenamefunc, nodeattrfunc): File "/home/user/.local/lib/python3.5/site-packages/anytree/exporter/dotexporter.py", line 174, in __iter_nodes nodename = nodenamefunc(node) File "/home/user/.local/lib/python3.5/site-packages/anytree/exporter/dotexporter.py", line 142, in __default_nodenamefunc return node.name AttributeError: 'RenderTree' object has no attribute 'name'

Piping the print(tree) to a text file give the JSON as a text block without white space formatting, where as in the docs this needs to be done line by line to capture the tree structure. So it appears as though RenderTree(root) isn't formatting the JSON in the Node style of the first example.

Does anyone know what is going wrong? Is there another step to correctly parse the JSON?

MikeS159
  • 1,884
  • 3
  • 29
  • 54

1 Answers1

1

Let's make a generalized example, i.e. where you almost have nothing to do manually.

Imports

import anytree.exporter as atex
import anytree as at
import json

A JSON

Below (i) a_str_json, a toy-json that I found at https://json.org/example.html, and which is representative of the content of your file called "config.json" and (ii) a_dict, its python converted version.

a_str_json = ("""
{
    "glossary": {
        "title": "example glossary",
        "GlossDiv": {
            "title": "S",
            "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
                    "SortAs": "SGML",
                    "GlossTerm": "Standard Generalized Markup Language",
                    "Acronym": "SGML",
                    "Abbrev": "ISO 8879:1986",
                    "GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
                        "GlossSeeAlso": ["GML", "XML"]
                    },
                    "GlossSee": "markup"
                }
            }
        }
    }
}
""")

a_dict = json.loads(a_str_json)

Core job

Let's define tree_builder, a function that will build our tree by exploring a_dict recursively.

def tree_builder(d, p_uid='root', l=0):

    for i, (k, v) in enumerate(d.items()):
        node_uid = 'l{}n{}'.format(l, i)
        node = nodes[k] = at.Node(
            name   = node_uid,
            key    = k,
            parent = nodes[p_uid]
        )
        if isinstance(v, dict):
            node.an_attr = ''
            tree_builder(v, k, l + 1)
        else:
            node.an_attr = v

... and use it

root  = at.Node(name='root', key='root', an_attr='')
nodes = {'root' : root}
tree_builder(a_dict)

for pre, fill, node in at.RenderTree(root):
    print("%s%s|%s" % (pre, node.key, node.an_attr))

atex.DotExporter(
    root, nodeattrfunc = lambda n : 'label="{}\n{}"'.format(n.key, n.an_attr)
).to_picture("root.png")

which produces

root|
└── glossary|
    ├── title|example glossary
    └── GlossDiv|
        ├── title|S
        └── GlossList|
            └── GlossEntry|
                ├── ID|SGML
                ├── SortAs|SGML
                ├── GlossTerm|Standard Generalized Markup Language
                ├── Acronym|SGML
                ├── Abbrev|ISO 8879:1986
                ├── GlossDef|
                │   ├── para|A meta-markup language, used to create markup languages such as DocBook.
                │   └── GlossSeeAlso|['GML', 'XML']
                └── GlossSee|markup

and

enter image description here


Tested with GraphViz 2.38 under windows 10.
keepAlive
  • 6,369
  • 5
  • 24
  • 39
  • That appears to work, except I am not seeing the image even if I give it a compete file path to save to. (I am on windows, don't know if that makes a difference). – MikeS159 Sep 17 '19 at 18:11
  • Errors with can't find the file specified – MikeS159 Sep 17 '19 at 18:14
  • My code is on a folder within my user area. Trace on paste bin. https://pastebin.com/fzhFHUrg – MikeS159 Sep 17 '19 at 22:13
  • Ahhh, OK. I was unable to install python-graphviz, that could be it. – MikeS159 Sep 17 '19 at 22:51
  • @MikeS159 No. Do not use python-graphviz. Download directly GraphViz from [here](https://graphviz.gitlab.io/_pages/Download/Download_windows.html) and do not forget to [add](https://youtu.be/bEroNNzqlF4) its bin folder (for example `C:\Program Files (x86)\Graphviz2.38\bin`) to the path. – keepAlive Sep 17 '19 at 23:03