package jalview.io.vamsas; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import jalview.analysis.NJTree; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.SeqCigar; import jalview.datamodel.SequenceI; import jalview.gui.AlignViewport; import jalview.gui.TreePanel; import jalview.io.NewickFile; import jalview.io.VamsasAppDatastore; import uk.ac.vamsas.client.Vobject; import uk.ac.vamsas.objects.core.Entry; import uk.ac.vamsas.objects.core.Input; import uk.ac.vamsas.objects.core.Newick; import uk.ac.vamsas.objects.core.Param; import uk.ac.vamsas.objects.core.Provenance; import uk.ac.vamsas.objects.core.Seg; import uk.ac.vamsas.objects.core.Treenode; import uk.ac.vamsas.objects.core.Vref; public class Tree extends DatastoreItem { AlignmentI jal; TreePanel tp; uk.ac.vamsas.objects.core.Tree tree; uk.ac.vamsas.objects.core.Alignment alignment; // may be null => dataset or // other kind of tree private NewickFile ntree; private String title; private AlignmentView inputData = null; public static void updateFrom(VamsasAppDatastore datastore, jalview.gui.AlignFrame alignFrame, uk.ac.vamsas.objects.core.Tree vtree) { Tree toTree = new Tree(datastore, alignFrame, vtree); } public Tree(VamsasAppDatastore datastore, jalview.gui.AlignFrame alignFrame, uk.ac.vamsas.objects.core.Tree vtree) { super(datastore); tree = vtree; TreePanel tp = (TreePanel) getvObj2jv(tree); if (tp != null) { if (tree.isUpdated()) { Cache.log.info( "Update from vamsas document to alignment associated tree not implemented yet."); } } else { // make a new tree Object[] idata = this.recoverInputData(tree.getProvenance()); try { if (idata != null && idata[0] != null) { inputData = (AlignmentView) idata[0]; } ntree = getNtree(); title = tree.getNewick(0).getTitle(); if (title==null || title.length()==0) { title = tree.getTitle(); // hack!!!! } } catch (Exception e) { Cache.log.warn("Problems parsing treefile '" + tree.getNewick(0).getContent() + "'", e); } } } private NewickFile getNtree() throws IOException { return new jalview.io.NewickFile(tree.getNewick(0).getContent()); } public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2, uk.ac.vamsas.objects.core.Alignment alignment2) { super(datastore); jal = jal2; tp = tp2; alignment = alignment2; tree = (uk.ac.vamsas.objects.core.Tree) getjv2vObj(tp); if (tree == null) { add(); } else { if (isModifiable(tree.getModifiable())) { // synchronize(); // update(); // verify any changes. System.out.println("Update tree in document."); } else { // handle conflict System.out .println("Add modified tree as new tree in document."); } } } /** * correctly creates provenance for trees calculated on an alignment by * jalview. * * @param jal * @param tp * @return */ private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp) { Cache.log.debug("Making Tree provenance for "+tp.getTitle()); Provenance prov = new Provenance(); prov.addEntry(new Entry()); prov.getEntry(0).setAction("imported " + tp.getTitle()); prov.getEntry(0).setUser(provEntry.getUser()); prov.getEntry(0).setApp(provEntry.getApp()); prov.getEntry(0).setDate(provEntry.getDate()); if (tp.getTree().hasOriginalSequenceData()) { Input vInput = new Input(); // LATER: check to see if tree input data is contained in this alignment - // or just correctly resolve the tree's seqData to the correct alignment // in // the document. Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal, tp.getTree().seqData.getSequences())); Object[] alsqs = new Object[alsqrefs.size()]; alsqrefs.copyInto(alsqs); vInput.setObjRef(alsqs); // now create main provenance data prov.getEntry(0).setAction("created " + tp.getTitle()); prov.getEntry(0).addInput(vInput); // jalview's special input parameter for distance matrix calculations vInput.setName("jalview:seqdist"); prov.getEntry(0).addParam(new Param()); prov.getEntry(0).getParam(0).setName("treeType"); prov.getEntry(0).getParam(0).setType("utf8"); prov.getEntry(0).getParam(0).setContent("NJ"); int ranges[] = tp.getTree().seqData.getVisibleContigs(); // VisibleContigs are with respect to alignment coordinates. Still need // offsets int start = tp.getTree().seqData.getAlignmentOrigin(); for (int r = 0; r < ranges.length; r += 2) { Seg visSeg = new Seg(); visSeg.setStart(1 + start + ranges[r]); visSeg.setEnd(start + ranges[r + 1]); visSeg.setInclusive(true); vInput.addSeg(visSeg); } } Cache.log.debug("Finished Tree provenance for "+tp.getTitle()); return prov; } /** * look up SeqCigars in an existing alignment. * * @param jal * @param sequences * @return vector of alignment sequences in order of SeqCigar array (but * missing unfound seqcigars) */ private Vector findAlignmentSequences(AlignmentI jal, SeqCigar[] sequences) { SeqCigar[] tseqs = new SeqCigar[sequences.length]; System.arraycopy(sequences, 0, tseqs, 0, sequences.length); Vector alsq = new Vector(); Enumeration as = jal.getSequences().elements(); while (as.hasMoreElements()) { SequenceI asq = (SequenceI) as.nextElement(); for (int t = 0; t=asq.getStart() && tseqs[t].getEnd()<=asq.getEnd()) { tseqs[t] = null; alsq.add(asq); } } } if (alsq.size()0) { Treenode[] tn = new Treenode[tnv.size()]; tnv.copyInto(tn); return tn; } return new Treenode[] {}; } private String makeNodeSpec(Hashtable nodespecs, jalview.datamodel.BinaryNode tnode) { String nname = new String(tnode.getName()); Integer nindx = (Integer) nodespecs.get(nname); if (nindx==null) { nindx = new Integer(1); } nname = nindx.toString()+" "+nname; return nname; } /** * call to match up Treenode specs to NJTree parsed from document object. * * @param nodespec * @param leaves * as returned from NJTree.findLeaves( .., ..) .. * @return */ private jalview.datamodel.BinaryNode findNodeSpec(String nodespec, Vector leaves) { int occurence=-1; String nspec = nodespec.substring(nodespec.indexOf(' ')+1); String oval = nodespec.substring(0, nodespec.indexOf(' ')); try { occurence = new Integer(oval).intValue(); } catch (Exception e) { System.err.println("Invalid nodespec '"+nodespec+"'"); return null; } jalview.datamodel.BinaryNode bn = null; int nocc = 0; Enumeration en = leaves.elements(); while (en.hasMoreElements() && nocc 0) { if (tp.getEntry(pe).getInputCount() > 1) { Cache.log.warn("Ignoring additional input spec in provenance entry " + tp.getEntry(pe).toString()); } // LATER: deal sensibly with multiple inputs Input vInput = tp.getEntry(pe).getInput(0); // is this the whole alignment or a specific set of sequences ? if (vInput.getObjRefCount()==0) continue; if (vInput.getObjRefCount()==1 && vInput.getObjRef(0) instanceof uk.ac.vamsas.objects.core.Alignment) { // recover an AlignmentView for the input data javport = (AlignViewport) getvObj2jv( (uk.ac.vamsas. client.Vobject) vInput .getObjRef(0)); jal = javport.getAlignment(); view = javport.getAlignment(). getCompactAlignment(); } else if (vInput.getObjRef(0) instanceof uk.ac.vamsas.objects.core.AlignmentSequence) { // recover an AlignmentView for the input data javport = (AlignViewport) getvObj2jv(((Vobject)vInput.getObjRef(0)).getV_parent()); jal = javport.getAlignment(); jalview.datamodel.SequenceI[] seqs = new jalview.datamodel.SequenceI[vInput.getObjRefCount()]; for (int i=0,iSize=vInput.getObjRefCount(); i from) { view.deleteRange(offset + from - 1, offset + se[0] - 2); offset -= se[0] - from; } from = se[1] + 1; } } if (from < to) { view.deleteRange(offset + from - 1, offset + to - 1); // final // deletion - // TODO: check // off by // one for to } return new Object[]{new AlignmentView(view), jal}; } } Cache.log.debug("Returning null for input data recovery from provenance."); return null; } public NewickFile getNewickTree() { return ntree; } public String getTitle() { return title; } public AlignmentView getInputData() { return inputData; } public boolean isValidTree() { try { ntree.parse(); if (ntree.getTree()!=null) { ntree = getNtree(); } return true; } catch (Exception e) { Cache.log.debug("Failed to parse newick tree string",e); } return false; } }