Ejemplo n.º 1
0
def _render_parasite_branches(fig: plot_tools.FigureWrapper, node: tree.Node,
                              recon_obj: recon.Reconciliation,
                              host_lookup: dict, parasite_lookup: dict):
    """
    Very basic branch drawing
    :param fig: Figure object that visualizes trees using MatplotLib
    :param node: Node object representing the parasite event being rendered
    :param recon_obj: Reconciliation object that represents an edge-to-edge mapping from  a parasite tree to a host tree
    :param host_lookup: Dictionary with host node names as the key and host node objects as the values
    :param parasite_lookup: Dictionary with parasite node names as the key and parasite node objects as the values
    """
    node_pos = plot_tools.Position(node.layout.x, node.layout.y)

    left_node, right_node = _get_children(node, recon_obj, parasite_lookup)

    right_pos = plot_tools.Position(right_node.layout.x, right_node.layout.y)

    mapping_node = recon_obj.mapping_of(node.name)
    event = recon_obj.event_of(mapping_node)

    if event.event_type is recon.EventType.COSPECIATION:
        _render_cospeciation_branch(node, host_lookup, parasite_lookup,
                                    recon_obj, fig)
    elif event.event_type is recon.EventType.DUPLICATION:
        _connect_children(node, host_lookup, parasite_lookup, recon_obj, fig)
    elif event.event_type is recon.EventType.TRANSFER:
        _render_transfer_branch(node_pos, right_pos, fig, node, host_lookup,
                                recon_obj, right_node)
        _connect_child_to_parent(node, left_node, host_lookup, recon_obj, fig)
    else:
        raise ValueError('%s is not an known event type' % event.event_type)
Ejemplo n.º 2
0
def _is_sharing_track(node: tree.Node, host_name: str,
                      recon_obj: recon.Reconciliation):
    """
    Determines if a node is sharing it's horizontal track with its children
    :param node: Node object representing a parasite event
    :param host_name: Name of host node
    :param recon_obj: Reconciliation Object
    """
    left_host_name = recon_obj.mapping_of(node.left_node.name).host
    right_host_name = recon_obj.mapping_of(node.right_node.name).host

    return host_name == left_host_name or host_name == right_host_name
Ejemplo n.º 3
0
def dict_to_reconciliation(old_recon: Dict[Tuple, List],
                           event_scores: Dict[tuple, float] = None):
    """
    Convert the old reconciliation graph format to Reconciliation.

    Example of old format:
    old_recon = {
        ('n0', 'm2'): [('S', ('n2', 'm3'), ('n1', 'm4'))],
        ('n1', 'm4'): [('C', (None, None), (None, None))],
        ('n2', 'm3'): [('T', ('n3', 'm3'), ('n4', 'm1'))],
        ('n3', 'm3'): [('C', (None, None), (None, None))],
        ('n4', 'm1'): [('C', (None, None), (None, None))],
    }
    """
    roots = _find_roots(old_recon)
    if len(roots) > 1:
        raise ValueError("old_recon has many roots")
    root = roots[0]
    recon = Reconciliation(root)
    event = None
    for mapping in old_recon:
        host, parasite = mapping
        if len(old_recon[mapping]) != 1:
            raise ValueError(
                'old_recon mapping node has no or multiple events')
        event_tuple = old_recon[mapping][0]
        etype, left, right = event_tuple
        mapping_node = MappingNode(host, parasite)
        if etype in 'SDT':
            left_parasite, left_host = left
            right_parasite, right_host = right
            left_mapping = MappingNode(left_parasite, left_host)
            right_mapping = MappingNode(right_parasite, right_host)
            if etype == 'S':
                event = Cospeciation(left_mapping, right_mapping)
            if etype == 'D':
                event = Duplication(left_mapping, right_mapping)
            if etype == 'T':
                event = Transfer(left_mapping, right_mapping)
        elif etype == 'L':
            child_parasite, child_host = left
            child_mapping = MappingNode(child_parasite, child_host)
            event = Loss(child_mapping)
        elif etype == 'C':
            event = TipTip()
        else:
            raise ValueError('%s not in "SDTLC"' % etype)
        if event_scores is not None:
            event._freq = event_scores[event_tuple]
        recon.set_event(mapping_node, event)
    return recon
Ejemplo n.º 4
0
def _get_children(node: tree.Node, recon_obj: recon.Reconciliation,
                  parasite_lookup: dict):
    """
    Gets the children of a node in the order they appear in the mapping node.
    :param node: Node object representing a parasite event
    :param recon_obj: Reconciliation Object
    :param parasite_lookup: Dictionary with parasite node names as the key and parasite node objects as the values
    :return A tuple consisting of the left node and right node
    """
    mapping_node = recon_obj.mapping_of(node.name)
    event = recon_obj.event_of(mapping_node)
    left_mapping_node = event.left
    right_mapping_node = event.right
    left_node_name = left_mapping_node.parasite
    right_node_name = right_mapping_node.parasite

    left_node = parasite_lookup[left_node_name]
    right_node = parasite_lookup[right_node_name]

    return left_node, right_node
