Skip to content

lineagetree.lineage_tree_manager

Classes:

Name Description
LineageTreeManager

LineageTreeManager

LineageTreeManager(
    lineagetree_list: Iterable[LineageTree] = (),
)

Creates a LineageTreeManager :TODO: write the docstring

Parameters:

Name Type Description Default

lineagetree_list

Iterable[LineageTree]

List of lineage trees to be in the LineageTreeManager

()

Methods:

Name Description
__len__

Returns how many lineagetrees are in the manager.

add

Function that adds a new lineagetree object to the class.

cross_lineage_edit_distance

Compute the unordered tree edit backtrace from Zhang 1996 between the trees spawned

labelled_mappings

Returns the labels or IDs of all the nodes in the subtrees compared.

load

Loading a lineage tree Manager from a ".ltm" file.

plot_tree_distance_graphs

Plots the subtrees compared and colors them according to the quality of the matching of their subtree.

remove_embryo

Removes the embryo from the manager.

write

Saves the manager

Attributes:

Name Type Description
gcd int

Calculates the greatesτ common divisor between all lineagetree resolutions in the manager.

Source code in src/lineagetree/lineage_tree_manager.py
def __init__(self, lineagetree_list: Iterable[LineageTree] = ()):
    """Creates a LineageTreeManager
    :TODO: write the docstring

    Parameters
    ----------
    lineagetree_list: Iterable of LineageTree
        List of lineage trees to be in the LineageTreeManager
    """
    self.lineagetrees: dict[str, LineageTree] = {}
    self.lineageTree_counter: int = 0
    self._comparisons: dict = {}
    for lT in lineagetree_list:
        self.add(lT)

gcd property

gcd: int

Calculates the greatesτ common divisor between all lineagetree resolutions in the manager.

Returns:

Type Description
int

The overall greatest common divisor.

__calculate_distance_of_sub_tree

__calculate_distance_of_sub_tree(
    node1: int,
    lT1: LineageTree,
    node2: int,
    lT2: LineageTree,
    alignment: Alignment,
    corres1: dict,
    corres2: dict,
    delta_tmp: Callable,
    norm: Callable,
    norm1: int | float,
    norm2: int | float,
) -> float

Calculates the distance of the subtree of a node matched in a comparison. DOES NOT CALCULATE THE DISTANCE FROM SCRATCH BUT USING THE ALIGNMENT.

TODO ITS BOUND TO CHANGE

Parameters:

Name Type Description Default

node1

int

The root of the first subtree

required

lT1

LineageTree

The dataset the first lineage exists

required

node2

int

The root of the first subtree

required

lT2

LineageTree

The dataset the second lineage exists

required

alignment

Alignment

The alignment of the subtree

required

corres1

dict

The correspndance dictionary of the first lineage

required

corres2

dict

The correspondance dictionary of the second lineage

required

delta_tmp

Callable

The delta function for the comparisons

required

norm

Callable

How should the lineages be normalized

required

norm1

int or float

The result of the normalization of the first tree

required

norm2

int or float

The result of the normalization of the second tree

required

Returns:

Type Description
float

The result of the comparison of the subtree

Source code in src/lineagetree/lineage_tree_manager.py
def __calculate_distance_of_sub_tree(
    self,
    node1: int,
    lT1: LineageTree,
    node2: int,
    lT2: LineageTree,
    alignment: Alignment,
    corres1: dict,
    corres2: dict,
    delta_tmp: Callable,
    norm: Callable,
    norm1: int | float,
    norm2: int | float,
) -> float:
    """Calculates the distance of the subtree of a node matched in a comparison.
    DOES NOT CALCULATE THE DISTANCE FROM SCRATCH BUT USING THE ALIGNMENT.

    TODO ITS BOUND TO CHANGE

    Parameters
    ----------
    node1 : int
        The root of the first subtree
    lT1 : LineageTree
        The dataset the first lineage exists
    node2 : int
        The root of the first subtree
    lT2 : LineageTree
        The dataset the second lineage exists
    alignment : Alignment
        The alignment of the subtree
    corres1 : dict
        The correspndance dictionary of the first lineage
    corres2 : dict
        The correspondance dictionary of the second lineage
    delta_tmp : Callable
        The delta function for the comparisons
    norm : Callable
        How should the lineages be normalized
    norm1 : int or float
        The result of the normalization of the first tree
    norm2 : int or float
        The result of the normalization of the second tree

    Returns
    -------
    float
        The result of the comparison of the subtree
    """
    sub_tree_1 = set(lT1.get_subtree_nodes(node1))
    sub_tree_2 = set(lT2.get_subtree_nodes(node2))
    res = 0
    for m in alignment:
        if (
            corres1.get(m._left, -1) in sub_tree_1
            or corres2.get(m._right, -1) in sub_tree_2
        ):
            res += delta_tmp(
                m._left if m._left != -1 else None,
                m._right if m._right != -1 else None,
            )
    return res / norm([norm1, norm2])

