Question

I'm trying to write a function that prints a object hierarchy tree (in Blender 3D but this is a general Python question) with decimal outline numbering.

I require:

  • an optional indent with any symbol like "+" or "--" or no indent "", and
  • an optionally appended ".0" to nodes that have children to distinguish branches from leaves.

For example, in Blender I created an armature with bones and hierarchy is like this:

+ Life
++ Bacteria
++ Eukaryota
+++ plants
+++ animals
++++ Vertebrates
+++++ amphibians
+++++ reptiles
+++++ mammals

In de Text Editor I created this basic script:

import bpy
D = bpy.data
root = D.armatures['Armature'].bones['Life']

def print_hierarchy(obj, indent = "+"):
    print(indent, obj.name)
    for child in obj.children:
        print_hierarchy(child, indent+"+")
print_hierarchy(root)

this script outputs:

+ Life
++ Bacteria
++ Eukaryota
+++ plants
+++ animals
++++ Vertebrates
+++++ amphibians
+++++ reptiles
+++++ mammals

I want it to look like this

1.0 Life
    1.1 Bacteria
    1.2.0 Eukaryota
        1.2.1 plants
        1.2.2.0 animals
            1.2.2.1.0 Vertebrates
                1.2.2.1.1 amphibians
                1.2.2.1.2 reptiles
                1.2.2.1.3 mammals

I've tinkered with the (recursive) function print_hierarchy() but it breaks everytime I try to add something new to it. I can't wrap my brain around it so I'd like some help please.

Is a while-loop better / more efficient / faster than a recursive function for this sort of thing?

Was it helpful?

Solution

It would be easier to do e.g.

1 Life
    1.1 Bacteria
    1.2 Eukaryota
        1.2.1 plants
        1.2.2 animals
              1.2.2.1 Vertebrates
              1.2.2.1.1 amphibians
              1.2.2.1.2 reptiles
              1.2.2.1.3 mammals

As then you don't have to check explicitly whether the node has children to print it out. A couple of useful bits of code:

for index, child in enumerate(obj.children, 1):

This will number each of the children, using one-based indices.

''.join(('\t', indent, '.', str(index)))

Adds a new tab to the start of the previous indent, and the index to the end. Putting that together:

def print_hierarchy(root, indent="1"):
    print('\t'.join([indent, root.name]))
    for index, child in enumerate(root.children, 1):
        print_hierarchy(child, ''.join(('\t', indent, '.', str(index))))

I get:

1   life
    1.1 bacteria
    1.2 eukaryota
        1.2.1   plants
        1.2.2   animals
            1.2.2.1 vertebrates
                1.2.2.1.1   amphibians
                1.2.2.1.2   reptiles
                1.2.2.1.3   mammals

For fuller functionality, it gets more complex:

def print_hierarchy(root, indent=None, dec=None, zeroes=False):
    if indent is None:
        indent = []
    elif isinstance(indent, str):
        indent = [indent]
    if dec is None:
        dec = []
        zeroes = False
    elif isinstance(dec, int):
        dec = [str(dec)]
    elif isinstance(dec, str):
        dec = [dec]
    print(' '.join([''.join(indent), 
                    '.'.join(dec + ["0"] if root.children and zeroes else dec), 
                    root.name]))
    for index, child in enumerate(root.children, 1):
        print_hierarchy(child, 
                        indent + [indent[0]] if indent else indent, 
                        dec + [str(index)] if dec else dec,
                        zeroes)

print_hierarchy(root, "\t", 1, True)

OTHER TIPS

You could change your recursive function like this:

>>> def print_hierarchy(obj, prefix = ''):
        print('{}{} {}'.format(prefix, '.0' if obj.children else '', obj.name))
        for num, child in enumerate(obj.children, 1):
            print_hierarchy(child, '    {}.{}'.format(prefix, num))

>>> print_hierarchy(root, '1')
1.0 Life
    1.1 Bacteria
    1.2.0 Eukaryota
        1.2.1 plants
        1.2.2.0 animals
            1.2.2.1.0 Vertebratens
                1.2.2.1.1 amphibians
                1.2.2.1.2 reptiles
                1.2.2.1.3 mammals

But I’d agree with jonrsharpe, that the numbering does not really make sense for a hierarchy. It makes it seem that Life and Bacteria are on the same level, but Eukaryota isn’t.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top