コード例 #1
0
ファイル: ete_tree.py プロジェクト: eulertx/treeomics
def create_tree(tree,
                tree_root_key,
                filepath,
                patient,
                phylogeny,
                drivers=None):
    """
    Takes a networkx tree and creates an ete3 tree and creates a PDF, SVG or PNG according to the given filename at
    the given path
    :param tree: inferred cancer phylogeny encoded as networkx tree
    :param tree_root_key: key of root in networkx tree
    :param filepath: path to output file (excluding file extension)
    :param patient: data structure around patient
    :param phylogeny: inferred cancer phylogeny
    :param drivers: defaultdict with mutation IDs and instance of driver class to be highlighted on edges
    :return path to the generated ete3 PNG file
    """

    # generate ete3 tree
    rt = Tree()  # generate root
    rt.name = 'Germline {}'.format(patient.name)
    _generate_ete_tree(tree,
                       tree_root_key,
                       rt,
                       0,
                       patient,
                       phylogeny,
                       gene_names=patient.gene_names,
                       drivers=drivers)

    ts = TreeStyle()
    ts.layout_fn = ete_layout
    ts.show_leaf_name = False
    ts.show_branch_length = False
    ts.show_branch_support = False
    ts.show_scale = False
    ts.extra_branch_line_color = 'Black'
    # ts.complete_branch_lines_when_necessary = False

    # Find the maximal number of variants present in a single sample to determine the optimal ETE3 scale level
    max_muts = max(no_pres_vars
                   for no_pres_vars in patient.no_present_vars.values())

    def round_to_1(x):
        """
        Round to one significant digit
        :param x:
        :return:
        """
        return round(x, -int(math.floor(math.log10(abs(x)))))

    # XX pixels per branch length unit
    # if max_muts > 20000:
    #     ts.scale = 0.02
    # elif max_muts > 10000:
    #     ts.scale = 0.05
    # elif max_muts > 5000:
    #     ts.scale = 0.1
    # elif max_muts > 2000:
    #     ts.scale = 0.2
    # elif max_muts > 1000:
    #     ts.scale = 0.5
    # elif max_muts > 500:
    #     ts.scale = 1
    # elif max_muts > 200:
    #     ts.scale = 2
    # elif max_muts > 100:
    #     ts.scale = 5
    # elif max_muts > 50:
    #     ts.scale = 5
    # else:
    #     ts.scale = 10

    ts.scale = round_to_1(600 / max_muts)

    ts.branch_vertical_margin = 15  # XX pixels between adjacent branches

    # rt.show(tree_style=ts)

    ete_tree_plot = filepath + '.png'
    rt.render(ete_tree_plot, w=183, units="mm", tree_style=ts, dpi=300)
    rt.render(filepath + '.pdf', w=183, units="mm", tree_style=ts, dpi=300)

    return ete_tree_plot
コード例 #2
0
    i += 1

sp_t.write(format=1,
           features=["D", "S"],
           outfile=args.o + ".nhx",
           format_root_node=True)

