package jalview.ext.archaeopteryx; import jalview.analysis.TreeBuilder; import jalview.datamodel.SequenceI; import jalview.ext.forester.DataConversions; import jalview.ext.forester.ForesterMatrix; import jalview.ext.treeviewer.ExternalTreeBuilderI; import jalview.util.MappingUtils; import jalview.util.MessageManager; import java.util.HashMap; import java.util.Map; import org.forester.evoinference.matrix.distance.DistanceMatrix; import org.forester.phylogeny.Phylogeny; import org.forester.phylogeny.PhylogenyNode; import org.forester.phylogeny.data.NodeData; import org.forester.phylogeny.data.Sequence; /** * Class for converting trees made in Jalview (through TreeBuilder) to trees * compatible with Forester (Phylogeny objects). * * Note that this currently demands a 1:1 relationship between tree nodes and * the sequences used for generating them. * * @author kjvanderheide * */ public class AptxTreeBuilder implements ExternalTreeBuilderI { protected final SequenceI[] sequences; protected final DistanceMatrix distances; protected final TreeBuilder jalviewTree; public String treeTitle; private final Phylogeny aptxTree; private PhylogenyNode rootNode; private final Map alignmentWithNodes; private final Map nodesWithAlignment; public AptxTreeBuilder(final TreeBuilder calculatedTree) { jalviewTree = calculatedTree; sequences = jalviewTree.getSequences(); distances = ForesterMatrix.convertJalviewToForester( jalviewTree.getDistances(), sequences); aptxTree = new Phylogeny(); rootNode = new PhylogenyNode(); int amountOfSequences = distances.getSize(); alignmentWithNodes = new HashMap<>(amountOfSequences); nodesWithAlignment = new HashMap<>(amountOfSequences); } @Override public Phylogeny buildTree(final PhylogenyNode treeRoot) { if (treeRoot != null) { rootNode = treeRoot; } buildTree(); return aptxTree; } @Override public Phylogeny buildTree() { for (SequenceI sequence : sequences) { Sequence seq = DataConversions .createForesterSequence(sequence, true); PhylogenyNode sequenceNode = new PhylogenyNode(sequence.getName()); NodeData nodeData = sequenceNode.getNodeData(); nodeData.setSequence(seq); MappingUtils.putWithDuplicationCheck(nodesWithAlignment, sequenceNode, sequence); MappingUtils.putWithDuplicationCheck(alignmentWithNodes, sequence, sequenceNode); rootNode.addAsChild(sequenceNode); } aptxTree.setRoot(rootNode); treeTitle = generateTreeName(); aptxTree.setName(treeTitle); return aptxTree; } @Override public Map getAlignmentBoundNodes() { return alignmentWithNodes; } @Override public Map getNodesBoundAlignment() { return nodesWithAlignment; } private Phylogeny clusterNodes() { return aptxTree; } /** * Formats a localised title for the tree panel, like *

* Neighbour Joining Using BLOSUM62 *

* For a tree loaded from file, just uses the file name * * @return */ @Override public String generateTreeName() // Move this and add selection region to the // title when applicable { if (treeTitle != null) // will currently never happen, loaded tree file will // take a different path { return treeTitle; } else { /* * i18n description of Neighbour Joining or Average Distance method */ String treecalcnm = MessageManager .getString("label.tree_calc_" + jalviewTree.getClass() .getSimpleName().substring(0, 2).toLowerCase()); /* * short score model name (long description can be too long) */ String smn = jalviewTree.getScoreModel().getName(); /* * put them together as Using */ final String ttl = MessageManager .formatMessage("label.treecalc_title", treecalcnm, smn); return ttl; } } }