def _draw_host_handle(fig: plot_tools.FigureWrapper, root: tree.Node):
    """
    Draw edge leading to root of host tree.
    :param fig: Figure object that visualizes trees using MatplotLib
    :param root: The root node of a tree object
    """
    fig.line((0, root.layout.y), (root.layout.x, root.layout.y),
             render_settings.HOST_EDGE_COLOR)
def _render_curved_line_to(node_pos: plot_tools.Position,
                           other_pos: plot_tools.Position,
                           fig: plot_tools.FigureWrapper):
    """
    Renders a curved line from one point to another
    :param node_pos: x and y position of a node
    :param other_pos: x and y position of another node
    :param fig: Figure object that visualizes trees using MatplotLib
    """
    mid_pos = plot_tools.Position(node_pos.x, other_pos.y)
    fig.line(node_pos, mid_pos, render_settings.PARASITE_EDGE_COLOR)
    fig.line(mid_pos, other_pos, render_settings.PARASITE_EDGE_COLOR)
def _connect_child_to_parent(node: tree.Node,
                             child_node: tree.Node,
                             host_lookup: dict,
                             recon_obj: recon.Reconciliation,
                             fig: plot_tools.FigureWrapper,
                             stop_row: float = None):
    """
    Connects a child node to its parent node
    :param node: Node object representing a parasite event
    :param child_node: The child node object of a given node
    :param host_lookup: Dictionary with host node names as the key and host node objects as the values
    :param recon_obj: Reconciliation object that represents an edge-to-edge mapping from  a parasite tree to a host tree
    :param fig: Figure object that visualizes trees using MatplotLib
    :param stop_row: row number to stop line drawing on
    """
    mapping_node = recon_obj.mapping_of(child_node.name)
    host_node = host_lookup[mapping_node.host]

    if stop_row == None:
        stop_row = node.layout.row

    current_pos = plot_tools.Position(child_node.layout.x, child_node.layout.y)

    while host_node.layout.row != stop_row and host_node.parent_node:
        parent_node = host_node.parent_node
        if parent_node.layout.row < host_node.layout.row:
            v_track = parent_node.get_and_update_track(
                tree.Track.UPPER_VERTICAL)
        else:
            v_track = parent_node.get_and_update_track(
                tree.Track.LOWER_VERTICAL)
            while v_track < parent_node.layout.upper_v_track:
                v_track = parent_node.get_and_update_track(
                    tree.Track.LOWER_VERTICAL)
        h_track = parent_node.get_and_update_track(tree.Track.HORIZONTAL)
        offset = parent_node.layout.offset

        sub_parent_pos = plot_tools.Position(parent_node.layout.x - (offset * v_track), \
            parent_node.layout.y + (offset * h_track))

        _render_loss_branch(sub_parent_pos, current_pos, fig)

        host_node = parent_node
        current_pos = sub_parent_pos

    node_pos = plot_tools.Position(node.layout.x, node.layout.y)
    mid_pos = plot_tools.Position(node_pos.x, current_pos.y)

    fig.line(node_pos, mid_pos, render_settings.PARASITE_EDGE_COLOR)
    fig.line(mid_pos, current_pos, render_settings.PARASITE_EDGE_COLOR)
def _render_loss_branch(node_pos: plot_tools.Position,
                        next_pos: plot_tools.Position,
                        fig: plot_tools.FigureWrapper):
    """
    Renders a loss branch given a two positions
    :param node_pos: x and y position of a node
    :param next_pos: x and y position of another node
    :param fig: Figure object that visualizes trees using MatplotLib
    """
    # Create vertical line to next node
    mid_pos = plot_tools.Position(node_pos.x, next_pos.y)
    fig.line(node_pos,
             mid_pos,
             render_settings.LOSS_EDGE_COLOR,
             linestyle='--')
    fig.line(mid_pos, next_pos, render_settings.PARASITE_EDGE_COLOR)
