Skip to content

visualization

Matplotlib-based visualization of phylogenetic trees.

tree_vis

Species and gene tree visualization.

assign_species_colors(tree: Tree) -> dict

Assign a unique color to each (extant) species in a species tree.

Parameters:

Name Type Description Default
tree Tree

The species tree with uniquely labeled (non-loss) leaves.

required

Returns:

Type Description
dict

A dictionary containing the labels of the extant species as keys and the assigned colors as values.

Source code in asymmetree/visualization/tree_vis.py
def assign_species_colors(tree: Tree) -> dict:
    """Assign a unique color to each (extant) species in a species tree.

    Args:
        tree: The species tree with uniquely labeled (non-loss) leaves.

    Returns:
        A dictionary containing the labels of the extant species as keys and the assigned colors as
            values.
    """
    return _assign_cmap({v.label for v in tree.leaves() if v.event != "L"})

assign_gene_colors(tree: Tree, species_colors: dict | None = None) -> dict

Assign a color to each (extant) gene in a gene tree according to its species.

Parameters:

Name Type Description Default
tree Tree

The gene tree whose (non-loss) leaves have the 'reconc' attribute, i.e, the information to which species they belong.

required
species_colors dict | None

A dictionary containing the values of the 'color' attribute appearing in the tree as keys and assigned colors as values.

None

Returns:

Type Description
dict

A dictionary containing the labels of the extant genes as keys and the assigned colors as values.

Source code in asymmetree/visualization/tree_vis.py
def assign_gene_colors(tree: Tree, species_colors: dict | None = None) -> dict:
    """Assign a color to each (extant) gene in a gene tree according to its species.

    Args:
        tree: The gene tree whose (non-loss) leaves have the 'reconc' attribute, i.e, the
            information to which species they belong.
        species_colors: A dictionary containing the values of the 'color' attribute appearing in the
            tree as keys and assigned colors as values.

    Returns:
        A dictionary containing the labels of the extant genes as keys and the assigned colors as
            values.
    """
    if species_colors is None:
        species_colors = _assign_cmap({v.reconc for v in tree.leaves() if v.event != "L"})

    return {v.label: species_colors[v.reconc] for v in tree.leaves() if v.event != "L"}

assign_colors(species_tree: Tree, gene_tree: Tree) -> tuple[dict, dict]

Assign a color to each (extant) species and gene.

Parameters:

Name Type Description Default
species_tree Tree

The species tree with uniquely labeled (non-loss) leaves.

required
gene_tree Tree

The gene tree whose (non-loss) leaves have the 'reconc' attribute, i.e, the information to which species they belong, that furthermore appear as labels of the (non-loss) leaves in the species tree.

required

Returns:

Type Description
dict

A dict containing the labels of the extant species as keys and the assigned colors as values.

dict

A dict containing the labels of the extant genes as keys and the assigned colors as values.

Source code in asymmetree/visualization/tree_vis.py
def assign_colors(species_tree: Tree, gene_tree: Tree) -> tuple[dict, dict]:
    """Assign a color to each (extant) species and gene.

    Args:
        species_tree: The species tree with uniquely labeled (non-loss) leaves.
        gene_tree: The gene tree whose (non-loss) leaves have the 'reconc' attribute, i.e, the
            information to which species they belong, that furthermore appear as labels of the
            (non-loss) leaves in the species tree.

    Returns:
        A `dict` containing the labels of the extant species as keys and the assigned colors as
            values.
        A `dict` containing the labels of the extant genes as keys and the assigned colors as
            values.
    """
    species_colors = assign_species_colors(species_tree)

    return species_colors, assign_gene_colors(gene_tree, species_colors=species_colors)

visualize(tree: Tree, *, backend: Literal['matplotlib', 'plotly'] = 'matplotlib', path: str | os.PathLike | None = None, show: bool = False, edge_length_mode: Literal['attr', 'uniform', 'even', 'rank'] = 'attr', edge_length_attr: str = 'dist', layout_mode: Literal['horizontal', 'vertical', 'circular'] = 'horizontal', node_rank_mode: Literal['mean', 'first', 'last', 'node'] = 'mean', tree_style: TreeStyle | None = None, color_dict: dict | None = None, species_info: bool = False, distance_axis: bool = False, scale_symbols: float = 1.0, fontsize: str | float | int = 'medium', save_as: str | os.PathLike | None = None, **renderer_kwargs: Any) -> tuple[Figure, Axes] | PlotlyFigure

