Skip to content

Hierarchy

Hierarchy(name, dimension_name, elements=None, element_attributes=None, edges=None, subsets=None, structure=None, default_member=None)

Bases: TM1Object

Abstraction of TM1 Hierarchy Requires reference to a Dimension

Elements modeled as a Dictionary where key is the element name and value an instance of TM1py.Element { 'US': instance of TM1py.Element, 'CN': instance of TM1py.Element, 'AU': instance of TM1py.Element }

ElementAttributes of type TM1py.Objects.ElementAttribute

Edges are represented as a TM1py.Utils.CaseAndSpaceInsensitiveTupleDict: { (parent1, component1) : 10, (parent1, component2) : 30 }

Subsets is list of type TM1py.Subset

Source code in TM1py/Objects/Hierarchy.py
def __init__(
    self,
    name: str,
    dimension_name: str,
    elements: Optional[Iterable["Element"]] = None,
    element_attributes: Optional[Iterable["ElementAttribute"]] = None,
    edges: Optional["Dict"] = None,
    subsets: Optional[Iterable[str]] = None,
    structure: Optional[int] = None,
    default_member: Optional[str] = None,
):

    self._name = name
    self._dimension_name = None
    self.dimension_name = dimension_name
    self._elements: Dict[str, Element] = CaseAndSpaceInsensitiveDict()
    if elements:
        for elem in elements:
            self._elements[elem.name] = elem
    self._element_attributes = list(element_attributes) if element_attributes else []
    self._edges = CaseAndSpaceInsensitiveTuplesDict(edges) if edges else CaseAndSpaceInsensitiveTuplesDict()
    self._subsets = list(subsets) if subsets else []
    # balanced is true, false or None (in versions < TM1 11)
    self._balanced = False if not structure else structure == 0
    self._default_member = default_member

balanced property

body property

body_as_dict property

default_member property

dimension_name property writable

edges property

element_attributes property

elements property

name property writable

subsets property

__contains__(item)

Source code in TM1py/Objects/Hierarchy.py
def __contains__(self, item):
    return self.contains_element(item)

__getitem__(item)

Source code in TM1py/Objects/Hierarchy.py
def __getitem__(self, item):
    return self.get_element(item)

__iter__()

Source code in TM1py/Objects/Hierarchy.py
def __iter__(self):
    return iter(self._elements.values())

__len__()

Source code in TM1py/Objects/Hierarchy.py
def __len__(self):
    return len(self._elements)

add_component(parent_name, component_name, weight)

Source code in TM1py/Objects/Hierarchy.py
def add_component(self, parent_name: str, component_name: str, weight: int):
    if parent_name not in self._elements:
        raise ValueError(f"Parent '{parent_name}' does not exist in hierarchy")
    if self._elements[parent_name].element_type != Element.Types.CONSOLIDATED:
        raise ValueError(f"Parent '{parent_name}' is not of type 'Consolidated'")

    if component_name not in self.elements:
        self.add_element(component_name, "Numeric")
    elif self._elements[component_name].element_type == Element.Types.STRING:
        raise ValueError(f"Component '{component_name}' must not be of type 'String'")

    self.add_edge(parent_name, component_name, weight)

add_edge(parent, component, weight)

Source code in TM1py/Objects/Hierarchy.py
def add_edge(self, parent: str, component: str, weight: float):
    self._edges[(parent, component)] = weight

add_element(element_name, element_type)

Source code in TM1py/Objects/Hierarchy.py
def add_element(self, element_name: str, element_type: Union[str, Element.Types]):
    if element_name in self._elements:
        raise ValueError("Element name must be unique")

    self._elements[element_name] = Element(name=element_name, element_type=element_type)

add_element_attribute(name, attribute_type)

Source code in TM1py/Objects/Hierarchy.py
def add_element_attribute(self, name: str, attribute_type: str):
    attribute = ElementAttribute(name, attribute_type)
    if attribute not in self.element_attributes:
        self.element_attributes.append(attribute)

contains_element(element_name)

Source code in TM1py/Objects/Hierarchy.py
def contains_element(self, element_name: str) -> bool:
    return element_name in self._elements

from_dict(hierarchy_as_dict, dimension_name=None) classmethod

Source code in TM1py/Objects/Hierarchy.py
@classmethod
def from_dict(cls, hierarchy_as_dict: Dict, dimension_name: str = None) -> "Hierarchy":
    # Build the Dictionary for the edges
    edges = CaseAndSpaceInsensitiveTuplesDict(
        {(edge["ParentName"], edge["ComponentName"]): edge["Weight"] for edge in hierarchy_as_dict["Edges"]}
    )

    if not dimension_name:
        dimension_name = hierarchy_as_dict["UniqueName"][1 : hierarchy_as_dict["UniqueName"].find("].[")]

    return cls(
        name=hierarchy_as_dict["Name"],
        dimension_name=dimension_name,
        elements=[Element.from_dict(elem) for elem in hierarchy_as_dict["Elements"]],
        element_attributes=[
            ElementAttribute(ea["Name"], ea["Type"]) for ea in hierarchy_as_dict.get("ElementAttributes", [])
        ],
        edges=edges,
        subsets=[subset["Name"] for subset in hierarchy_as_dict.get("Subsets", [])],
        structure=hierarchy_as_dict["Structure"] if "Structure" in hierarchy_as_dict else None,
        default_member=(
            hierarchy_as_dict["DefaultMember"]["Name"] if hierarchy_as_dict.get("DefaultMember", None) else None
        ),
    )

get_ancestor_edges(element_name, recursive=False)

