2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.io.vamsas;
20 import java.io.IOException;
21 import java.util.Enumeration;
22 import java.util.Hashtable;
23 import java.util.Vector;
25 import jalview.analysis.NJTree;
26 import jalview.analysis.SequenceIdMatcher;
27 import jalview.bin.Cache;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.AlignmentView;
30 import jalview.datamodel.BinaryNode;
31 import jalview.datamodel.SeqCigar;
32 import jalview.datamodel.Sequence;
33 import jalview.datamodel.SequenceI;
34 import jalview.datamodel.SequenceNode;
35 import jalview.gui.AlignFrame;
36 import jalview.gui.AlignViewport;
37 import jalview.gui.TreePanel;
38 import jalview.io.NewickFile;
39 import jalview.io.VamsasAppDatastore;
40 import uk.ac.vamsas.client.Vobject;
41 import uk.ac.vamsas.objects.core.AlignmentSequence;
42 import uk.ac.vamsas.objects.core.Entry;
43 import uk.ac.vamsas.objects.core.Input;
44 import uk.ac.vamsas.objects.core.Newick;
45 import uk.ac.vamsas.objects.core.Param;
46 import uk.ac.vamsas.objects.core.Provenance;
47 import uk.ac.vamsas.objects.core.Seg;
48 import uk.ac.vamsas.objects.core.Treenode;
49 import uk.ac.vamsas.objects.core.Vref;
51 public class Tree extends DatastoreItem
57 uk.ac.vamsas.objects.core.Tree tree;
59 uk.ac.vamsas.objects.core.Alignment alignment; // may be null => dataset or
62 private NewickFile ntree;
66 private AlignmentView inputData = null;
68 public static void updateFrom(VamsasAppDatastore datastore,
69 jalview.gui.AlignFrame alignFrame,
70 uk.ac.vamsas.objects.core.Tree vtree)
72 Tree toTree = new Tree(datastore, alignFrame, vtree);
75 public Tree(VamsasAppDatastore datastore,
76 jalview.gui.AlignFrame alignFrame,
77 uk.ac.vamsas.objects.core.Tree vtree)
79 super(datastore, vtree, TreePanel.class);
83 private NewickFile getNtree() throws IOException
85 return new jalview.io.NewickFile(tree.getNewick(0).getContent());
88 public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2,
89 uk.ac.vamsas.objects.core.Alignment alignment2)
91 super(datastore, tp2, uk.ac.vamsas.objects.core.Tree.class);
94 tp = (TreePanel) jvobj;
95 alignment = alignment2;
97 tree = (uk.ac.vamsas.objects.core.Tree) vobj;
104 * @see jalview.io.vamsas.DatastoreItem#addFromDocument()
106 public void addFromDocument()
108 tree = (uk.ac.vamsas.objects.core.Tree) vobj; // vtree;
109 TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
111 Object[] idata = recoverInputData(tree.getProvenance());
114 if (idata != null && idata[0] != null)
116 inputData = (AlignmentView) idata[0];
119 title = tree.getNewick(0).getTitle();
120 if (title == null || title.length() == 0)
122 title = tree.getTitle(); // hack!!!!
124 } catch (Exception e)
126 Cache.log.warn("Problems parsing treefile '"
127 + tree.getNewick(0).getContent() + "'", e);
134 * @see jalview.io.vamsas.DatastoreItem#conflict()
136 public void conflict()
139 .info("Update (with conflict) from vamsas document to alignment associated tree not implemented yet.");
145 * @see jalview.io.vamsas.DatastoreItem#update()
147 public void updateToDoc()
149 if (isModifiable(tree.getModifiable()))
151 // synchronize(); // update();
152 // verify any changes.
153 log.info("TODO: Update tree in document from jalview.");
158 log.info("TODO: Add the locally modified tree in Jalview as a new tree in document, leaving locked tree unchanged.");
165 * @see jalview.io.vamsas.DatastoreItem#updateFromDoc()
167 public void updateFromDoc()
169 // should probably just open a new tree panel in the same place as the old
171 // TODO: Tree.updateFromDoc
173 * TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
175 * // make a new tree Object[] idata =
176 * recoverInputData(tree.getProvenance()); try { if (idata != null &&
177 * idata[0] != null) { inputData = (AlignmentView) idata[0]; } ntree =
178 * getNtree(); title = tree.getNewick(0).getTitle(); if (title == null ||
179 * title.length() == 0) { title = tree.getTitle(); // hack!!!! } } catch
180 * (Exception e) { Cache.log.warn("Problems parsing treefile '" +
181 * tree.getNewick(0).getContent() + "'", e); }
183 log.debug("Update the local tree in jalview from the document.");
185 if (isModifiable(tree.getModifiable()))
187 // synchronize(); // update();
188 // verify any changes.
189 log.debug("Update tree in document from jalview.");
194 log.debug("Add modified jalview tree as new tree in document.");
199 * correctly creates provenance for trees calculated on an alignment by
206 private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
208 Cache.log.debug("Making Tree provenance for " + tp.getTitle());
209 Provenance prov = new Provenance();
210 prov.addEntry(new Entry());
211 prov.getEntry(0).setAction("imported " + tp.getTitle());
212 prov.getEntry(0).setUser(provEntry.getUser());
213 prov.getEntry(0).setApp(provEntry.getApp());
214 prov.getEntry(0).setDate(provEntry.getDate());
215 if (tp.getTree().hasOriginalSequenceData())
217 Input vInput = new Input();
218 // LATER: check to see if tree input data is contained in this alignment -
219 // or just correctly resolve the tree's seqData to the correct alignment
222 Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal,
223 tp.getTree().seqData.getSequences()));
224 Object[] alsqs = new Object[alsqrefs.size()];
225 alsqrefs.copyInto(alsqs);
226 vInput.setObjRef(alsqs);
227 // now create main provenance data
228 prov.getEntry(0).setAction("created " + tp.getTitle());
229 prov.getEntry(0).addInput(vInput);
230 // jalview's special input parameter for distance matrix calculations
231 vInput.setName("jalview:seqdist"); // TODO: settle on appropriate name.
232 prov.getEntry(0).addParam(new Param());
233 prov.getEntry(0).getParam(0).setName("treeType");
234 prov.getEntry(0).getParam(0).setType("utf8");
235 prov.getEntry(0).getParam(0).setContent("NJ"); // TODO: type of tree is a
237 int ranges[] = tp.getTree().seqData.getVisibleContigs();
238 // VisibleContigs are with respect to alignment coordinates. Still need
240 int start = tp.getTree().seqData.getAlignmentOrigin();
241 for (int r = 0; r < ranges.length; r += 2)
243 Seg visSeg = new Seg();
244 visSeg.setStart(1 + start + ranges[r]);
245 visSeg.setEnd(start + ranges[r + 1]);
246 visSeg.setInclusive(true);
247 vInput.addSeg(visSeg);
250 Cache.log.debug("Finished Tree provenance for " + tp.getTitle());
255 * look up SeqCigars in an existing alignment.
259 * @return vector of alignment sequences in order of SeqCigar array (but
260 * missing unfound seqcigars)
262 private Vector findAlignmentSequences(AlignmentI jal, SeqCigar[] sequences)
264 SeqCigar[] tseqs = new SeqCigar[sequences.length];
265 System.arraycopy(sequences, 0, tseqs, 0, sequences.length);
266 Vector alsq = new Vector();
267 Enumeration as = jal.getSequences().elements();
268 while (as.hasMoreElements())
270 SequenceI asq = (SequenceI) as.nextElement();
271 for (int t = 0; t < sequences.length; t++)
274 && (tseqs[t].getRefSeq() == asq || tseqs[t].getRefSeq() == asq
275 .getDatasetSequence()))
276 // && tseqs[t].getStart()>=asq.getStart() &&
277 // tseqs[t].getEnd()<=asq.getEnd())
284 if (alsq.size() < sequences.length)
286 .warn("Not recovered all alignment sequences for given set of input sequence CIGARS");
292 * Update jalview newick representation with TreeNode map
295 * the treepanel that this tree is bound to.
297 public void UpdateSequenceTreeMap(TreePanel tp)
299 if (tp == null || tree == null)
301 Vector leaves = new Vector();
302 if (tp.getTree() == null)
304 Cache.log.warn("Not updating SequenceTreeMap for "
305 + tree.getVorbaId());
308 tp.getTree().findLeaves(tp.getTree().getTopNode(), leaves);
309 Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
316 Treenode node = tn[i++];
317 BinaryNode mappednode = findNodeSpec(node.getNodespec(), leaves);
318 if (mappednode != null && mappednode instanceof SequenceNode)
320 SequenceNode leaf = (SequenceNode) mappednode;
321 // check if we can make the specified association
323 int vrf = 0, refv = 0;
324 while (jvseq == null && vrf < node.getVrefCount())
326 if (refv < node.getVref(vrf).getRefsCount())
328 Object noderef = node.getVref(vrf).getRefs(refv++);
329 if (noderef instanceof AlignmentSequence)
331 // we only make these kind of associations
332 jvseq = getvObj2jv((Vobject) noderef);
341 if (jvseq instanceof SequenceI)
343 leaf.setElement(jvseq);
344 leaf.setPlaceholder(false);
348 leaf.setPlaceholder(true);
349 leaf.setElement(new Sequence(leaf.getName(), "THISISAPLACEHLDER"));
355 // / TODO: refactor to vamsas :start
357 * construct treenode mappings for mapped sequences
363 public Treenode[] makeTreeNodes(NJTree ntree, Newick newick)
365 Vector leaves = new Vector();
366 ntree.findLeaves(ntree.getTopNode(), leaves);
367 Vector tnv = new Vector();
368 Enumeration l = leaves.elements();
369 Hashtable nodespecs = new Hashtable();
370 while (l.hasMoreElements())
372 jalview.datamodel.BinaryNode tnode = (jalview.datamodel.BinaryNode) l
374 if (tnode instanceof jalview.datamodel.SequenceNode)
376 if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
378 Object assocseq = ((jalview.datamodel.SequenceNode) tnode)
380 if (assocseq instanceof SequenceI)
382 Vobject vobj = this.getjv2vObj(assocseq);
385 Treenode node = new Treenode();
386 if (newick.isRegisterable())
388 this.cdoc.registerObject(newick);
389 node.addTreeId(newick);
391 node.setNodespec(makeNodeSpec(nodespecs, tnode));
392 node.setName(tnode.getName());
393 Vref vr = new Vref();
396 tnv.addElement(node);
400 System.err.println("WARNING: Unassociated treeNode "
401 + tnode.element().toString()
403 + ((tnode.getName() != null) ? " label "
404 + tnode.getName() : ""));
412 Treenode[] tn = new Treenode[tnv.size()];
416 return new Treenode[]
420 private String makeNodeSpec(Hashtable nodespecs,
421 jalview.datamodel.BinaryNode tnode)
423 String nname = new String(tnode.getName());
424 Integer nindx = (Integer) nodespecs.get(nname);
427 nindx = new Integer(1);
429 nname = nindx.toString() + " " + nname;
434 * call to match up Treenode specs to NJTree parsed from document object.
438 * as returned from NJTree.findLeaves( .., ..) ..
441 private jalview.datamodel.BinaryNode findNodeSpec(String nodespec,
445 String nspec = nodespec.substring(nodespec.indexOf(' ') + 1);
446 String oval = nodespec.substring(0, nodespec.indexOf(' '));
449 occurence = new Integer(oval).intValue();
450 } catch (Exception e)
452 System.err.println("Invalid nodespec '" + nodespec + "'");
455 jalview.datamodel.BinaryNode bn = null;
458 Enumeration en = leaves.elements();
459 while (en.hasMoreElements() && nocc < occurence)
461 bn = (jalview.datamodel.BinaryNode) en.nextElement();
462 if (bn instanceof jalview.datamodel.SequenceNode
463 && bn.getName().equals(nspec))
473 // todo: end refactor to vamsas library
475 * add jalview object to vamsas document
478 public void addToDocument()
480 tree = new uk.ac.vamsas.objects.core.Tree();
481 bindjvvobj(tp, tree);
482 tree.setTitle(tp.getTitle());
483 Newick newick = new Newick();
484 newick.setContent(tp.getTree().toString());
485 newick.setTitle(tp.getTitle());
486 tree.addNewick(newick);
487 tree.setProvenance(makeTreeProvenance(jal, tp));
488 tree.setTreenode(makeTreeNodes(tp.getTree(), newick));
490 alignment.addTree(tree);
494 * note: this function assumes that all sequence and alignment objects
495 * referenced in input data has already been associated with jalview objects.
499 * @return Object[] { AlignmentView, AlignmentI - reference alignment for
502 public Object[] recoverInputData(Provenance tp)
504 AlignViewport javport = null;
505 jalview.datamodel.AlignmentI jal = null;
506 jalview.datamodel.CigarArray view = null;
507 for (int pe = 0; pe < tp.getEntryCount(); pe++)
509 if (tp.getEntry(pe).getInputCount() > 0)
511 if (tp.getEntry(pe).getInputCount() > 1)
514 .warn("Ignoring additional input spec in provenance entry "
515 + tp.getEntry(pe).toString());
517 // LATER: deal sensibly with multiple inputs
518 Input vInput = tp.getEntry(pe).getInput(0);
519 // is this the whole alignment or a specific set of sequences ?
520 if (vInput.getObjRefCount() == 0)
522 if (tree.getV_parent() != null
523 && tree.getV_parent() instanceof uk.ac.vamsas.objects.core.Alignment)
525 javport = getViewport(tree.getV_parent());
526 jal = javport.getAlignment();
527 view = javport.getAlignment().getCompactAlignment();
532 // Explicit reference - to alignment, sequences or what.
533 if (vInput.getObjRefCount() == 1
534 && vInput.getObjRef(0) instanceof uk.ac.vamsas.objects.core.Alignment)
536 // recover an AlignmentView for the input data
537 javport = getViewport((Vobject) vInput.getObjRef(0));
538 jal = javport.getAlignment();
539 view = javport.getAlignment().getCompactAlignment();
541 else if (vInput.getObjRef(0) instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
543 // recover an AlignmentView for the input data
544 javport = getViewport(((Vobject) vInput.getObjRef(0))
546 jal = javport.getAlignment();
547 jalview.datamodel.SequenceI[] seqs = new jalview.datamodel.SequenceI[vInput
549 for (int i = 0, iSize = vInput.getObjRefCount(); i < iSize; i++)
551 SequenceI seq = (SequenceI) getvObj2jv((Vobject) vInput
555 view = new jalview.datamodel.Alignment(seqs)
556 .getCompactAlignment();
560 int from = 1, to = jal.getWidth();
561 int offset = 0; // deleteRange modifies its frame of reference
562 for (int r = 0, s = vInput.getSegCount(); r < s; r++)
564 Seg visSeg = vInput.getSeg(r);
565 int se[] = getSegRange(visSeg, true); // jalview doesn't do
566 // bidirection alignments yet.
569 Cache.log.warn("Ignoring invalid segment in InputData spec.");
575 view.deleteRange(offset + from - 1, offset + se[0] - 2);
576 offset -= se[0] - from;
583 view.deleteRange(offset + from - 1, offset + to - 1); // final
590 { new AlignmentView(view), jal };
594 .debug("Returning null for input data recovery from provenance.");
598 private AlignViewport getViewport(Vobject v_parent)
600 if (v_parent instanceof uk.ac.vamsas.objects.core.Alignment)
603 .findViewport((uk.ac.vamsas.objects.core.Alignment) v_parent);
608 public NewickFile getNewickTree()
613 public String getTitle()
618 public AlignmentView getInputData()
623 public boolean isValidTree()
632 if (ntree.getTree() != null)
637 } catch (Exception e)
639 Cache.log.debug("Failed to parse newick tree string", e);