def make_cluster_tree(tree_file: str, matrix: str, out_file: str, outgroup: Optional[List[str]] = None) -> None: """Draw a tree with cluster absence/presence information from an existing tree file and absence/presence matrix, and save it as an image under the supplied file name. Arguments: tree_file: the name of the file containing the tree to annotate matrix: a comma- or tab-separated absence/presence matrix out_file: the name under which to save the resulting image outgroup: the organism(s) to use as an outgroup, if any """ # ClusterTree needs tab-separated, but that can't be exported cleanly matrix = matrix.replace(",", "\t") # tree with clustering analysis tree = ClusterTree(tree_file, text_array=matrix) # rerooting the tree if outgroup: ancestor = tree.get_common_ancestor(outgroup) tree.set_outgroup(ancestor) tree.ladderize(direction=1) # set drawing line width to 2 my_node_style = NodeStyle() my_node_style["vt_line_width"] = 2 my_node_style["hz_line_width"] = 2 my_node_style["size"] = 5 # layout function def sel_mylayout(node): node.set_style(my_node_style) if node.is_leaf(): # add names in larger font + italics species_name = AttrFace("name", fsize=12, fstyle="italic") add_face_to_node(species_name, node, column=0, position="branch-right") # add absence/presence matrix for i, value in enumerate(getattr(node, "profile", [])): if value > 0: color = "#FF0000" else: color = "#EEEEEE" my_face = CircleFace(8, color, style="circle") my_face.margin_right = 3 my_face.margin_bottom = 3 add_face_to_node(my_face, node, position="aligned", column=i) # Use my layout to visualize the tree my_tree_style = TreeStyle() # Add header for j, name in enumerate(tree.arraytable.colNames): name_face = TextFace(name, fsize=11) name_face.rotation = -90 name_face.hz_align = 1 name_face.vt_align = 1 name_face.margin_bottom = 10 my_tree_style.aligned_header.add_face(name_face, column=j) my_tree_style.scale_length = 0.1 # myTreeStyle.show_branch_support = True # don't auto-show leaf names, since we dealt with that above my_tree_style.show_leaf_name = False # set layout function for my_tree_style my_tree_style.layout_fn = sel_mylayout #tree.render(out_file, w=183, units="mm", dpi=600, tree_style=my_tree_style) tree.render(out_file, dpi=600, tree_style=my_tree_style)
# | # | /-F # \--------| # | /-G # \--------| # \-H # Now we can ask the numerical profile associated to each node A = t.search_nodes(name='A')[0] print "A associated profile:\n", A.profile # [-1.23 -0.81 1.79 0.78 -0.42 -0.69 0.58] # # Or we can ask for the mean numerical profile of an internal # partition, which is computed as the average of all vectors under the # the given node. cluster = t.get_common_ancestor("E", "A") print "Internal cluster mean profile:\n", cluster.profile #[-1.574 -0.686 1.048 -0.012 -0.118 0.614 0.728] # # We can also obtain the std. deviation vector of the mean profile print "Internal cluster std deviation profile:\n", cluster.deviation #[ 0.36565558 0.41301816 0.40676283 0.56211743 0.50704635 0.94949671 # 0.26753691] # If would need to re-link the tree to a different matrix or use # different matrix for different sub parts of the tree, we can use the # link_to_arraytable method() # # Creates a matrix with all values = 1 matrix_ones = """ #Names\tcol1\tcol2\tcol3\tcol4\tcol5\tcol6\tcol7 A\t1\t1\t1\t1\t1\t1\t1