def __init__(self, T, B): """ @param T: tree topology @param B: branch lengths """ self.T = T self.B = B # define a leaf and internal vertex order self.leaves = Ftree.T_to_leaves(self.T) self.internal = Ftree.T_to_internal_vertices(self.T) # compute the reference MDS for canonical reflection D = Ftree.TB_to_D(self.T, self.B, self.leaves) self.reference_MDS = self._D_to_MDS(D)
def get_response_content(fs): """ @param fs: a FieldStorage object containing the cgi arguments @return: the response """ T, B, N = FtreeIO.newick_to_TBN(fs.tree_string) # sanitize taxon labels if requested if fs.sanitization: for v in N: N[v] = latexutil.sanitize(N[v]) # scale branch lengths so the diameter is 1 diameter = np.max(Ftree.TB_to_D(T, B, Ftree.T_to_leaves(T))) # scale the branch lengths for u_edge in T: B[u_edge] /= diameter info = FigureInfo(T, B, N, fs.label_mode) # get the texts tikz_bodies = [ info.get_tikz_tree(fs.tree_layout), info.get_tikz_MDS_full(), info.get_tikz_MDS_partial(), info.get_tikz_MDS_harmonic(), ] tikz_pictures = [] for b in tikz_bodies: tikzpicture = tikz.get_picture(b, 'auto', scale=fs.scaling_factor) tikz_pictures.append(tikzpicture) figure_body = '\n'.join([ '\\subfloat[]{', tikz_pictures[0], '}', '\\subfloat[]{', tikz_pictures[1], '} \\\\', '\\subfloat[]{', tikz_pictures[2], '}', '\\subfloat[]{', tikz_pictures[3], '}', ]) packages = ['tikz', 'subfig'] preamble = '' figure_caption = None figure_label = None return latexutil.get_centered_figure_response( figure_body, fs.latexformat, figure_caption, figure_label, packages, preamble)
def get_full_distance_MDS(self): """ Reflect towards the reference MDS. This is similar to the leaf MDS but for the full distance matrix. @return: Nx2 MDS matrix """ D_full = Ftree.TB_to_D(self.T, self.B, self.vertices) G_neg = MatrixUtil.double_centered(D_full) / 2.0 W_neg, V = scipy.linalg.eigh(G_neg, eigvals=(0,1)) MDS = V * np.sqrt(np.abs(W_neg)) # compute signs of dot products of corresponding columns signs = [] nleaves = len(self.leaves) for a, b in zip(MDS[:nleaves].T, self.reference_leaf_MDS.T): signs.append(1 if np.dot(a, b) > 0 else -1) # return a copy of the MDS with the new signs return np.array(MDS) * signs
def get_reference_leaf_MDS(self): """ Let the MDS be an Nx2 matrix of scaled points. The points should be appropriately scaled by eigenvalues. The reflections (column signs) of the points are arbitrary. The points should be ordered conformantly with the NxN distance matrix. @param D: NxN distance matrix @return: Nx2 MDS matrix """ D_leaves = Ftree.TB_to_D(self.T, self.B, self.leaves) G_neg = MatrixUtil.double_centered(D_leaves) / 2.0 # Get eigenvalues in increasing order as W, # and get corresponding eigenvectors as columns of V. W_neg, V = scipy.linalg.eigh(G_neg, eigvals=(0,1)) # Scale columns by square root of negative eigenvalue. # Use absolute value to hackily deal with non-Euclidean # distance matrices which may arise as a result of # adding a perturbation. return V * np.sqrt(np.abs(W_neg))
def __init__(self, T, B, N, label_mode): """ @param T: tree topology @param B: branch lengths @param N: vertex to name @param label_mode: this is an option for MDS vertex labels """ # store tree characteristics self.T = T self.B = B self.N = N # store options self.label_mode = label_mode # define a leaf and internal vertex order self.leaves = Ftree.T_to_leaves(self.T) self.internal = Ftree.T_to_internal_vertices(self.T) self.vertices = self.leaves + self.internal # map vertices to short names self.N_short = dict(zip(self.vertices, gen_short_names())) # compute the reference MDS for canonical reflection D_leaves = Ftree.TB_to_D(self.T, self.B, self.leaves) self.reference_leaf_MDS = self.get_reference_leaf_MDS()
def get_response_content(fs): # read the user input weight_delta_mu = fs.weight_delta_mu T, B, N = FtreeIO.newick_to_TBN(fs.newick) # summarize the tree leaves = Ftree.T_to_leaves(T) internal = Ftree.T_to_internal_vertices(T) vertices = leaves + internal nleaves = len(leaves) # define the fully connected schur complement graph as a Laplacian matrix # init the tree reconstruction state v_to_name = {} for v in leaves: name = N.get(v, None) if name is None: name = 'P' + chr(ord('a') + v) v_to_name[v] = name v_to_svs = dict((v, set([0])) for v in leaves) sv_to_vs = {0: set(leaves)} # define edge weights (used only for spectral split strategy) G = Ftree.TB_to_L_schur(T, B, leaves) # add some random amount to each edge weight for i in range(nleaves): for j in range(i): rate = 1 / fs.weight_delta_mu x = random.expovariate(rate) G[i, j] -= x G[j, i] -= x G[i, i] += x G[j, j] += x edge_to_weight = {} for index_pair in itertools.combinations(range(nleaves), 2): i, j = index_pair leaf_pair = (leaves[i], leaves[j]) edge_to_weight[frozenset(leaf_pair)] = -G[index_pair] # define pairwise distances (used only for nj split strategy) D = Ftree.TB_to_D(T, B, leaves) edge_to_distance = {} for index_pair in itertools.combinations(range(nleaves), 2): i, j = index_pair leaf_pair = (leaves[i], leaves[j]) edge_to_distance[frozenset(leaf_pair)] = D[index_pair] # pairs like (-(number of vertices in supervertex sv), supervertex sv) active_svs = set([0]) # initialize the sources of unique vertex and supervertex identifiers v_gen = itertools.count(max(leaves) + 1) sv_gen = itertools.count(1) # write the output out = StringIO() print >> out, '<html>' print >> out, '<body>' for count_pos in itertools.count(1): # add the graph rendering before the decomposition at this stage if fs.nj_split: edge_to_branch_weight = {} for k, v in edge_to_distance.items(): edge_to_branch_weight[k] = 1 / v elif fs.spectral_split: edge_to_branch_weight = edge_to_weight print >> out, '<div>' if fs.vis_star: print >> out, nhj.get_svg_star_components(active_svs, sv_to_vs, v_to_name, v_to_svs, edge_to_branch_weight) elif fs.vis_complete: print >> out, nhj.get_svg(active_svs, sv_to_vs, v_to_name, v_to_svs, edge_to_branch_weight) print >> out, '</div>' # update the splits next_active_svs = set() # svs can be decomposed independently in arbitrary order alpha_index_gen = itertools.count() for sv in active_svs: nstates = len(sv_to_vs[sv]) if nstates > 2: v_new = next(v_gen) sv_new_a = next(sv_gen) sv_new_b = next(sv_gen) alpha_index = next(alpha_index_gen) alpha = chr(ord('a') + alpha_index) v_to_name[v_new] = 'R%s%s' % (count_pos, alpha) next_active_svs.add(sv_new_a) next_active_svs.add(sv_new_b) if fs.spectral_split: if len(sv_to_vs[sv]) == 3: sv_new_c = next(sv_gen) nhj.delta_wye_transform(sv, v_to_svs, sv_to_vs, edge_to_weight, v_new, sv_new_a, sv_new_b, sv_new_c) next_active_svs.add(sv_new_c) else: nhj.harmonic_split_transform(sv, v_to_svs, sv_to_vs, edge_to_weight, v_new, sv_new_a, sv_new_b) elif fs.nj_split: sv_new_big = next(sv_gen) nhj.nj_split_transform(sv, v_to_svs, sv_to_vs, edge_to_distance, v_new, sv_new_big, sv_new_a, sv_new_b) next_active_svs.add(sv_new_big) elif nstates == 2: next_active_svs.add(sv) else: raise ValueError('supervertex has too few vertices') # if the set of active svs has not changed then we are done if active_svs == next_active_svs: break else: active_svs = next_active_svs print >> out, '</html>' print >> out, '</body>' return out.getvalue()
def get_full_distance_MDS(T, B, vertices): D_full = Ftree.TB_to_D(T, B, vertices) G_neg = MatrixUtil.double_centered(D_full) / 2.0 W_neg, V = scipy.linalg.eigh(G_neg, eigvals=(0, 1)) return V * np.sqrt(np.abs(W_neg))
def _get_D(self): """ @return: distance matrix relating leaves """ return Ftree.TB_to_D(self.T, self.B, self.leaves)