/* * Copyright (C) Justo Montiel, David Torres, Sergio Gomez, Alberto Fernandez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * <http://www.gnu.org/licenses/> */ package parser; import inicial.Language; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import newickTreeParsing.Tree; import newickTreeParsing.TreeNode; import parser.figures.Cercle; import parser.figures.Linia; import parser.figures.Marge; import tipus.tipusDades; import definicions.Cluster; import definicions.Config; import definicions.Coordenada; /** * <p> * <b>MultiDendrograms</b> * </p> * * Convert the dendrogram to geometric figures * * @author Justo Montiel, David Torres, Sergio Gómez, Alberto Fernández * * @since JDK 6.0 */ public class Fig_Pizarra { // ----- Fields -----------------------------------------------// //New fields public Cluster ComputedRootCluster; public Cluster DendrogramCluster; private double LongestBranch = 0.0; private static final int CERCLE = 0; private static final int LINIA = 1; private static final int MARGE = 2; private final int prec; private int next = 0; private final double radi; private final Cluster abre; private static tipusDades tip; private double posNodes = 0.0; private final double val_Max_show; public static String[] noms; private final LinkedList[] figura = { new LinkedList<Cercle>(), new LinkedList<Linia>(), new LinkedList<Marge>() }; private final Hashtable<String, Integer> htNoms = new Hashtable<String, Integer>(); public static Double[][] mat_ultrametrica; // ----- Methods -----------------------------------------------// public Fig_Pizarra(final Cluster c, final Config cf) throws Exception { abre = c; //JCE-appropriate // if (cf != null){ val_Max_show = cf.getValorMaxim(); radi = cf.getRadi(); Fig_Pizarra.tip = cf.getTipusMatriu(); prec = cf.getPrecision(); if (tip.equals(tipusDades.DISTANCIA)) { posNodes = 0.0; } else { posNodes = val_Max_show; } Branca(abre, cf.getConfigMenu().isFranjaVisible()); //branch if (c.getFills() > 200){ construeixMatriuUltrametrica(c, true); //don't fill in the matrix } else { construeixMatriuUltrametrica(c, false); // do fill in the matrix (time-consuming) } // //should only be null when calling from other classes. // } else { // val_Max_show = 1; // radi = 1; // prec = 18; // // Branca(abre, true); //branch // } } public Fig_Pizarra(Tree ImportedNewickTree, final Config cf) throws Exception { //convert the tree to a cluster Cluster c = ConvertTree2Cluster(ImportedNewickTree); //Usual cluster processing abre = c; val_Max_show = cf.getValorMaxim(); //val_Max_show = 1.0; radi = cf.getRadi(); Fig_Pizarra.tip = cf.getTipusMatriu(); prec = cf.getPrecision(); if (tip.equals(tipusDades.DISTANCIA)) { posNodes = 0.0; } else { posNodes = val_Max_show; } Branca(abre, cf.getConfigMenu().isFranjaVisible()); //branch //time-consuming point! construeixMatriuUltrametrica(c, true); //save the value as a field. this.ComputedRootCluster = c; } //method to convert between data types private Cluster ConvertTree2Cluster(Tree T) { //iterate through nodes, determine heights boolean HasParent; double TotalWeights; double LongestJourney = 0; int MaxHeight = 1; for (int i = 0; i < T.nodes.size(); i++){ //Retrieve Tree Node TreeNode TN = T.getNodeByKey(i); //re-initialize if (TN.isRoot()){ HasParent = false; } else { HasParent = true; } TotalWeights = 0; //CN = Current Node, initially, this particular tree node TN TreeNode CN = TN; TreeNode PN; //Determine Height while (HasParent){ PN = CN.parent(); if (PN != null){ TotalWeights = TotalWeights + CN.weight; CN = PN; } else { HasParent = false; } } //update total length if (TotalWeights > LongestJourney){ LongestJourney = TotalWeights; } //update max height if (TN.height > MaxHeight){ MaxHeight = TN.height; } } //update longest branch this.LongestBranch = LongestJourney; for (int i = 0; i < T.nodes.size(); i++){ TreeNode TN = T.getNodeByKey(i); //re-initialize if (TN.isRoot()){ HasParent = false; } else { HasParent = true; } //CN = Current Node, initially, this particular tree node TN TreeNode CN = TN; TreeNode PN; TotalWeights = 0; //Determine Height while (HasParent){ PN = CN.parent(); if (PN != null){ TotalWeights = TotalWeights + CN.weight; CN = PN; } else { HasParent = false; } } //update Alcada <height> value //TN.Alcada = 1 - (TotalWeights/LongestJourney); TN.Alcada = LongestBranch - TotalWeights; } // Create intermediate cluster nodes at every step, starting from the leaf nodes. //<Key,Value> = <ID, cluster> LinkedHashMap<Integer,Cluster> CreatedClusters = new LinkedHashMap<Integer,Cluster>(); HashSet<TreeNode> Children = new HashSet<TreeNode>(); int RootKey = 0; //recover all nodes at the deepest level - initial children set for (int i = 0; i <T.nodes.size(); i++){ TreeNode TN = T.getNodeByKey(i); if (TN.height == MaxHeight){ //update list of children Children.add(TN); //Initialize cluster info Cluster c = new Cluster(); c.setAlcada(TN.Alcada); c.setNom(TN.label); c.setNado(false); c.setPhyloSupport(TN.getSupport()); CreatedClusters.put(TN.getKey(), c); if (TN.isRoot()){ RootKey = i; } } } HashSet<TreeNode> Parents; //keep scanning, organizing, until not possible any more //while (NodesReceived < T.nodes.size()){ for (int CurrentHeight = MaxHeight-1; CurrentHeight > 0; CurrentHeight--){ //determine parents of current children Parents = new HashSet<TreeNode>(); for (int i = 0; i <T.nodes.size(); i++){ TreeNode TN = T.getNodeByKey(i); if (TN.height == CurrentHeight){ Parents.add(TN); } } //Translate each parent tree node into a cluster structure for (TreeNode TN : Parents){ //Initialize cluster info for the parent Cluster c = new Cluster(); c.setAlcada(TN.Alcada); c.setPhyloSupport(TN.getSupport()); if (TN.isLeaf()){ c.setNom(TN.label); c.setNado(false); } else { c.setNom(Integer.toString(TN.getKey())); try { boolean SetNado = true; //find all children for this node for (TreeNode CN : Children){ if (CN.parent.getKey() == TN.getKey()){ if (CN.isLeaf()){ SetNado = false; } c.addCluster(CreatedClusters.get(CN.getKey())); } } c.setNado(SetNado); } catch (Exception ex) { ex.printStackTrace(); } } //mark root key if (TN.isRoot()){ RootKey = TN.getKey(); } //add to hash map CreatedClusters.put(TN.getKey(), c); } //update Children = Parents; } return CreatedClusters.get(RootKey); } // Coordinates Leaf private Coordenada<Double> Fulla(final Cluster c) { double x; final Coordenada<Double> pos = new Coordenada<Double>(0.0, 0.0); next++; x = radi * ((3 * next) - 1); pos.setX(x); pos.setY(posNodes); figura[Fig_Pizarra.CERCLE].add(new Cercle(pos, radi, prec, c.getNom())); return pos; } // Coordinates Branch //strip private Coordenada<Double> Branca(final Cluster c, final boolean franja) throws Exception { Coordenada<Double> pos = new Coordenada<Double>(0.0, 0.0); double aglo; double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; if ((c.getFamily() == 1) && (c.getFills() == 1)) pos = this.Fulla(c); else { aglo = c.getAglomeracio(); // grouping for (int n = 0; n < c.getFamily(); n++) { try { pos = this.Branca(c.getFill(n), franja); } catch (Exception e) { String msg_err = Language.getLabel(64) + "\n" + e.getMessage(); //FesLog.LOG.throwing(msg_err, "Branca(final Cluster c)", e); throw new Exception(msg_err); } // create line Linia Lin = new Linia(pos, c.getAlcada(), prec); //note if line extends to leaf, and determine factor if (c.getFill(n).getFills() == 1){ //write phylo fraction Lin.setExtendsToLeaf(true); double PhyFrac = 1.0 - ((c.getAlcada() - c.getFill(n).getAlcada())/LongestBranch); Lin.setPhyloFraction(PhyFrac); } figura[Fig_Pizarra.LINIA].add(Lin); // FesLog.LOG // .finer("new Linia: (" + pos.getX() + ", " + pos.getY() // + ", " + c.getAlcada() + ", " + prec + ")"); min = min > pos.getX() ? pos.getX() : min; max = max < pos.getX() ? pos.getX() : max; } //innitialize group Marge m; // store the group if (franja) { //strip m = new Marge(min, c.getAlcada(), aglo, (max-min), prec); m.setPhyloWeight(c.getPhyloSupport()); // figura[Fig_Pizarra.MARGE].add(new Marge(min, c.getAlcada(), // aglo, (max - min), prec)); // FesLog.LOG.finer("Marge: (" + min + ", " + c.getAlcada() + ", " // + aglo + ", " + (max - min)); } else { m = new Marge(min, c.getAlcada(), 0, (max-min), prec); m.setPhyloWeight(c.getPhyloSupport()); // figura[Fig_Pizarra.MARGE].add(new Marge(min, c.getAlcada(), 0, // (max - min), prec)); // FesLog.LOG.finer("Marge: (" + min + ", " + c.getAlcada() + ", " // + 0 + ", " + (max - min)); } // System.out.println("Fig_Pizarra m: " + m.getPhyloWeight()); //add Marge figura[Fig_Pizarra.MARGE].add(m); pos.setX((min + max) / 2); // weights the agglomeration group downwards if (tip.equals(tipusDades.DISTANCIA)) { if (franja) pos.setY(c.getAlcada() + c.getAglomeracio()); else pos.setY(c.getAlcada()); } else { if (franja) pos.setY(c.getAlcada() - c.getAglomeracio()); else pos.setY(c.getAlcada()); } } return pos; } // build ultrametric matrix public void construeixMatriuUltrametrica(Cluster c, boolean isPhylo) { List<Cluster> lFills = c.getLstFills(); List<String> lNoms = new LinkedList<String>(); for (int i = 0; i < lFills.size(); i++) lNoms.add((lFills.get(i)).getNom()); Collections.sort(lNoms); int mida = c.getFills(); // files/cols. de la matriu mat_ultrametrica = new Double[mida][mida]; noms = new String[mida]; //mida = size for (int i = 0; i < lNoms.size(); i++) { htNoms.put(lNoms.get(i), i); // 'a'->0, 'b'->1, ... noms[i] = lNoms.get(i); } //Only need to fill matrix when computing context tree. if (!isPhylo){ ompleMatriuUltrametrica(c); } } // fill ultrametric matrix private void ompleMatriuUltrametrica(Cluster c) { if (c.getFamily() > 1) { List<Cluster> l = c.getLstFills(); double alc = c.getAlcada(); for (int n = 0; n < l.size(); n++) for (int i = 0; i < c.getLstFills().size(); i++) { Cluster ci = c.getLstFills().get(i); int posi = htNoms.get(ci.getNom()); for (int j = 0; j < c.getLstFills().size(); j++) { Cluster cj = c.getLstFills().get(j); int posj = htNoms.get(cj.getNom()); if (posi == posj) mat_ultrametrica[posi][posj] = 0.0; else mat_ultrametrica[posi][posj] = alc; } } for (int n = 0; n < c.getFamily(); n++) { try { ompleMatriuUltrametrica(c.getFill(n)); //fill ultrametric matrix } catch (Exception e) { e.printStackTrace(); } } } } public static int getIndCercle() { return Fig_Pizarra.CERCLE; } public static int getIndLinia() { return Fig_Pizarra.LINIA; } public static int getIndMarge() { return Fig_Pizarra.MARGE; } public LinkedList[] getFigures() { return figura; } public Hashtable<Integer, String> getHtNoms() { // Need to switch arguments for output Hashtable<Integer, String> HtNomsSwitched = new Hashtable<Integer, String>(); Enumeration Names = htNoms.keys(); while (Names.hasMoreElements()){ String Key = (String) Names.nextElement(); HtNomsSwitched.put(htNoms.get(Key),Key); } return HtNomsSwitched; } public double getLongestBranch() { return LongestBranch; } public void setLongestBranch(double longestBranch) { LongestBranch = longestBranch; } }