__cross_lineage_edit_backtrace

__cross_lineage_edit_backtrace(
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    style: (
        Literal[
            "simple",
            "normalized_simple",
            "full",
            "downsampled",
        ]
        | type[TreeApproximationTemplate]
    ) = "simple",
    norm: Literal["max", "sum", None] = "max",
    downsample: int = 2,
) -> dict[
    str,
    Alignment
    | tuple[
        TreeApproximationTemplate, TreeApproximationTemplate
    ],
]

Compute the unordered tree edit distance from Zhang 1996 between the trees spawned by two nodes n1 from lineagetree1 and n2 lineagetree2. The topology of the trees are compared and the matching cost is given by the function delta (see edist doc for more information).The distance is normed by the function norm that takes the two list of nodes spawned by the trees n1 and n2.

Parameters:

Name Type Description Default

n1

int

Node of the first Lineagetree

required

embryo_1

str

The key/name of the first Lineagetree

required

n2

int

The key/name of the first Lineagetree

required

embryo_2

str

Node of the second Lineagetree

required

end_time1

int

The final time point the comparison algorithm will take into account for the first dataset. If None or not provided all nodes will be taken into account.

None

end_time2

int

The final time point the comparison algorithm will take into account for the second dataset. If None or not provided all nodes will be taken into account.

None

style

('simple', 'normalized_simple', 'full', 'downsampled')

The approximation used to calculate the tree.

"simple"

norm

('max', 'sum', 'None')

The normalization method used (Not important for this function)

"max","sum"

downsample

int

The downsample factor for the downsampled tree approximation. Used only when style="downsampled".

=2

Returns:

Type Description
dict mapping str to Alignment or tuple of [TreeApproximationTemplate, TreeApproximationTemplate]
  • 'alignment' The alignment between the nodes by the subtrees spawned by the nodes n1,n2 and the normalization function.`
  • 'trees' A list of the two trees that have been mapped to each other.
Source code in src/lineagetree/lineage_tree_manager.py
def __cross_lineage_edit_backtrace(
    self,
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    style: (
        Literal["simple", "normalized_simple", "full", "downsampled"]
        | type[TreeApproximationTemplate]
    ) = "simple",
    norm: Literal["max", "sum", None] = "max",
    downsample: int = 2,
) -> dict[
    str,
    Alignment
    | tuple[TreeApproximationTemplate, TreeApproximationTemplate],
]:
    """Compute the unordered tree edit distance from Zhang 1996 between the trees spawned
    by two nodes `n1` from lineagetree1 and `n2` lineagetree2. The topology of the trees
    are compared and the matching cost is given by the function delta (see edist doc for
    more information).The distance is normed by the function norm that takes the two list
    of nodes spawned by the trees `n1` and `n2`.

    Parameters
    ----------
    n1 : int
        Node of the first Lineagetree
    embryo_1 : str
        The key/name of the first Lineagetree
    n2 : int
        The key/name of the first Lineagetree
    embryo_2 : str
        Node of the second Lineagetree
    end_time1 : int, optional
        The final time point the comparison algorithm will take into account for the first dataset.
        If None or not provided all nodes will be taken into account.
    end_time2 : int, optional
         The final time point the comparison algorithm will take into account for the second dataset.
        If None or not provided all nodes will be taken into account.
    style : {"simple", "normalized_simple", "full", "downsampled"} or TreeApproximationTemplate subclass, default="simple"
        The approximation used to calculate the tree.
    norm : {"max","sum", "None"}, default="max"
        The normalization method used (Not important for this function)
    downsample : int, default==2
        The downsample factor for the downsampled tree approximation.
        Used only when `style="downsampled"`.

    Returns
    -------
    dict mapping str to Alignment or tuple of [TreeApproximationTemplate, TreeApproximationTemplate]
        - 'alignment'
            The alignment between the nodes by the subtrees spawned by the nodes n1,n2 and the normalization function.`
        - 'trees'
            A list of the two trees that have been mapped to each other.
    """
    if (
        self[embryo_1].time_resolution <= 0
        or self[embryo_2].time_resolution <= 0
    ):
        raise Warning("Resolution cannot be <=0 ")
    parameters = (
        (end_time1, end_time2),
        convert_style_to_number(style, downsample),
    )
    n1_embryo, n2_embryo = sorted(
        ((n1, embryo_1), (n2, embryo_2)), key=lambda x: x[0]
    )
    self._comparisons.setdefault(parameters, {})
    if isinstance(style, str):
        tree = tree_style[style].value
    elif issubclass(style, TreeApproximationTemplate):
        tree = style
    else:
        raise Warning("Use a valid approximation.")
    time_res = tree.handle_resolutions(
        time_resolution1=self.lineagetrees[embryo_1]._time_resolution,
        time_resolution2=self.lineagetrees[embryo_2]._time_resolution,
        gcd=self.gcd,
        downsample=downsample,
    )
    tree1 = tree(
        lT=self.lineagetrees[embryo_1],
        downsample=downsample,
        end_time=end_time1,
        root=n1,
        time_scale=time_res[0],
    )
    tree2 = tree(
        lT=self.lineagetrees[embryo_2],
        downsample=downsample,
        end_time=end_time2,
        root=n2,
        time_scale=time_res[1],
    )
    delta = tree1.delta
    _, times1 = tree1.tree
    _, times2 = tree2.tree

    nodes1, adj1, corres1 = tree1.edist
    nodes2, adj2, corres2 = tree2.edist
    if len(nodes1) == len(nodes2) == 0:
        self._comparisons[parameters][(n1_embryo, n2_embryo)] = {
            "alignment": (),
            "trees": (),
        }
        return self._comparisons[parameters][(n1_embryo, n2_embryo)]
    delta_tmp = partial(
        delta,
        corres1=corres1,
        times1=times1,
        corres2=corres2,
        times2=times2,
    )
    btrc = uted.uted_backtrace(nodes1, adj1, nodes2, adj2, delta=delta_tmp)

    self._comparisons[parameters][(n1_embryo, n2_embryo)] = {
        "alignment": btrc,
        "trees": (tree1, tree2),
    }
    return self._comparisons[parameters][(n1_embryo, n2_embryo)]

__len__

__len__() -> int

Returns how many lineagetrees are in the manager.

Returns:

Type Description
int

The number of trees inside the manager

Source code in src/lineagetree/lineage_tree_manager.py
def __len__(self) -> int:
    """Returns how many lineagetrees are in the manager.

    Returns
    -------
    int
        The number of trees inside the manager
    """
    return len(self.lineagetrees)

add

add(other_tree: LineageTree, name: str = '')

Function that adds a new lineagetree object to the class. Can be added either by .add or by using the + operator. If a name is specified it will also add it as this specific name, otherwise it will use the already existing name of the lineagetree.

Parameters:

Name Type Description Default

other_tree

LineageTree

Thelineagetree to be added.

required

name

str

Then name of the lineagetree to be added, defaults to ''. (Usually lineageTrees have the name of the path they are read from, so this is going to be the name most of the times.)

""
Source code in src/lineagetree/lineage_tree_manager.py
def add(self, other_tree: LineageTree, name: str = ""):
    """Function that adds a new lineagetree object to the class.
    Can be added either by .add or by using the + operator. If a name is
    specified it will also add it as this specific name, otherwise it will
    use the already existing name of the lineagetree.

    Parameters
    ----------
    other_tree : LineageTree
        Thelineagetree to be added.
    name : str, default=""
        Then name of the lineagetree to be added, defaults to ''.
        (Usually lineageTrees have the name of the path they are read from,
        so this is going to be the name most of the times.)
    """
    if isinstance(other_tree, LineageTree):
        for tree in self.lineagetrees.values():
            if tree == other_tree:
                return False
        if name:
            self.lineagetrees[name] = other_tree
        else:
            if other_tree.name:
                name = other_tree.name
                self.lineagetrees[name] = other_tree
            else:
                name = f"Lineagetree {next(self)}"
                self.lineagetrees[name] = other_tree
                self.lineagetrees[name].name = name
    else:
        raise Exception(
            "Please add a LineageTree object or add time resolution to the LineageTree added."
        )

cross_lineage_edit_distance

cross_lineage_edit_distance(
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    norm: Literal["max", "sum", None] = "max",
    style: (
        Literal[
            "simple",
            "normalized_simple",
            "full",
            "downsampled",
        ]
        | type[TreeApproximationTemplate]
    ) = "simple",
    downsample: int = 2,
    return_norms: bool = False,
) -> float | tuple[float, tuple[float, float]]

Compute the unordered tree edit backtrace from Zhang 1996 between the trees spawned by two nodes n1 and n2. The topology of the trees are compared and the matching cost is given by the function delta (see edist doc for more information). There are 5 styles available (tree approximations) and the user may add their own.

Parameters:

Name Type Description Default

n1

int

id of the first node to compare

required

embryo_1

str

the name of the first embryo to be used. (from lTm.lineagetrees.keys())

required

n2

int

id of the second node to compare

required

embryo_2

str

the name of the second embryo to be used. (from lTm.lineagetrees.keys())

required

end_time_1

int

the final time point the comparison algorithm will take into account for the first dataset. If None or not provided all nodes will be taken into account.

required

end_time_2

int

the final time point the comparison algorithm will take into account for the second dataset. If None or not provided all nodes will be taken into account.

required

norm

('max', 'sum')

The normalization method to use, defaults to 'max'.

"max"

style

('simple', 'normalized_simple', 'full', 'downsampled')

Which tree approximation is going to be used for the comparisons, defaults to 'simple'.

"simple"

downsample

int

The downsample factor for the downsampled tree approximation. Used only when style="downsampled".

2

return_norms

bool

Decide if the norms will be returned explicitly (mainly used for the napari plugin)

False

Returns:

Type Description
Alignment

The alignment between the nodes by the subtrees spawned by the nodes n1,n2 and the normalization function.`

(tuple(tree, tree), optional)

The two trees that have been mapped to each other. Returned if return_norms is True

Source code in src/lineagetree/lineage_tree_manager.py
def cross_lineage_edit_distance(
    self,
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    norm: Literal["max", "sum", None] = "max",
    style: (
        Literal["simple", "normalized_simple", "full", "downsampled"]
        | type[TreeApproximationTemplate]
    ) = "simple",
    downsample: int = 2,
    return_norms: bool = False,
) -> float | tuple[float, tuple[float, float]]:
    """
    Compute the unordered tree edit backtrace from Zhang 1996 between the trees spawned
    by two nodes `n1` and `n2`. The topology of the trees are compared and the matching
    cost is given by the function delta (see edist doc for more information). There are
    5 styles available (tree approximations) and the user may add their own.

    Parameters
    ----------
    n1 : int
        id of the first node to compare
    embryo_1 : str
        the name of the first embryo to be used. (from lTm.lineagetrees.keys())
    n2 : int
        id of the second node to compare
    embryo_2 : str
        the name of the second embryo to be used. (from lTm.lineagetrees.keys())
    end_time_1 : int, optional
        the final time point the comparison algorithm will take into account for the first dataset.
        If None or not provided all nodes will be taken into account.
    end_time_2 : int, optional
        the final time point the comparison algorithm will take into account for the second dataset.
        If None or not provided all nodes will be taken into account.
    norm : {"max", "sum"}, default="max"
        The normalization method to use, defaults to 'max'.
    style : {"simple", "normalized_simple", "full", "downsampled"} or TreeApproximationTemplate subclass, default="simple"
        Which tree approximation is going to be used for the comparisons, defaults to 'simple'.
    downsample : int, default=2
        The downsample factor for the downsampled tree approximation.
        Used only when `style="downsampled"`.
    return_norms : bool
        Decide if the norms will be returned explicitly (mainly used for the napari plugin)

    Returns
    -------
    Alignment
        The alignment between the nodes by the subtrees spawned by the nodes n1,n2 and the normalization function.`
    tuple(tree,tree), optional
        The two trees that have been mapped to each other.
        Returned if `return_norms` is `True`
    """

    parameters = (
        (end_time1, end_time2),
        convert_style_to_number(style, downsample),
    )
    n1_embryo, n2_embryo = sorted(
        ((n1, embryo_1), (n2, embryo_2)), key=lambda x: x[0]
    )
    self._comparisons.setdefault(parameters, {})
    if self._comparisons[parameters].get((n1, n2)):
        tmp = self._comparisons[parameters][(n1_embryo, n2_embryo)]
    else:
        tmp = self.__cross_lineage_edit_backtrace(
            n1,
            embryo_1,
            n2,
            embryo_2,
            end_time1,
            end_time2,
            style,
            norm,
            downsample,
        )
    if len(self._comparisons) > 100:
        warnings.warn(
            "More than 100 comparisons are saved, use clear_comparisons() to delete them.",
            stacklevel=2,
        )
    btrc = tmp["alignment"]
    tree1, tree2 = tmp["trees"]
    _, times1 = tree1.tree
    _, times2 = tree2.tree
    (
        nodes1,
        adj1,
        corres1,
    ) = tree1.edist
    (
        nodes2,
        adj2,
        corres2,
    ) = tree2.edist
    if len(nodes1) == len(nodes2) == 0:
        self._comparisons[hash(frozenset(parameters))] = {
            "alignment": (),
            "trees": (),
        }
        return self._comparisons[hash(frozenset(parameters))]
    delta_tmp = partial(
        tree1.delta,
        corres1=corres1,
        corres2=corres2,
        times1=times1,
        times2=times2,
    )
    if norm not in self.norm_dict:
        raise ValueError(
            "Select a viable normalization method (max, sum, None)"
        )
    cost = btrc.cost(nodes1, nodes2, delta_tmp)
    norm_values = (tree1.get_norm(n1), tree2.get_norm(n2))
    if return_norms:
        return cost, norm_values
    return cost / self.norm_dict[norm](norm_values)

labelled_mappings

labelled_mappings(
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    norm: Literal["max", "sum", None] = "max",
    style: (
        Literal[
            "simple",
            "normalized_simple",
            "full",
            "downsampled",
        ]
        | type[TreeApproximationTemplate]
    ) = "simple",
    downsample: int = 2,
) -> dict[str, list[str]]

Returns the labels or IDs of all the nodes in the subtrees compared.

Parameters:

Name Type Description Default

n1

int

id of the first node to compare

required

embryo_1

str

the name of the first lineage

required

n2

int

id of the second node to compare

required

embryo_2

str

the name of the second lineage

required

end_time1

int

the final time point the comparison algorithm will take into account for the first dataset. If None or not provided all nodes will be taken into account.

None

end_time2

int

the final time point the comparison algorithm will take into account for the first dataset. If None or not provided all nodes will be taken into account.

None

norm

('max', 'sum')

The normalization method to use.

"max"

style

('simple', 'normalized_simple', 'full', 'downsampled')

Which tree approximation is going to be used for the comparisons.

"simple"

downsample

int

The downsample factor for the downsampled tree approximation. Used only when style="downsampled".

2

Returns:

Type Description
dict mapping str to lists of str
  • 'matched' The labels of the matched nodes of the alignment.
  • 'unmatched' The labels of the unmatched nodes of the alginment.
Source code in src/lineagetree/lineage_tree_manager.py
def labelled_mappings(
    self,
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    norm: Literal["max", "sum", None] = "max",
    style: (
        Literal["simple", "normalized_simple", "full", "downsampled"]
        | type[TreeApproximationTemplate]
    ) = "simple",
    downsample: int = 2,
) -> dict[str, list[str]]:
    """
    Returns the labels or IDs of all the nodes in the subtrees compared.

    Parameters
    ----------
    n1 : int
        id of the first node to compare
    embryo_1 : str
        the name of the first lineage
    n2 : int
        id of the second node to compare
    embryo_2: str
        the name of the second lineage
    end_time1 : int, optional
        the final time point the comparison algorithm will take into account for the first dataset.
        If None or not provided all nodes will be taken into account.
    end_time2 : int, optional
        the final time point the comparison algorithm will take into account for the first dataset.
        If None or not provided all nodes will be taken into account.
    norm : {"max", "sum"}, default="max"
        The normalization method to use.
    style : {"simple", "normalized_simple", "full", "downsampled"} or TreeApproximationTemplate subclass, default="simple"
        Which tree approximation is going to be used for the comparisons.
    downsample : int, default=2
        The downsample factor for the downsampled tree approximation.
        Used only when `style="downsampled"`.

    Returns
    -------
    dict mapping str to lists of str
        - 'matched' The labels of the matched nodes of the alignment.
        - 'unmatched' The labels of the unmatched nodes of the alginment.
    """

    parameters = (
        (end_time1, end_time2),
        convert_style_to_number(style, downsample),
    )
    n1_embryo, n2_embryo = sorted(
        ((n1, embryo_1), (n2, embryo_2)), key=lambda x: x[0]
    )
    self._comparisons.setdefault(parameters, {})
    if self._comparisons[parameters].get((n1, n2)):
        tmp = self._comparisons[parameters][(n1_embryo, n2_embryo)]
    else:
        tmp = self.__cross_lineage_edit_backtrace(
            n1,
            embryo_1,
            n2,
            embryo_2,
            end_time1,
            end_time2,
            style,
            norm,
            downsample,
        )
    btrc = tmp["alignment"]
    tree1, tree2 = tmp["trees"]
    _, times1 = tree1.tree
    _, times2 = tree2.tree
    (
        *_,
        corres1,
    ) = tree1.edist
    (
        *_,
        corres2,
    ) = tree2.edist
    if norm not in self.norm_dict:
        raise Warning(
            "Select a viable normalization method (max, sum, None)"
        )
    matched = []
    unmatched = []
    if style not in ("full", "downsampled"):
        for m in btrc:
            if m._left != -1 and m._right != -1:
                cyc1 = tree1.lT.get_chain_of_node(corres1[m._left])
                if len(cyc1) > 1:
                    node_1, *_ = cyc1
                elif len(cyc1) == 1:
                    node_1 = cyc1.pop()

                cyc2 = tree2.lT.get_chain_of_node(corres2[m._right])
                if len(cyc2) > 1:
                    node_2, *_ = cyc2

                elif len(cyc2) == 1:
                    node_2 = cyc2.pop()

                matched.append(
                    (
                        tree1.lT.labels.get(node_1, node_1),
                        tree2.lT.labels.get(node_2, node_2),
                    )
                )
            else:
                if m._left != -1:
                    tmp_node = tree1.lT.get_chain_of_node(
                        corres1.get(m._left, "-")
                    )[0]
                    node_1 = (
                        tree1.lT.labels.get(tmp_node, tmp_node),
                        tree1.lT.name,
                    )
                else:
                    tmp_node = tree2.lT.get_chain_of_node(
                        corres2.get(m._right, "-")
                    )[0]
                    node_1 = (
                        tree2.lT.labels.get(tmp_node, tmp_node),
                        tree2.lT.name,
                    )
                unmatched.append(node_1)
    else:
        for m in btrc:
            if m._left != -1 and m._right != -1:
                node_1 = corres1[m._left]
                node_2 = corres2[m._right]
                matched.append(
                    (
                        tree1.lT.labels.get(node_1, node_1),
                        tree2.lT.labels.get(node_2, node_2),
                    )
                )
            else:
                if m._left != -1:
                    tmp_node = tree1.lT.get_chain_of_node(
                        corres1.get(m._left, "-")
                    )[0]
                    node_1 = (
                        tree1.lT.labels.get(tmp_node, tmp_node),
                        tree1.lT.name,
                    )
                else:
                    tmp_node = tree2.lT.get_chain_of_node(
                        corres2.get(m._right, "-")
                    )[0]
                    node_1 = (
                        tree2.lT.labels.get(tmp_node, tmp_node),
                        tree2.lT.name,
                    )
                unmatched.append(node_1)
    return {"matched": matched, "unmatched": unmatched}

load classmethod

load(fname: str) -> LineageTreeManager

Loading a lineage tree Manager from a ".ltm" file.

Parameters:

Name Type Description Default

fname

str

path to and name of the file to read

required

Returns:

Type Description
LineageTreeManager

loaded file

Source code in src/lineagetree/lineage_tree_manager.py
@classmethod
def load(cls, fname: str) -> LineageTreeManager:
    """Loading a lineage tree Manager from a ".ltm" file.

    Parameters
    ----------
    fname : str
        path to and name of the file to read

    Returns
    -------
    LineageTreeManager
        loaded file
    """
    with open(fname, "br") as f:
        ltm = pkl.load(f)
        f.close()
    return ltm

plot_tree_distance_graphs

plot_tree_distance_graphs(
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    norm: Literal["max", "sum"] | None = "max",
    style: (
        Literal[
            "simple",
            "normalized_simple",
            "full",
            "downsampled",
        ]
        | type[TreeApproximationTemplate]
    ) = "simple",
    downsample: int = 2,
    colormap: str = "cool",
    default_color: str = "black",
    size: float = 10,
    lw: float = 0.3,
    ax: ndarray | None = None,
    vmin=None,
    vmax=None,
) -> tuple[plt.figure, plt.Axes]

Plots the subtrees compared and colors them according to the quality of the matching of their subtree.

Parameters:

Name Type Description Default

n1

int

id of the first node to compare

required

embryo_1

str

the name of the first embryo

required

n2

int

id of the second node to compare

required

embryo_2

str

the name of the second embryo

required

end_time1

int

the final time point the comparison algorithm will take into account for the first dataset. If None or not provided all nodes will be taken into account.

None

end_time2

int

the final time point the comparison algorithm will take into account for the second dataset. If None or not provided all nodes will be taken into account.

None

norm

('max', 'sum')

The normalization method to use.

"max"

style

('simple', 'normalized_simple', 'full', 'downsampled')

Which tree approximation is going to be used for the comparisons.

"simple"

downsample

int

The downsample factor for the downsampled tree approximation. Used only when style="downsampled".

2

colormap

str

The colormap used for matched nodes, defaults to "cool"

"cool"

default_color

str

The color of the unmatched nodes, defaults to "black"

'black'

size

float

The size of the nodes, defaults to 10

10

lw

float

The width of the edges, defaults to 0.3

0.3

ax

ndarray

The axes used, if not provided another set of axes is produced, defaults to None

None

vmin

Values within the range [vmin, vmax] from the input data will be linearly mapped to [0, 1]. vmin defaults to the 0.05 quantile of the values of the unordered tree edist distances of the subtrees. vmax defaults to the 0.95 quantile of the values of the unordered tree edist distances of the subtrees.

None

vmax

Values within the range [vmin, vmax] from the input data will be linearly mapped to [0, 1]. vmin defaults to the 0.05 quantile of the values of the unordered tree edist distances of the subtrees. vmax defaults to the 0.95 quantile of the values of the unordered tree edist distances of the subtrees.

None

Returns:

Type Description
Figure

The matplotlib figure

Axes

The matplotlib axes

Source code in src/lineagetree/lineage_tree_manager.py
def plot_tree_distance_graphs(
    self,
    n1: int,
    embryo_1: str,
    n2: int,
    embryo_2: str,
    end_time1: int | None = None,
    end_time2: int | None = None,
    norm: Literal["max", "sum"] | None = "max",
    style: (
        Literal["simple", "normalized_simple", "full", "downsampled"]
        | type[TreeApproximationTemplate]
    ) = "simple",
    downsample: int = 2,
    colormap: str = "cool",
    default_color: str = "black",
    size: float = 10,
    lw: float = 0.3,
    ax: np.ndarray | None = None,
    vmin=None,
    vmax=None,
) -> tuple[plt.figure, plt.Axes]:
    """
    Plots the subtrees compared and colors them according to the quality of the matching of their subtree.

    Parameters
    ----------
    n1 : int
        id of the first node to compare
    embryo_1 : str
        the name of the first embryo
    n2 : int
        id of the second node to compare
    embryo_2 : str
        the name of the second embryo
    end_time1 : int, optional
        the final time point the comparison algorithm will take into account for the first dataset.
        If None or not provided all nodes will be taken into account.
    end_time2 : int, optional
        the final time point the comparison algorithm will take into account for the second dataset.
        If None or not provided all nodes will be taken into account.
    norm : {"max", "sum"}, default="max"
        The normalization method to use.
    style : {"simple", "normalized_simple", "full", "downsampled"} or TreeApproximationTemplate subclass, default="simple"
        Which tree approximation is going to be used for the comparisons.
    downsample : int, default=2
        The downsample factor for the downsampled tree approximation.
        Used only when `style="downsampled"`.
    colormap : str, default="cool"
        The colormap used for matched nodes, defaults to "cool"
    default_color : str
        The color of the unmatched nodes, defaults to "black"
    size : float
        The size of the nodes, defaults to 10
    lw : float
        The width of the edges, defaults to 0.3
    ax : np.ndarray, optional
        The axes used, if not provided another set of axes is produced, defaults to None
    vmin, vmax: float, optional
        Values within the range ``[vmin, vmax]`` from the input data will be
        linearly mapped to ``[0, 1]``.
        *vmin* defaults to the 0.05 quantile of the values of the unordered tree edist distances of the subtrees.
        *vmax* defaults to the 0.95 quantile of the values of the unordered tree edist distances of the subtrees.

    Returns
    -------
    plt.Figure
        The matplotlib figure
    plt.Axes
        The matplotlib axes
    """

    parameters = (
        (end_time1, end_time2),
        convert_style_to_number(style, downsample),
    )
    n1_embryo, n2_embryo = sorted(
        ((n1, embryo_1), (n2, embryo_2)), key=lambda x: x[0]
    )
    self._comparisons.setdefault(parameters, {})
    if self._comparisons[parameters].get((n1, n2)):
        tmp = self._comparisons[parameters][(n1_embryo, n2_embryo)]
    else:
        tmp = self.__cross_lineage_edit_backtrace(
            n1,
            embryo_1,
            n2,
            embryo_2,
            end_time1,
            end_time2,
            style,
            norm,
            downsample,
        )
    btrc = tmp["alignment"]
    tree1, tree2 = tmp["trees"]
    _, times1 = tree1.tree
    _, times2 = tree2.tree
    (
        *_,
        corres1,
    ) = tree1.edist
    (
        *_,
        corres2,
    ) = tree2.edist
    delta_tmp = partial(
        tree1.delta,
        corres1=corres1,
        corres2=corres2,
        times1=times1,
        times2=times2,
    )
    if norm not in self.norm_dict:
        raise Warning(
            "Select a viable normalization method (max, sum, None)"
        )
    matched_right = []
    matched_left = []
    colors1 = {}
    colors2 = {}
    if style not in ("full", "downsampled"):
        for m in btrc:
            if m._left != -1 and m._right != -1:
                cyc1 = tree1.lT.get_chain_of_node(corres1[m._left])
                if len(cyc1) > 1:
                    node_1, *_, l_node_1 = cyc1
                    matched_left.append(node_1)
                    matched_left.append(l_node_1)
                elif len(cyc1) == 1:
                    node_1 = l_node_1 = cyc1.pop()
                    matched_left.append(node_1)

                cyc2 = tree2.lT.get_chain_of_node(corres2[m._right])
                if len(cyc2) > 1:
                    node_2, *_, l_node_2 = cyc2
                    matched_right.append(node_2)
                    matched_right.append(l_node_2)

                elif len(cyc2) == 1:
                    node_2 = l_node_2 = cyc2.pop()
                    matched_right.append(node_2)

                colors1[node_1] = self.__calculate_distance_of_sub_tree(
                    node_1,
                    tree1.lT,
                    node_2,
                    tree2.lT,
                    btrc,
                    corres1,
                    corres2,
                    delta_tmp,
                    self.norm_dict[norm],
                    tree1.get_norm(node_1),
                    tree2.get_norm(node_2),
                )
                colors2[node_2] = colors1[node_1]
                colors1[l_node_1] = colors1[node_1]
                colors2[l_node_2] = colors2[node_2]

    else:
        for m in btrc:
            if m._left != -1 and m._right != -1:
                node_1 = tree1.lT.get_chain_of_node(corres1[m._left])[0]
                node_2 = tree2.lT.get_chain_of_node(corres2[m._right])[0]
                if (
                    tree1.lT.get_chain_of_node(node_1)[0] == node_1
                    or tree2.lT.get_chain_of_node(node_2)[0] == node_2
                    and (node_1 not in colors1 or node_2 not in colors2)
                ):
                    matched_left.append(node_1)
                    l_node_1 = tree1.lT.get_chain_of_node(node_1)[-1]
                    matched_left.append(l_node_1)
                    matched_right.append(node_2)
                    l_node_2 = tree2.lT.get_chain_of_node(node_2)[-1]
                    matched_right.append(l_node_2)
                    colors1[node_1] = (
                        self.__calculate_distance_of_sub_tree(
                            node_1,
                            tree1.lT,
                            node_2,
                            tree2.lT,
                            btrc,
                            corres1,
                            corres2,
                            delta_tmp,
                            self.norm_dict[norm],
                            tree1.get_norm(node_1),
                            tree2.get_norm(node_2),
                        )
                    )
                    colors2[node_2] = colors1[node_1]
                    colors1[tree1.lT.get_chain_of_node(node_1)[-1]] = (
                        colors1[node_1]
                    )
                    colors2[tree2.lT.get_chain_of_node(node_2)[-1]] = (
                        colors2[node_2]
                    )

                    if tree1.lT.get_chain_of_node(node_1)[-1] != node_1:
                        matched_left.append(
                            tree1.lT.get_chain_of_node(node_1)[-1]
                        )
                    if tree2.lT.get_chain_of_node(node_2)[-1] != node_2:
                        matched_right.append(
                            tree2.lT.get_chain_of_node(node_2)[-1]
                        )
    if ax is None:
        fig, ax = plt.subplots(nrows=1, ncols=2)
    cmap = colormaps[colormap]
    if vmin is None:
        vmin = np.percentile(list(colors1.values()), 5)
    if vmax is None:
        vmax = np.percentile(list(colors1.values()), 95)
    c_norm = mcolors.Normalize(vmin, vmax)
    colors1 = {c: cmap(c_norm(v)) for c, v in colors1.items()}
    colors2 = {c: cmap(c_norm(v)) for c, v in colors2.items()}
    tree1.lT.plot_subtree(
        tree1.lT.get_ancestor_at_t(n1),
        end_time=end_time1,
        size=size,
        color_of_nodes=colors1,
        color_of_edges=colors1,
        default_color=default_color,
        lw=lw,
        ax=ax[0],
    )
    tree2.lT.plot_subtree(
        tree2.lT.get_ancestor_at_t(n2),
        end_time=end_time2,
        size=size,
        color_of_nodes=colors2,
        color_of_edges=colors2,
        default_color=default_color,
        lw=lw,
        ax=ax[1],
    )
    return ax[0].get_figure(), ax

remove_embryo

remove_embryo(key: str)

Removes the embryo from the manager.

Parameters:

Name Type Description Default

key

str

The name of the lineagetree to be removed

required

Raises:

Type Description
IndexError

If there is no such lineagetree

Source code in src/lineagetree/lineage_tree_manager.py
def remove_embryo(self, key: str):
    """Removes the embryo from the manager.

    Parameters
    ----------
    key : str
        The name of the lineagetree to be removed

    Raises
    ------
    IndexError
        If there is no such lineagetree
    """
    self.lineagetrees.pop(key, None)

write

write(fname: str)

Saves the manager

Parameters:

Name Type Description Default

fname

str

The path and name of the file that is to be saved.

required
Source code in src/lineagetree/lineage_tree_manager.py
def write(self, fname: str):
    """Saves the manager

    Parameters
    ----------
    fname : str
        The path and name of the file that is to be saved.
    """
    if os.path.splitext(fname)[-1].upper() != ".LTM":
        fname = os.path.extsep.join((fname, "lTM"))
    for _, lT in self:
        if hasattr(lT, "_protected_predecessor"):
            del lT._protected_predecessor
        if hasattr(lT, "_protected_successor"):
            del lT._protected_successor
        if hasattr(lT, "_protected_time"):
            del lT._protected_time
    with open(fname, "bw") as f:
        pkl.dump(self, f)
        f.close()