if os.environ.has_key("DISPLAY"):
    from ete3 import TreeStyle, TextFace
    # Basic tree style
    tree_style = TreeStyle()
    tree_style.show_leaf_name = False
    tree_style.show_branch_length = False
    tree_style.show_scale = False
    tree_style.extra_branch_line_type = 0  # 0=solid, 1=dashed, 2=dotted
    tree_style.extra_branch_line_color = "black"

    i = 0
    for n in sp_t.traverse():
        n.dist = 5
        Dstrinq = " D: " + str(Res_dict[str(i)]["D"])
        Sstrinq = " S: " + str(Res_dict[str(i)]["S"])
        n.add_face(TextFace(Dstrinq, fgcolor="#1C01AC"),
                   column=0,
                   position='branch-bottom')
        n.add_face(TextFace(Sstrinq, fgcolor="#800080"),
                   column=0,
                   position='branch-bottom')
        if n.is_leaf():
            n.add_face(TextFace(
                " " + n.name,
コード例 #3
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("-t",
                        action="store",
                        dest="treef",
                        help="The tree file")
    parser.add_argument("-s",
                        action="store",
                        dest="statf",
                        help="The statistics file")
    parser.add_argument("-c",
                        action="store",
                        default=0,
                        type=float,
                        dest="scaling",
                        help="If this parameter is set "
                        "to more than 0, "
                        "the size of the pie charts "
                        "correlate with the total "
                        "number of events at a node "
                        "(and are scaled by the factor "
                        "given as a float).")
    parser.add_argument(
        "-e",
        action="store",
        type=str,
        default="all",
        dest="event",
        help=
        "If an event type is specified, just this event type is visualized. Per default all event types are shown on the tree.\n"
        "all\n"
        "fusions\n"
        "fissions\n"
        "termLosses\n"
        "termEmergences\n"
        "singleDomainLosses\n"
        "singleDomainEmergences")
    parser.add_argument(
        "-p",
        action="store",
        dest="treeshape",
        default="r",
        choices=["c", "r"],
        help="shape of the tree, circle (c) or tree format (r)")
    parser.add_argument("-o", action="store", dest="outputname")
    parser.add_argument(
        "-y",
        action="store",
        type=str,
        dest="NodeIDtreeName",
        default=None,
        help="Name for output file that shows a tree with all node IDs.")
    parser.add_argument(
        "-l",
        dest="short_legend",
        help=
        "Writes the full legend for all events in two levels for short trees",
        action="store_true")

    params = parser.parse_args()

    if (params.event not in ("all", "fusions", "fissions", "termLosses",
                             "termEmergences", "singleDomainLosses",
                             "singleDomainEmergences")):
        print(
            "Error: Please specify a valid event type. For a list of possible options use the --help parameter."
        )
        sys.exit(1)

    if params.NodeIDtreeName != None:
        id_tree = Tree(params.treef, format=0)

        coun = 0
        for node in id_tree.traverse('preorder'):
            node.add_features(ID=coun)
            coun += 1

        # Create empty TreeStyle
        ts = TreeStyle()

        # Set custom layout function
        ts.layout_fn = layout_idtree
        # Draw tree
        ts.mode = params.treeshape
        ts.complete_branch_lines_when_necessary = True
        ts.extra_branch_line_type = 0
        ts.extra_branch_line_color = "black"
        # ts.optimal_scale_level ="full"
        ts.branch_vertical_margin = 40
        ts.scale = 100

        # We will add node names manually
        ts.show_leaf_name = False
        ts.draw_guiding_lines = True

        if (params.NodeIDtreeName.endswith(".pdf")):
            pathout = params.NodeIDtreeName
        else:
            pathout = params.NodeIDtreeName + ".pdf"
        id_tree.render(pathout, dpi=1200, tree_style=ts)
        pl.close()

    else:

        tree = Tree(params.treef, format=0)

        # Read statistics file
        node_stat_dict = {}
        with open(params.statf, "r") as sf:
            for line in sf:
                # Stop the loop at the second part of statistics file
                if line.startswith(
                        "# Number of events per domain."
                ) or line.startswith(
                        "# Events per domain arrangement for last common ancestor"
                ):
                    break
                if line[0] not in ('#', '\n'):
                    vecline = line.strip().split()
                    id = vecline.pop(0)
                    stats = [int(i) for i in vecline]
                    node_stat_dict[int(id)] = stats

        # determine max. number of events per node for scaling
        fus_max = 0
        fis_max = 0
        termLoss_max = 0
        termGain_max = 0
        singLoss_max = 0
        singGain_max = 0
        tot_max = 0

        # Assign rearrangement events to leaves
        c = 0
        for node in tree.traverse('preorder'):
            node.add_features(fusion=node_stat_dict[c][0])
            if (node_stat_dict[c][0] > fus_max):
                fus_max = node_stat_dict[c][0]
            node.add_features(fission=node_stat_dict[c][1])
            if (node_stat_dict[c][1] > fis_max):
                fis_max = node_stat_dict[c][1]
            node.add_features(termLoss=node_stat_dict[c][2])
            if (node_stat_dict[c][2] > termLoss_max):
                termLoss_max = node_stat_dict[c][2]
            node.add_features(termGain=node_stat_dict[c][3])
            if (node_stat_dict[c][3] > termGain_max):
                termGain_max = node_stat_dict[c][3]
            node.add_features(singLoss=node_stat_dict[c][4])
            if (node_stat_dict[c][4] > singLoss_max):
                singLoss_max = node_stat_dict[c][4]
            node.add_features(singGain=node_stat_dict[c][5])
            if (node_stat_dict[c][5] > singGain_max):
                singGain_max = node_stat_dict[c][5]
            if (sum(node_stat_dict[c]) > tot_max):
                tot_max = sum(node_stat_dict[c])
            c += 1

        global scal
        scal = params.scaling

        global eve
        event_options = {
            "all": 0,
            "fusions": 1,
            "fissions": 2,
            "termLosses": 3,
            "termEmergences": 4,
            "singleDomainLosses": 5,
            "singleDomainEmergences": 6
        }
        eve = event_options[params.event]

        # Create empty TreeStyle
        ts = TreeStyle()

        # Set custom layout function
        ts.layout_fn = layout_gen_events
        # Draw tree
        ts.mode = params.treeshape
        ts.complete_branch_lines_when_necessary = True
        ts.extra_branch_line_type = 0
        ts.extra_branch_line_color = "black"
        #ts.optimal_scale_level ="full"
        ts.branch_vertical_margin = 40
        ts.scale = 100

        # We will add node names manually
        ts.show_leaf_name = False

        # legend creation
        if (params.event == "all"):
            ts.legend.add_face(CircleFace(10, "DimGray"), column=0)
            ts.legend.add_face(TextFace(" Fusion     ",
                                        fsize=16,
                                        fgcolor='DimGray'),
                               column=1)
            ts.legend.add_face(CircleFace(10, "DeepPink"), column=2)
            ts.legend.add_face(TextFace(' Fission     ',
                                        fsize=16,
                                        fgcolor='DeepPink'),
                               column=3)
            ts.legend.add_face(CircleFace(10, "YellowGreen"), column=4)
            ts.legend.add_face(TextFace(' Terminal Loss     ',
                                        fsize=16,
                                        fgcolor='YellowGreen'),
                               column=5)
            if params.short_legend:
                ts.legend.add_face(CircleFace(10, "DarkBlue"), column=0)
                ts.legend.add_face(TextFace(' Terminal Emergence     ',
                                            fsize=16,
                                            fgcolor='DarkBlue'),
                                   column=1)
                ts.legend.add_face(CircleFace(10, "Chocolate"), column=2)
                ts.legend.add_face(TextFace(' Single Domain Loss     ',
                                            fsize=16,
                                            fgcolor='Chocolate'),
                                   column=3)
                ts.legend.add_face(CircleFace(10, "DeepSkyBlue"), column=4)
                ts.legend.add_face(TextFace(' Single Domain Emergence     ',
                                            fsize=16,
                                            fgcolor='DeepSkyBlue'),
                                   column=5)
            else:
                ts.legend.add_face(CircleFace(10, "DarkBlue"), column=6)
                ts.legend.add_face(TextFace(' Terminal Emergence     ',
                                            fsize=16,
                                            fgcolor='DarkBlue'),
                                   column=7)
                ts.legend.add_face(CircleFace(10, "Chocolate"), column=8)
                ts.legend.add_face(TextFace(' Single Domain Loss     ',
                                            fsize=16,
                                            fgcolor='Chocolate'),
                                   column=9)
                ts.legend.add_face(CircleFace(10, "DeepSkyBlue"), column=10)
                ts.legend.add_face(TextFace(' Single Domain Emergence     ',
                                            fsize=16,
                                            fgcolor='DeepSkyBlue'),
                                   column=11)
        elif (params.event == "fusions"):
            ts.legend.add_face(CircleFace(10, "DimGray"), column=0)
            ts.legend.add_face(TextFace(" Fusion     ",
                                        fsize=16,
                                        fgcolor='DimGray'),
                               column=1)
        elif (params.event == "fissions"):
            ts.legend.add_face(CircleFace(10, "DeepPink"), column=0)
            ts.legend.add_face(TextFace(' Fission     ',
                                        fsize=16,
                                        fgcolor='DeepPink'),
                               column=1)
        elif (params.event == "termLosses"):
            ts.legend.add_face(CircleFace(10, "YellowGreen"), column=0)
            ts.legend.add_face(TextFace(' Terminal Loss     ',
                                        fsize=16,
                                        fgcolor='YellowGreen'),
                               column=1)
        elif (params.event == "termEmergences"):
            ts.legend.add_face(CircleFace(10, "DarkBlue"), column=0)
            ts.legend.add_face(TextFace(' Terminal Emergence     ',
                                        fsize=16,
                                        fgcolor='DarkBlue'),
                               column=1)
        elif (params.event == "singleDomainLosses"):
            ts.legend.add_face(CircleFace(10, "Chocolate"), column=0)
            ts.legend.add_face(TextFace(' Single Domain Loss     ',
                                        fsize=16,
                                        fgcolor='Chocolate'),
                               column=1)
        elif (params.event == "singleDomainEmergences"):
            ts.legend.add_face(CircleFace(10, "DeepSkyBlue"), column=0)
            ts.legend.add_face(TextFace(' Single Domain Emergence     ',
                                        fsize=16,
                                        fgcolor='DeepSkyBlue'),
                               column=1)

        ts.legend_position = 1
        ts.draw_guiding_lines = True

        if (params.outputname.endswith(".pdf")):
            pathout = params.outputname
        else:
            pathout = params.outputname + ".pdf"
        tree.render(pathout, dpi=1200, tree_style=ts)
        pl.close()

    sys.exit(0)
コード例 #4
0
def analyze_tree(tree, outfile, anno, monoout):
    """
    Main function to analyze the tree
    :param tree:
    :param outfile:
    :param anno:
    :param monoout:
    :return: tree file as pdf file
    """
    m = pd.read_csv(group_mapping,
                    sep="\t",
                    header=None,
                    names=['taxon', 'group'])
    taxon_mapping = dict(zip(m['taxon'], m['group']))
    unique_groups = list(set(m['group']))

    group_dict = {}
    for u in unique_groups:
        group_dict[u] = []
    for k, v in taxon_mapping.iteritems():
        if taxon_mapping[k] in group_dict:
            group_dict[taxon_mapping[k]].append(k)

    adf = pd.read_csv(anno, sep="\t", header=None, names=['gene', 'anno'])
    anno_dict = dict(zip(adf['gene'], adf['anno']))
    title = "unknown gene"
    if tree.startswith("chloNOG"):
        gene = '.'.join(tree.split(".")[:3])
        if gene in anno_dict:
            title = gene + " (" + anno_dict[gene] + ")"
    elif tree.startswith("OC_"):
        gene = tree.split(".")[0]
        if gene in anno_dict:
            title = gene + " (" + anno_dict[gene] + ")"

    t = Tree(tree)
    outgroup_to_use = determine_outgroup(t, group_dict)

    print title

    if outgroup_to_use[2] == 0:
        print "None of the outgroups chosen are found in the tree. Rooted with mid-point rooting."
        r = t.get_midpoint_outgroup()
        t.set_outgroup(r)
    elif outgroup_to_use[2] == 1:
        t.set_outgroup(outgroup_to_use[1][0])
    elif outgroup_to_use[2] >= 2:
        ## do mid-point rooting first to get around the problem of some clades that can't be re-rooted right away
        r = t.get_midpoint_outgroup()
        t.set_outgroup(r)
        x = t.check_monophyly(values=outgroup_to_use[1], target_attr="name")
        if x[0] == True:
            print outgroup_to_use[0], "members are monophyletic"
            ## now, re-root with actual outgroup
            lca = t.get_common_ancestor(outgroup_to_use[1])
            t.set_outgroup(lca)
        else:
            ## use mid-point rooting if members are not mono (already mid-point rooted in the outer scope)
            print outgroup_to_use[
                0], "members are NOT monophyletic. Can't use as an outgroup. Rooted with mid-point rooting"

    check_monophyly(t, group_dict, monoout)

    t.ladderize(direction=1)
    ts = TreeStyle()
    ns = NodeStyle()
    ts.show_branch_support = True
    ts.extra_branch_line_color = "DarkGrey"
    ts.show_leaf_name = False
    ts.layout_fn = tree_layout
    #ts.branch_vertical_margin = 0
    ns['shape'] = "square"
    ns['size'] = 0
    ts.title.add_face(TextFace(title, fsize=8), column=0)
    for n in t.traverse():
        n.set_style(ns)
    t.render(outfile, w=1500, units="px", tree_style=ts)
    print " "