Render a tree.

This function calls the plot_tree function in tralda for rendering the tree according to the specified backend and options. If no tree_style is provided, the default AsymmeTree style is used: - Leaf colors are determined by the color_dict if provided. - Node symbols are determined by the event type: - Leaf nodes are represented by a circle with a dot inside. - Speciation events are represented by a circle. - Duplication events are represented by a square. - Loss events are represented by a cap. - Transfer events are represented by a triangle. - Gene conversion events are represented by a star.

Parameters:

Name Type Description Default
tree Tree

The tree to render.

required
backend Literal['matplotlib', 'plotly']

"matplotlib" (default) or "plotly".

'matplotlib'
path str | PathLike | None

If given, save the resulting figure to this path. For the matplotlib backend the format is inferred from the file extension by :meth:~matplotlib.figure.Figure.savefig (e.g. .png, .pdf, .svg). For the plotly backend, a .html extension writes a self-contained interactive file via :meth:~plotly.graph_objects.Figure.write_html; any other extension writes a static image via :meth:~plotly.graph_objects.Figure.write_image.

None
show bool

If True, display the figure (fig.show()) after rendering.

False
edge_length_mode Literal['attr', 'uniform', 'even', 'rank']

How edge lengths are determined. See tralda documentation for details.

'attr'
edge_length_attr str

Node attribute read as edge length in "attr" mode.

'dist'
layout_mode Literal['horizontal', 'vertical', 'circular']

Tree orientation. See tralda documentation for details.

'horizontal'
node_rank_mode Literal['mean', 'first', 'last', 'node']

How the rank of internal nodes is derived from their children. See tralda documentation for details.

'mean'
tree_style TreeStyle | None

Styling configuration. When None the AsymmeTree default style is used.

None
color_dict dict | None

For the default style function, a dictionary containing as values the assigned color for each label of the (non-loss) leaves. The default is None, in which case all leaves are colored white.

None
species_info bool

If True, append the reconciliation information (the 'reconc' attribute) to the label of each (non-loss) leaf for which it is available.

False
distance_axis bool

If True, show an x-axis with the accumulated edge lengths from the root. Only supported for the matplotlib backend with layout_mode="horizontal" and edge_length_mode="attr". Depth rescaling is disabled in this case.

False
scale_symbols float

Adjust the size of the event type symbols.

1.0
fontsize str | float | int

Adjust the size of the text.

'medium'
save_as str | PathLike | None

Deprecated alias for path. Use path instead.

None
**renderer_kwargs Any

Additional keyword arguments forwarded to the renderer constructor (e.g. figsize / ax for matplotlib, width / height / hover_attrs for plotly).

{}

Returns:

Type Description
tuple[Figure, Axes] | Figure

(fig, ax) for the matplotlib backend, or a plotly Figure for the plotly backend.