Ejemplo n.º 5
0
def _populate_host_tracks(node: tree.Node, recon_obj: recon.Reconciliation,
                          host_lookup: dict):
    """
    :param node: Node object
    :param recon_obj: Reconciliation object that represents an edge-to-edge mapping from  a parasite tree to a host tree
    :param host_lookup: Dictionary with host node names as the key and host node objects as the values
    """
    mapping_node = recon_obj.mapping_of(node.name)
    event = recon_obj.event_of(mapping_node)
    host_name = mapping_node.host
    host_node = host_lookup[host_name]

    if not (event.event_type is recon.EventType.DUPLICATION
            or event.event_type is recon.EventType.TRANSFER):
        host_node.update_count()
    else:
        if not (_is_sharing_track(node, host_name, recon_obj)):
            host_node.update_count()

    if not (node.is_leaf()):
        _populate_host_tracks(node.left_node, recon_obj, host_lookup)
        _populate_host_tracks(node.right_node, recon_obj, host_lookup)
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
def _fix_transfer(node: tree.Node,
                  left_node,
                  right_node: tree.Node,
                  host_node: tree.Node,
                  host_lookup: dict,
                  parasite_lookup: dict,
                  recon_obj: recon.Reconciliation,
                  node_col: float = None,
                  offset_number: int = 1):
    """
    Checks to see in tranfer node is inconsistent and the tries to fix node if it can be slid down the host edge
    The tries to push a given node forward if possible to correct the assumed inconsistency
    :param node: Node object representing the parasite event being rendered
    :param node: Right node of the node object
    :param left_node: Left node of the node object
    :param right_node: Right node of the node object
    :param host_node: Node object represeting a host that the parasite node is mapped to
    :param host_lookup: Dictionary with host node names as the key and host node objects as the values
    :param parasite_lookup: Dictionary with parasite node names as the key and parasite 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 node_col: Column of the node, used when function is called recursively to check the next available transfer spot
    :param offset_number: Used to push node to an available transfer spot
    """
    min_col = host_lookup[recon_obj.mapping_of(
        right_node.name).host].parent_node.layout.col
    max_col = host_node.layout.col
    node_col = node.layout.col
    max_col = min(host_node.layout.col, left_node.layout.col)
    if not (node_col):
        node_col = node.layout.col

    # Checks to see if transfer is inconsistent and if the inconsistency can be fixed by sliding the transfer node down the host edge
    if min_col >= node_col and min_col < max_col and not (_is_sharing_track(
            node, host_node.name, recon_obj)):
        node.set_layout(col=min_col + 0.5, x=min_col + 0.5)
    if min_col < max_col:
        new_value = min_col + render_settings.PUSHED_NODE_OFFSET * offset_number
        if _is_col_taken(new_value, host_lookup, parasite_lookup):
            _fix_transfer(node,
                          left_node,
                          right_node,
                          host_node,
                          host_lookup,
                          parasite_lookup,
                          recon_obj,
                          node_col=new_value,
                          offset_number=offset_number + 1)
        else:
            node.set_layout(col=new_value, x=new_value)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
def _render_cospeciation_branch(node: tree.Node, host_lookup: dict,
                                parasite_lookup: dict,
                                recon_obj: recon.Reconciliation,
                                fig: plot_tools.FigureWrapper):
    """
    Renders the cospeciation branch.
    :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 parasite_lookup: Dictionary with parasite node names as the key and parasite 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
    """
    left_node, right_node = _get_children(node, recon_obj, parasite_lookup)

    node_pos = plot_tools.Position(node.layout.x, node.layout.y)
    left_pos = plot_tools.Position(left_node.layout.x, left_node.layout.y)
    right_pos = plot_tools.Position(right_node.layout.x, right_node.layout.y)

    mapping_node = recon_obj.mapping_of(node.name)
    host_node = host_lookup[mapping_node.host]

    # Update h_track
    host_node.get_and_update_track(tree.Track.HORIZONTAL)

    left_mapping_node = recon_obj.mapping_of(left_node.name)
    left_host_node = host_lookup[left_mapping_node.host]

    right_mapping_node = recon_obj.mapping_of(right_node.name)
    right_host_node = host_lookup[right_mapping_node.host]
    # Draw left node
    offset = host_node.layout.offset
    if host_node.left_node.name == left_host_node.name:
        _render_curved_line_to(node_pos, left_pos, fig)
        if host_node.layout.lower_v_track < (host_node.layout.x -
                                             node_pos.x) / offset:
            host_node.layout.lower_v_track += (host_node.layout.x -
                                               node_pos.x) / offset + offset
    else:
        stop_row = host_node.left_node.layout.row
        _connect_child_to_parent(node,
                                 left_node,
                                 host_lookup,
                                 recon_obj,
                                 fig,
                                 stop_row=stop_row)

    # Draw Right node
    if host_node.right_node.name == right_host_node.name:
        _render_curved_line_to(node_pos, right_pos, fig)
        if host_node.layout.upper_v_track < (host_node.layout.x -
                                             node_pos.x) / offset:
            host_node.layout.upper_v_track += (host_node.layout.x -
                                               node_pos.x) / offset + offset
    else:
        stop_row = host_node.right_node.layout.row
        _connect_child_to_parent(node,
                                 right_node,
                                 host_lookup,
                                 recon_obj,
                                 fig,
                                 stop_row=stop_row)
