Multidimensional Trees

Application: Tree nodes should be hooked-up in multiple trees.

An anytree node is only able to be part of one tree, not multiple. The following example shows how to handle this.

Example: 4 objects A, B, C and D shall be part of the trees X and Y.

The objects A, B, C and D are instances of a class Item. It is not a tree node. It just contains references x and y to the node representations in the corresponding trees.

>>> class Item:
...     def __init__(self, name):
...         self.name = name
...         self.x = None
...         self.y = None
...     def __repr__(self):
...         return "Item(%r)" % self.name
>>> a = Item('A')
>>> b = Item('B')
>>> c = Item('C')
>>> d = Item('D')

The tree nodes just contain the reference to item and take care of the proper reference, by using the attach/detach protocol.

>>> from anytree import NodeMixin, RenderTree
>>> class NodeX(NodeMixin):
...     def __init__(self, item, parent=None):
...         self.item = item
...         self.parent = parent
...     def _pre_detach(self, parent):
...         self.item.x = None
...     def _pre_attach(self, parent):
...         self.item.x = self
>>> class NodeY(NodeMixin):
...     def __init__(self, item, parent=None):
...         self.item = item
...         self.parent = parent
...     def _pre_detach(self, parent):
...         self.item.y = None
...     def _pre_attach(self, parent):
...         self.item.y = self

Tree generation is simple:

>>> # X
>>> xa = NodeX(a)
>>> xb = NodeX(b, parent=xa)
>>> xc = NodeX(c, parent=xa)
>>> xd = NodeX(d, parent=xc)
>>> # Y
>>> yd = NodeY(d)
>>> yc = NodeY(c, parent=yd)
>>> yb = NodeY(b, parent=yd)
>>> ya = NodeY(a, parent=yb)

All tree functions as rendering and exporting can be used as usual:

>>> for row in RenderTree(xa):
...     print("%s%s" % (row.pre, row.node.item))
Item('A')
├── Item('B')
└── Item('C')
    └── Item('D')
>>> for row in RenderTree(yd):
...     print("%s%s" % (row.pre, row.node.item))
Item('D')
├── Item('C')
└── Item('B')
    └── Item('A')