Source code in asymmetree/visualization/tree_vis.py
def visualize(
    tree: Tree,
    *,
    backend: Literal["matplotlib", "plotly"] = "matplotlib",
    path: str | os.PathLike | None = None,
    show: bool = False,
    edge_length_mode: Literal["attr", "uniform", "even", "rank"] = "attr",
    edge_length_attr: str = "dist",
    layout_mode: Literal["horizontal", "vertical", "circular"] = "horizontal",
    node_rank_mode: Literal["mean", "first", "last", "node"] = "mean",
    tree_style: TreeStyle | None = None,
    color_dict: dict | None = None,
    species_info: bool = False,
    distance_axis: bool = False,
    scale_symbols: float = 1.0,
    fontsize: str | float | int = "medium",
    save_as: str | os.PathLike | None = None,
    **renderer_kwargs: Any,
) -> tuple[Figure, Axes] | PlotlyFigure:
    """Render a tree.

    This function calls the ``plot_tree`` function in tralda for rendering the tree according to the
    specified backend and options.
    If no ``tree_style`` is provided, the default AsymmeTree style is used:
    - Leaf colors are determined by the ``color_dict`` if provided.
    - Node symbols are determined by the event type:
        - Leaf nodes are represented by a circle with a dot inside.
        - Speciation events are represented by a circle.
        - Duplication events are represented by a square.
        - Loss events are represented by a cap.
        - Transfer events are represented by a triangle.
        - Gene conversion events are represented by a star.

    Args:
        tree: The tree to render.
        backend: ``"matplotlib"`` (default) or ``"plotly"``.
        path: If given, save the resulting figure to this path. For the matplotlib backend the
            format is inferred from the file extension by
            :meth:`~matplotlib.figure.Figure.savefig` (e.g. ``.png``, ``.pdf``, ``.svg``). For the
            plotly backend, a ``.html`` extension writes a self-contained interactive file via
            :meth:`~plotly.graph_objects.Figure.write_html`; any other extension writes a static
            image via :meth:`~plotly.graph_objects.Figure.write_image`.
        show: If ``True``, display the figure (``fig.show()``) after rendering.
        edge_length_mode: How edge lengths are determined. See tralda documentation for details.
        edge_length_attr: Node attribute read as edge length in ``"attr"`` mode.
        layout_mode: Tree orientation. See tralda documentation for details.
        node_rank_mode: How the rank of internal nodes is derived from their children. See tralda
            documentation for details.
        tree_style: Styling configuration. When ``None`` the AsymmeTree default style is used.
        color_dict: For the default style function, a dictionary containing as values the assigned
            color for each label of the (non-loss) leaves. The default is None, in which case all
            leaves are colored white.
        species_info: If True, append the reconciliation information (the 'reconc' attribute) to
            the label of each (non-loss) leaf for which it is available.
        distance_axis: If True, show an x-axis with the accumulated edge lengths from the root.
            Only supported for the matplotlib backend with ``layout_mode="horizontal"`` and
            ``edge_length_mode="attr"``. Depth rescaling is disabled in this case.
        scale_symbols: Adjust the size of the event type symbols.
        fontsize: Adjust the size of the text.
        save_as: Deprecated alias for ``path``. Use ``path`` instead.
        **renderer_kwargs: Additional keyword arguments forwarded to the renderer constructor
            (e.g. ``figsize`` / ``ax`` for matplotlib, ``width`` / ``height`` / ``hover_attrs`` for
            plotly).

    Returns:
        ``(fig, ax)`` for the matplotlib backend, or a plotly ``Figure`` for the plotly backend.
    """
    if save_as is not None:
        if path is not None:
            raise ValueError("Cannot specify both 'path' and 'save_as'. Use 'path' only.")
        path = save_as

    if distance_axis:
        if backend != "matplotlib" or layout_mode != "horizontal" or edge_length_mode != "attr":
            raise ValueError(
                "distance_axis requires backend='matplotlib', layout_mode='horizontal' and "
                "edge_length_mode='attr'."
            )
        if renderer_kwargs.setdefault("rescale_depth", False):
            raise ValueError("distance_axis cannot be combined with rescale_depth=True.")

    if species_info:
        tree = _with_species_info_labels(tree)

    if tree_style is None:
        tree_style = TreeStyle(style_fn=partial(_default_style_fn, color_map=color_dict))
    elif color_dict is not None:
        raise ValueError("Cannot specify color_dict when providing a custom tree_style.")

    # the default symbol size in tralda is 9, so we scale it by the scale_symbols factor
    base_node_style = NodeStyle(symbol_size=9.0 * scale_symbols, label_fontsize=fontsize)
    tree_style.default = tree_style.default.overlay(base_node_style)

    # with a distance axis, saving and showing must happen after the axis has been added
    result = plot_tree(
        tree,
        backend=backend,
        path=None if distance_axis else path,
        show=False if distance_axis else show,
        edge_length_mode=edge_length_mode,
        edge_length_attr=edge_length_attr,
        layout_mode=layout_mode,
        node_rank_mode=node_rank_mode,
        tree_style=tree_style,
        **renderer_kwargs,
    )

    if distance_axis:
        fig, ax = result
        _add_distance_axis(ax, fontsize)
        if path is not None:
            fig.savefig(path, bbox_inches="tight")
        if show:
            fig.show()

    return result