Source code in TM1py/Objects/Hierarchy.py
def get_ancestor_edges(self, element_name: str, recursive: bool = False) -> Dict:
    ancestor_edges = dict()

    for (parent, component), weight in self._edges.items():
        if not case_and_space_insensitive_equals(component, element_name):
            continue

        ancestor_edges[parent, component] = weight
        ancestor: Element = self.elements[component]

        if recursive:
            ancestor_edges.update(self.get_ancestor_edges(ancestor.name, True))

    return ancestor_edges

get_ancestors(element_name, recursive=False)

Source code in TM1py/Objects/Hierarchy.py
def get_ancestors(self, element_name: str, recursive: bool = False) -> Set[Element]:
    ancestors = set()

    for parent, component in self._edges:
        if not case_and_space_insensitive_equals(component, element_name):
            continue

        ancestor: Element = self.elements[parent]
        ancestors.add(ancestor)

        if recursive:
            ancestors = ancestors.union(self.get_ancestors(ancestor.name, True))
    return ancestors

get_descendant_edges(element_name, recursive=False)

Source code in TM1py/Objects/Hierarchy.py
def get_descendant_edges(self, element_name: str, recursive: bool = False) -> Dict:
    descendant_edges = dict()

    for (parent, component), weight in self._edges.items():
        if not case_and_space_insensitive_equals(parent, element_name):
            continue

        descendant_edges[parent, component] = weight
        descendant: Element = self.elements[component]

        if recursive and descendant.element_type == Element.Types.CONSOLIDATED:
            descendant_edges.update(self.get_descendant_edges(descendant.name, True))

    return descendant_edges

get_descendants(element_name, recursive=False, leaves_only=False)

Source code in TM1py/Objects/Hierarchy.py
def get_descendants(self, element_name: str, recursive: bool = False, leaves_only=False) -> Set[Element]:
    descendants = set()

    for parent, component in self._edges:
        if not case_and_space_insensitive_equals(parent, element_name):
            continue

        descendant: Element = self.elements[component]
        if not leaves_only:
            descendants.add(descendant)
        else:
            if descendant.element_type == Element.Types.NUMERIC:
                descendants.add(descendant)

        if recursive and descendant.element_type == Element.Types.CONSOLIDATED:
            descendants = descendants.union(self.get_descendants(descendant.name, True, leaves_only=leaves_only))
    return descendants

get_element(element_name)

Source code in TM1py/Objects/Hierarchy.py
def get_element(self, element_name: str) -> Element:
    if element_name in self._elements:
        return self._elements[element_name]
    else:
        raise ValueError("Element: {} not found in Hierarchy: {}".format(element_name, self.name))

remove_all_edges()

Source code in TM1py/Objects/Hierarchy.py
def remove_all_edges(self):
    self._edges = CaseAndSpaceInsensitiveTuplesDict()

remove_all_elements()

Source code in TM1py/Objects/Hierarchy.py
def remove_all_elements(self):
    self._elements = CaseAndSpaceInsensitiveDict()
    self.remove_all_edges()

remove_edge(parent, component)

Source code in TM1py/Objects/Hierarchy.py
def remove_edge(self, parent: str, component: str):
    if (parent, component) in self.edges:
        del self.edges[(parent, component)]

remove_edges(edges)

Source code in TM1py/Objects/Hierarchy.py
def remove_edges(self, edges: Iterable[Tuple[str, str]]):
    for edge in edges:
        self.remove_edge(*edge)
Source code in TM1py/Objects/Hierarchy.py
def remove_edges_related_to_element(self, element_name: str):
    element_name_adjusted = lower_and_drop_spaces(element_name)
    edges_to_remove = set()
    for edge in self._edges.adjusted_keys():
        if element_name_adjusted in edge:
            edges_to_remove.add(edge)
    self.remove_edges(edges=edges_to_remove)

remove_element(element_name)

Source code in TM1py/Objects/Hierarchy.py
def remove_element(self, element_name: str):
    if element_name not in self._elements:
        return
    del self._elements[element_name]
    self.remove_edges_related_to_element(element_name=element_name)

remove_element_attribute(name)

Source code in TM1py/Objects/Hierarchy.py
def remove_element_attribute(self, name: str):
    self._element_attributes = [
        element_attribute
        for element_attribute in self.element_attributes
        if not case_and_space_insensitive_equals(element_attribute.name, name)
    ]

replace_element(old_element_name, new_element_name)

Substitute one element in the hierarchy structure, so that all edges are moved from the old element to the new element.

Source code in TM1py/Objects/Hierarchy.py
def replace_element(self, old_element_name: str, new_element_name: str):
    """
    Substitute one element in the hierarchy structure,
    so that all edges are moved from the old element to the new element.
    """
    if old_element_name not in self.elements:
        raise ValueError(f"Element '{old_element_name}' does not exist in hierarchy")

    if new_element_name in self.elements:
        raise ValueError(f"Element '{new_element_name}' already exists in hierarchy")

    element = self.get_element(old_element_name)
    ancestor_edges = self.get_ancestor_edges(old_element_name, recursive=False)
    descendant_edges = self.get_descendant_edges(element_name=old_element_name, recursive=False)

    self.remove_element(element_name=old_element_name)

    self.add_element(element_name=new_element_name, element_type=element.element_type)

    for (ancestor, _), weight in ancestor_edges.items():
        self.add_edge(parent=ancestor, component=new_element_name, weight=weight)
    for (_, descendant), weight in descendant_edges.items():
        self.add_edge(parent=new_element_name, component=descendant, weight=weight)

update_edge(parent, component, weight)

Source code in TM1py/Objects/Hierarchy.py
def update_edge(self, parent: str, component: str, weight: float):
    self._edges[(parent, component)] = weight

update_element(element_name, element_type)

Source code in TM1py/Objects/Hierarchy.py
def update_element(self, element_name: str, element_type: Union[str, Element.Types]):
    self._elements[element_name].element_type = element_type