def _render_host_helper(fig: plot_tools.FigureWrapper, node: tree.Node,
                        show_internal_labels: bool, font_size: float,
                        host_tree: tree.Tree):
    """
    Helper function for rendering the host tree.
    :param fig: Figure object that visualizes trees using MatplotLib
    :param node: Host Node object that will be rendered
    :param show_internal_labels: Boolean that determines whether or not the internal labels are shown
    :param font_size: Font size for the text of the tips and internal nodes of the tree
    :param host_tree: Tree object representing a Host Tree
    """
    host_tree.pos_dict[(node.layout.row, node.layout.col)] = node

    node_pos = plot_tools.Position(node.layout.x, node.layout.y)

    if node.is_leaf():
        text_offset = (node_pos.x + render_settings.TIP_TEXT_OFFSET_X,
                       node_pos.y)
        if node.layout.node_count == 0:
            fig.text_v2(text_offset,
                        node.name,
                        render_settings.HOST_NODE_COLOR,
                        size=font_size,
                        vertical_alignment=render_settings.TIP_ALIGNMENT)
        else:
            fig.text_v2(text_offset,
                        node.name,
                        render_settings.HOST_NODE_COLOR,
                        size=font_size,
                        vertical_alignment=render_settings.TIP_ALIGNMENT)
    else:
        fig.dot(node_pos,
                col=render_settings.HOST_NODE_COLOR)  # Render host node
        if show_internal_labels:
            color = plot_tools.transparent_color(
                render_settings.HOST_NODE_COLOR,
                render_settings.INTERNAL_NODE_ALPHA)
            text_xy = (node_pos.x, node_pos.y)
            fig.text_v2(text_xy,
                        node.name,
                        color,
                        size=font_size,
                        border_col=render_settings.HOST_NODE_BORDER_COLOR)
        left_x, left_y = node.left_node.layout.x, node.left_node.layout.y
        right_x, right_y = node.right_node.layout.x, node.right_node.layout.y
        fig.line(node_pos, (node_pos.x, left_y),
                 render_settings.HOST_EDGE_COLOR)
        fig.line(node_pos, (node_pos.x, right_y),
                 render_settings.HOST_EDGE_COLOR)
        fig.line((node_pos.x, left_y), (left_x, left_y),
                 render_settings.HOST_EDGE_COLOR)
        fig.line((node_pos.x, right_y), (right_x, right_y),
                 render_settings.HOST_EDGE_COLOR)
        _render_host_helper(fig, node.left_node, show_internal_labels,
                            font_size, host_tree)
        _render_host_helper(fig, node.right_node, show_internal_labels,
                            font_size, host_tree)
def _render_transfer_branch(node_pos: plot_tools.Position,
                            right_pos: plot_tools.Position,
                            fig: plot_tools.FigureWrapper, node: tree.Node,
                            host_lookup: dict, recon_obj: recon.Reconciliation,
                            right_node: tree.Node):
    """
    Renders a transfer branch
    :param node_xy: x and y position of a node
    :param right_pos: x and y position of the right child of a node
    :param fig: Figure object that visualizes trees using MatplotLib
    :param node: Node object representing the parasite event being rendered
    :param host_lookup: Dictionary with host node names as the key and host node objects as the values
    :param recon_obj: Reconciliation object that represents an edge-to-edge mapping from  a parasite tree to a host tree
    :param right_node: The right node object of node
    """

    child_mapping_node = recon_obj.mapping_of(right_node.name)
    child_host_node = host_lookup[child_mapping_node.host]

    # Check temporal consistency of transfer event
    if child_host_node.parent_node.layout.col < node.layout.col:
        # Draw right node, which is transfered
        mid_pos = plot_tools.Position(node_pos.x,
                                      right_pos.y)  # xy coords of midpoint
        y_midpoint = abs(
            mid_pos.y +
            node_pos.y) / 2  # value of midpoint between mid_xy and parent node

        # Determine if transfer is upwards or downwards, and draw triangle accordingly
        is_upwards = True if y_midpoint < mid_pos.y else False
        arrow_pos = plot_tools.Position(node_pos.x, y_midpoint)
        if is_upwards:
            fig.triangle(arrow_pos, render_settings.PARASITE_EDGE_COLOR)
        else:
            fig.triangle(arrow_pos,
                         render_settings.PARASITE_EDGE_COLOR,
                         rotation=render_settings.DOWN_ARROW_ROTATION)

        # Draw branch to midpoint, then draw branch to child
        fig.line(node_pos, mid_pos, render_settings.PARASITE_EDGE_COLOR)
        fig.line(mid_pos, right_pos, render_settings.PARASITE_EDGE_COLOR)
    else:
        transfer_edge_color = plot_tools.transparent_color(
            render_settings.PARASITE_EDGE_COLOR,
            render_settings.TRANSFER_TRANSPARENCY)
        fig.arrow_segment(node_pos, right_pos, transfer_edge_color)
        fig.line(node_pos, right_pos, transfer_edge_color)