package statalign.postprocess.plugins.contree; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; /** * The Consensus network * * @author wood * */ public class CNetwork { public String outputString; public ArrayList<CNetworkSplit> splits; public ArrayList<CNetworkNode> nodes; public int noOfTaxa; /** * Constructs a new Consensus Network. * * @param noOfTaxa The number of taxa in the network. */ public CNetwork(int noOfTaxa){ splits = new ArrayList<CNetworkSplit>(); nodes = new ArrayList<CNetworkNode>(); this.noOfTaxa = noOfTaxa; } /** * Prints out the network in Nexus format. Can be read by SplitsTree 4 * * @param function 1 - print as splits, 2 - print drawn network as calculated * @param noOfTaxa The number of taxa in the network. * @param taxa the map of taxa indices to names */ public void PrintOut(int function,int noOfTaxa,TaxaMap taxa) throws IOException{ String fileName = ""; if(function==1){ fileName = "splits"; } if(function==2){ fileName = "network"; } PrintWriter out = new PrintWriter(new FileWriter(fileName+".nex")); out.println("#nexus"); out.println("BEGIN Taxa;"); out.println("DIMENSIONS ntax="+noOfTaxa+";"); out.println("TAXLABELS"); for(int x=0;x<taxa.size();x++){ out.println("["+(x+1)+"] '"+taxa.getName(x)+"'"); } out.println(";"); out.println("END; [Taxa]"); if(function==1){ out.println("BEGIN Splits;"); int countSplits = 0; for(int y=0; y<splits.size();y++){ if(splits.get(y).split.cardinality()!=0 && splits.get(y).split.cardinality()!=noOfTaxa){ countSplits++; } } out.println("DIMENSIONS ntax="+noOfTaxa+" nsplits="+countSplits+";"); out.println("FORMAT labels=no weights=yes confidences=no intervals=no;"); out.println("PROPERTIES fit=-1.0 compatible;"); out.print("CYCLE"); for(int x=0;x<taxa.size();x++){ out.print(" "+(x+1)); } out.println(";"); out.println("MATRIX"); for(int y=0; y<splits.size();y++){ if(splits.get(y).split.cardinality()!=0 && splits.get(y).split.cardinality()!=noOfTaxa){ out.print("["+(y+1)+", size=1] 1.0 "); for(int z=0;z<noOfTaxa;z++){ out.print((splits.get(y).split.get(z))?(z+1)+" ":""); } out.println(","); } } out.println(";"); out.println("END; [Splits]"); } if(function==2){ out.println("BEGIN Network;"); int noOfEdges = 0; for(int w=0;w<splits.size();w++){ for(int u=0;u<splits.get(w).edges.size();u++){ noOfEdges++; } } out.println("DIMENSIONS ntax="+noOfTaxa+" nvertices="+nodes.size()+" nedges="+noOfEdges+";"); out.println("DRAW to_scale;"); out.println("VERTICES"); for(int w=0;w<nodes.size();w++){ out.println((w+1)+" "+nodes.get(w).xPos+" "+nodes.get(w).yPos+","); nodes.get(w).outputNumber = (w+1); } out.println(";"); out.println("VLABELS"); for(int w=0;w<nodes.size();w++){ out.println((w+1)+" '"+nodes.get(w).Taxaname+"',"); } out.println(";"); out.println("EDGES"); int edgePrinted = 0; for(int w=0;w<splits.size();w++){ for(int u=0;u<splits.get(w).edges.size();u++){ edgePrinted++; out.println(edgePrinted+" "+splits.get(w).edges.get(u).networkNodeA.outputNumber+" "+splits.get(w).edges.get(u).networkNodeB.outputNumber+","); } } out.println(";"); out.println("END; [Network]"); } out.close(); } /** * Calculates positions for network nodes and edges linking them to output to the network visualiser. * * @param noOfTaxa The number of taxa in the network */ public void FindPositions(int noOfTaxa){ //catch empty network... if (nodes.size()>0){ //pick a node to start with... (we'll just start from the end as this is most likely to be not a taxon (unless it is a star graph hmmmm). CNetworkNode firstNode = nodes.get(nodes.size()-1); // it has all angles to go at... firstNode.angleWidth = 2*Math.PI; firstNode.angleDirection = 0.0; firstNode.drawn = true; // begin at origin... firstNode.xPos = 0.0; firstNode.yPos = 0.0; // the next edges are stored in an ArrayList so that the drawing spreads out from our initial node! ArrayList<CNetworkNode> nextNodesToDraw = new ArrayList<CNetworkNode>(); nextNodesToDraw.add(firstNode); // Loop through nodes in rings that spread outwards from the central node, with each ring containing nodes that are the same number of nodes away from the initial node. do{ // Move next lot over to current lot to draw ArrayList<CNetworkNode> nodesToDraw = new ArrayList<CNetworkNode>(); nodesToDraw.addAll(nextNodesToDraw); // and clear the array that stores the next lot nextNodesToDraw.clear(); for(CNetworkNode currentNode : nodesToDraw){ nextNodesToDraw.addAll(currentNode.DrawEdges(noOfTaxa)); } //clear the array ready for the next lot nodesToDraw.clear(); } while(nextNodesToDraw.size()>0); } } }