PathMap

class treepathmap.PathMap(path_map_table: Optional[treepathmap.maps.PathMapTable] = None, selected_real_paths: Optional[pandas.core.indexes.base.Index] = None, selection_path_name: Optional[str] = None, path_mapping_behavior: Optional[treepathmap.maps.APathMappingBehavior] = None)

A map of a nested collection.

Parameters
  • path_map_table (Optional[PathMapTable]) – The table of all real paths and path map items, which is the basis of each path map.

  • selected_real_paths (Optional[pandas.Index]) – The selected real paths (indexes) of this instance.

  • selection_path_name (Optional[str]) – The name of the paths (real or additional paths) this path map points to.

  • path_mapping_behavior (Optional[APathMappingBehavior]) – The mapping behavior of this path map, by which new items are mapped.

Examples

In this example the map is build from scratch instead using treepathmap.map_tree(), which is the recommend way.

>>> from treepathmap import (
...     TreeNodePaths,
...     TreeNodeItem,
...     TreeNodeItems,
...     PathMapTable
... )

The nested sample collection is kept simple.

>>> sample_tree = {"a": {"b": {"d": "leaf-1"}, "c": {"e": "leaf-2"}}}

The tree node paths are pointing at items of the collection. Meta attributes are inherited, what is taken into account here.

>>> tree_node_paths = [
...     TreeNodePaths([["a"], ["x"]], {"k1": 1}),
...     TreeNodePaths([["a", "b"], [""]], {"k1": 2, "k2": "n"}),
...     TreeNodePaths([["a", "b", "d"], ["y"]], {"k1": 2, "k2": "m"}),
...     TreeNodePaths([["a", "c"], [""]], {"k1": 3, "k2": "n"}),
...     TreeNodePaths([["a", "c", "e"], ["y"]], {"k1": 3, "k2": "m"})
... ]

The prior block is identical to the following one, which shows the joining method of TreeNodePaths.

>>> a_root_path = TreeNodePaths([RootNodePath()])
>>> path_1 = a_root_path.join([["a"], ["x"]], {"k1": 1})
>>> path_11 = path_1.join([["b"], [""]], {"k1": 2, "k2": "n"})
>>> path_111 = path_11.join([["d"], ["y"]], {"k2": "m"})
>>> path_21 = path_1.join([["c"], [""]], {"k1": 3, "k2": "n"})
>>> path_211 = path_21.join([["e"], ["y"]], {"k2": "m"})
>>> tree_node_paths = [path_1, path_11, path_111, path_21, path_211]

The tree node items resembles the core of the PathMapTable, which is the basis of the final PathMap. Using treepathmap.map_tree() is the recommended way to get a PathMap.

>>> sample_node_items = TreeNodeItems(
...     TreeNodeItem(tree_node_paths[0], sample_tree),
...     TreeNodeItem(tree_node_paths[1], sample_tree["a"]),
...     TreeNodeItem(tree_node_paths[2], sample_tree["a"]["b"]),
...     TreeNodeItem(tree_node_paths[3], sample_tree["a"]),
...     TreeNodeItem(tree_node_paths[4], sample_tree["a"]["c"]),
... )
...
>>> sample_table = PathMapTable(tree_node_items=sample_node_items)
>>> sample_map = PathMap(sample_table)
>>> print(sample_map)
          additional_path_1 meta_attributes
->a                     ->x        //k1/1//
->a->b                       //k1/2//k2/n//
->a->b->d               ->y  //k1/2//k2/m//
->a->c                       //k1/3//k2/n//
->a->c->e               ->y  //k1/3//k2/m//

The choosen path column defines the active tree nodes. The default column are the real paths. In this example the additional paths has one blank path, which is removed from the view.

>>> sample_map = PathMap(sample_table)
>>> sample_map.real_paths
Index(['->a', '->a->b', '->a->b->d', '->a->c', '->a->c->e'], dtype='object')
>>> other_view = sample_map[1]
>>> other_view.real_paths
Index(['->a', '->a->b->d', '->a->c->e'], dtype='object')

The choosen paths define the selection and iteration behavior of the path map. In the following case the paths ‘->a->b’ and ‘->a->c’ are omitted, due to a blank path in the additional paths.

>>> rows = {
...     real_path: row.to_list()
...     for real_path, row in other_view.iter_rows()
... }
...
>>> from dicthandling import print_tree
>>> print_tree(rows)
->a: ['->a', '->x']
->a->b->d: ['->a->b->d', '->y']
->a->c->e: ['->a->c->e', '->y']
>>> selected_map = other_view.select("y")
>>> print(selected_map)
          additional_path_1 meta_attributes
->a->b->d               ->y  //k1/2//k2/m//
->a->c->e               ->y  //k1/3//k2/m//

Since the additional paths are active only ‘->a->c->e’ should be selected using the where statement, although ‘->a->c’ also is tagged with {k1: 3}.

>>> reduced_map = selected_map.meta.where(wh_is("k1", "3"))
>>> print(reduced_map)
          additional_path_1 meta_attributes
->a->c->e               ->y  //k1/3//k2/m//
>>> reduced_map.select("->a->b->d")
<empty map>
>>> reduced_map.real_path_exists("->not->existing")
False
>>> reduced_map.real_path_exists("->a->b")
False
>>> reduced_map.real_path_exists("->a->c->e")
True
>>> for item in reduced_map.tree_node_items:
...     print(item)
TreeNodeItem(->a->c->e: in a dict)
>>> list(reduced_map.tree_items)
['leaf-2']

The reduced map is switched back to the real paths. Selections from the reduced map should not exceed the current selection.

>>> reduced_map = reduced_map["real_path"]
>>> reduced_map.selected_indexes
Index(['->a->c->e'], dtype='object')
>>> reduced_map.select("a", "*")
->a->c->e
    additional_path_1: ->y
    meta attributes: {'k1': 3, 'k2': 'm'}

By default the first tag group are the meta_attributes, which are an instance of treepathmap.IrregularTags. The tags attribute of the path map gives access to all tag groups. In this example all items with the meta attributes k2 being m are selected. The new tag group ‘ids’ is assigned, which can be selected by this tags from the whole map afterwards.

>>> items_with_k2_is_m = sample_map.tags["meta_attributes"].where("k2/m")
>>> items_with_k2_is_m.tags["ids"].tag({"category": "foo", "name": "bar"})
>>> items_with_k2_is_m.tags["ids"]
          category name                         ids
->a->b->d      foo  bar  //category/foo//name/bar//
->a->c->e      foo  bar  //category/foo//name/bar//
>>> sample_map.tags["ids"].where("category/foo")
->a->b->d
    additional_path_1: ->y
    meta attributes: {'k1': 2, 'k2': 'm'}
->a->c->e
    additional_path_1: ->y
    meta attributes: {'k1': 3, 'k2': 'm'}