Ejemplo n.º 10
0
def _render_parasite_helper(fig: plot_tools.FigureWrapper, node: tree.Node,
                            recon_obj: recon.Reconciliation, host_lookup: dict,
                            parasite_lookup: dict, show_internal_labels: bool,
                            show_freq: bool, font_size: float,
                            longest_host_name: int):
    """
    Helper function for rendering the parasite tree.
    :param fig: Figure object that visualizes trees using MatplotLib
    :param node: Node object representing the parasite event being rendered
    :param recon_obj: Reconciliation object that represents an edge-to-edge mapping from  a parasite tree to a host tree
    :param host_lookup: Dictionary with host node names as the key and host node objects as the values
    :param parasite_lookup: Dictionary with parasite node names as the key and parasite node objects as the values
    :param show_internal_labels: Boolean that determines whether or not the internal labels are shown
    :param show_freq: Boolean that determines wheter or not the frequencies are shown
    :param font_size: Font size for the text of the tips and internal nodes of the tree
    :param longest_host_name: The number of symbols in the longest host tree tip name
    """
    # mapping_node is of type MappingNode which associates
    # a parasite to a host in a reconciliation
    mapping_node = recon_obj.mapping_of(node.name)

    # A reconciliation has an event_of method which is an object of
    # type Event.
    event = recon_obj.event_of(mapping_node)

    host_name = mapping_node.host

    # host_lookup is a dictionary computed in the Tree class
    # that associates a host name (a string) with the correspond node
    # object for that host.  The node object contains layout information
    # which we need here.
    host_node = host_lookup[host_name]

    # Set parasite node layout
    host_row = host_node.layout.row
    # host_col = host_node.layout.col
    # host_x = host_node.layout.x
    host_y = host_node.layout.y
    node.set_layout(row=host_row, x=node.layout.col, y=host_y)

    # Render parasite node and recurse if not a leaf
    if node.is_leaf():
        node.layout.y += host_node.get_and_update_track(
            tree.Track.HORIZONTAL) * host_node.layout.offset
        _render_parasite_node(fig, node, event, font_size, longest_host_name)
        return

    # If the Node is in their own track, change their position
    if not (_is_sharing_track(node, host_name, recon_obj)):
        node.layout.y += host_node.layout.h_track * host_node.layout.offset

    left_node, right_node = _get_children(node, recon_obj, parasite_lookup)

    _render_parasite_helper(fig, left_node, recon_obj, host_lookup,
                            parasite_lookup, show_internal_labels, show_freq,
                            font_size, longest_host_name)
    _render_parasite_helper(fig, right_node, recon_obj, host_lookup,
                            parasite_lookup, show_internal_labels, show_freq,
                            font_size, longest_host_name)

    # Checking to see if left node is mapped to the same host node as parent
    if node.layout.row == left_node.layout.row:
        node.set_layout(y=left_node.layout.y)
    elif node.layout.row == right_node.layout.row:
        node.set_layout(y=right_node.layout.y)
    elif event.event_type is recon.EventType.TRANSFER:
        node.layout.y = host_node.layout.y + host_node.layout.h_track * host_node.layout.offset

    #Checks to see if transfer node is inconsistent and if it can be fixed
    if event.event_type is recon.EventType.TRANSFER:
        min_col = host_lookup[recon_obj.mapping_of(
            right_node.name).host].parent_node.layout.col
        if min_col >= node.layout.col:
            _fix_transfer(node, left_node, right_node, host_node, host_lookup,
                          parasite_lookup, recon_obj)

    _render_parasite_branches(fig, node, recon_obj, host_lookup,
                              parasite_lookup)
    _render_parasite_node(fig, node, event, font_size, longest_host_name,
                          show_internal_labels, show_freq)