2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.io.vamsas;
23 import jalview.analysis.TreeBuilder;
24 import jalview.analysis.TreeModel;
25 import jalview.bin.Cache;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.AlignmentView;
28 import jalview.datamodel.BinaryNode;
29 import jalview.datamodel.SeqCigar;
30 import jalview.datamodel.Sequence;
31 import jalview.datamodel.SequenceI;
32 import jalview.datamodel.SequenceNode;
33 import jalview.gui.TreePanel;
34 import jalview.io.NewickFile;
35 import jalview.io.VamsasAppDatastore;
36 import jalview.viewmodel.AlignmentViewport;
38 import java.io.IOException;
39 import java.util.Enumeration;
40 import java.util.Hashtable;
41 import java.util.List;
42 import java.util.Vector;
44 import uk.ac.vamsas.client.Vobject;
45 import uk.ac.vamsas.objects.core.AlignmentSequence;
46 import uk.ac.vamsas.objects.core.Entry;
47 import uk.ac.vamsas.objects.core.Input;
48 import uk.ac.vamsas.objects.core.Newick;
49 import uk.ac.vamsas.objects.core.Param;
50 import uk.ac.vamsas.objects.core.Provenance;
51 import uk.ac.vamsas.objects.core.Seg;
52 import uk.ac.vamsas.objects.core.Treenode;
53 import uk.ac.vamsas.objects.core.Vref;
55 public class Tree extends DatastoreItem
61 uk.ac.vamsas.objects.core.Tree tree;
63 uk.ac.vamsas.objects.core.Alignment alignment; // may be null => dataset or
66 private NewickFile ntree;
70 private AlignmentView inputData = null;
72 public static void updateFrom(VamsasAppDatastore datastore,
73 jalview.gui.AlignFrame alignFrame,
74 uk.ac.vamsas.objects.core.Tree vtree)
76 Tree toTree = new Tree(datastore, alignFrame, vtree);
79 public Tree(VamsasAppDatastore datastore,
80 jalview.gui.AlignFrame alignFrame,
81 uk.ac.vamsas.objects.core.Tree vtree)
83 super(datastore, vtree, TreePanel.class);
87 private NewickFile getNtree() throws IOException
89 return new jalview.io.NewickFile(tree.getNewick(0).getContent());
92 public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2,
93 uk.ac.vamsas.objects.core.Alignment alignment2)
95 super(datastore, tp2, uk.ac.vamsas.objects.core.Tree.class);
98 tp = (TreePanel) jvobj;
99 alignment = alignment2;
101 tree = (uk.ac.vamsas.objects.core.Tree) vobj;
108 * @see jalview.io.vamsas.DatastoreItem#addFromDocument()
111 public void addFromDocument()
113 tree = (uk.ac.vamsas.objects.core.Tree) vobj; // vtree;
114 TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
116 Object[] idata = recoverInputData(tree.getProvenance());
119 if (idata != null && idata[0] != null)
121 inputData = (AlignmentView) idata[0];
124 title = tree.getNewick(0).getTitle();
125 if (title == null || title.length() == 0)
127 title = tree.getTitle(); // hack!!!!
129 } catch (Exception e)
131 Cache.log.warn("Problems parsing treefile '"
132 + tree.getNewick(0).getContent() + "'", e);
139 * @see jalview.io.vamsas.DatastoreItem#conflict()
142 public void conflict()
145 "Update (with conflict) from vamsas document to alignment associated tree not implemented yet.");
151 * @see jalview.io.vamsas.DatastoreItem#update()
154 public void updateToDoc()
156 if (isModifiable(tree.getModifiable()))
158 // synchronize(); // update();
159 // verify any changes.
160 log.info("TODO: Update tree in document from jalview.");
166 "TODO: Add the locally modified tree in Jalview as a new tree in document, leaving locked tree unchanged.");
173 * @see jalview.io.vamsas.DatastoreItem#updateFromDoc()
176 public void updateFromDoc()
178 // should probably just open a new tree panel in the same place as the old
180 // TODO: Tree.updateFromDoc
182 * TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
184 * // make a new tree Object[] idata =
185 * recoverInputData(tree.getProvenance()); try { if (idata != null &&
186 * idata[0] != null) { inputData = (AlignmentView) idata[0]; } ntree =
187 * getNtree(); title = tree.getNewick(0).getTitle(); if (title == null ||
188 * title.length() == 0) { title = tree.getTitle(); // hack!!!! } } catch
189 * (Exception e) { Cache.log.warn("Problems parsing treefile '" +
190 * tree.getNewick(0).getContent() + "'", e); }
192 log.debug("Update the local tree in jalview from the document.");
194 if (isModifiable(tree.getModifiable()))
196 // synchronize(); // update();
197 // verify any changes.
198 log.debug("Update tree in document from jalview.");
203 log.debug("Add modified jalview tree as new tree in document.");
208 * correctly creates provenance for trees calculated on an alignment by
215 private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
217 Cache.log.debug("Making Tree provenance for " + tp.getTitle());
218 Provenance prov = new Provenance();
219 prov.addEntry(new Entry());
220 prov.getEntry(0).setAction("imported " + tp.getTitle());
221 prov.getEntry(0).setUser(provEntry.getUser());
222 prov.getEntry(0).setApp(provEntry.getApp());
223 prov.getEntry(0).setDate(provEntry.getDate());
225 AlignmentView originalData = tp.getTree().getOriginalData();
226 if (originalData != null)
228 Input vInput = new Input();
229 // LATER: check to see if tree input data is contained in this alignment -
230 // or just correctly resolve the tree's seqData to the correct alignment
233 Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal,
234 tp.getTree().getOriginalData().getSequences()));
235 Object[] alsqs = new Object[alsqrefs.size()];
236 alsqrefs.copyInto(alsqs);
237 vInput.setObjRef(alsqs);
238 // now create main provenance data
239 prov.getEntry(0).setAction("created " + tp.getTitle());
240 prov.getEntry(0).addInput(vInput);
241 // jalview's special input parameter for distance matrix calculations
242 vInput.setName("jalview:seqdist"); // TODO: settle on appropriate name.
243 prov.getEntry(0).addParam(new Param());
244 prov.getEntry(0).getParam(0).setName("treeType");
245 prov.getEntry(0).getParam(0).setType("utf8");
246 prov.getEntry(0).getParam(0)
247 .setContent(TreeBuilder.NEIGHBOUR_JOINING);
248 // TODO: type of tree is a general parameter
249 int ranges[] = originalData.getVisibleContigs();
250 // VisibleContigs are with respect to alignment coordinates. Still need
252 int start = tp.getTree().getOriginalData().getAlignmentOrigin();
253 for (int r = 0; r < ranges.length; r += 2)
255 Seg visSeg = new Seg();
256 visSeg.setStart(1 + start + ranges[r]);
257 visSeg.setEnd(start + ranges[r + 1]);
258 visSeg.setInclusive(true);
259 vInput.addSeg(visSeg);
262 Cache.log.debug("Finished Tree provenance for " + tp.getTitle());
267 * look up SeqCigars in an existing alignment.
271 * @return vector of alignment sequences in order of SeqCigar array (but
272 * missing unfound seqcigars)
274 private Vector<SequenceI> findAlignmentSequences(AlignmentI jal,
275 SeqCigar[] sequences)
277 SeqCigar[] tseqs = new SeqCigar[sequences.length];
278 System.arraycopy(sequences, 0, tseqs, 0, sequences.length);
279 Vector<SequenceI> alsq = new Vector<>();
280 List<SequenceI> jalsqs = jal.getSequences();
281 synchronized (jalsqs)
283 for (SequenceI asq : jalsqs)
285 for (int t = 0; t < sequences.length; t++)
287 if (tseqs[t] != null && (tseqs[t].getRefSeq() == asq
288 || tseqs[t].getRefSeq() == asq.getDatasetSequence()))
289 // && tseqs[t].getStart()>=asq.getStart() &&
290 // tseqs[t].getEnd()<=asq.getEnd())
298 if (alsq.size() < sequences.length)
301 "Not recovered all alignment sequences for given set of input sequence CIGARS");
308 * Update jalview newick representation with TreeNode map
311 * the treepanel that this tree is bound to.
313 public void UpdateSequenceTreeMap(TreePanel tp)
315 if (tp == null || tree == null)
320 if (tp.getTree() == null)
323 "Not updating SequenceTreeMap for " + tree.getVorbaId());
326 Vector<SequenceNode> leaves = tp.getTree()
327 .findLeaves(tp.getTree().getTopNode());
328 Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
335 Treenode node = tn[i++];
336 BinaryNode mappednode = findNodeSpec(node.getNodespec(), leaves);
337 if (mappednode != null && mappednode instanceof SequenceNode)
339 SequenceNode leaf = (SequenceNode) mappednode;
340 // check if we can make the specified association
342 int vrf = 0, refv = 0;
343 while (jvseq == null && vrf < node.getVrefCount())
345 if (refv < node.getVref(vrf).getRefsCount())
347 Object noderef = node.getVref(vrf).getRefs(refv++);
348 if (noderef instanceof AlignmentSequence)
350 // we only make these kind of associations
351 jvseq = getvObj2jv((Vobject) noderef);
360 if (jvseq instanceof SequenceI)
362 leaf.setElement(jvseq);
363 leaf.setPlaceholder(false);
367 leaf.setPlaceholder(true);
369 new Sequence(leaf.getName(), "THISISAPLACEHLDER"));
375 // / TODO: refactor to vamsas :start
377 * construct treenode mappings for mapped sequences
383 public Treenode[] makeTreeNodes(TreeModel treeModel, Newick newick)
385 Vector<SequenceNode> leaves = treeModel
386 .findLeaves(treeModel.getTopNode());
387 Vector tnv = new Vector();
388 Enumeration l = leaves.elements();
389 Hashtable nodespecs = new Hashtable();
390 while (l.hasMoreElements())
392 jalview.datamodel.BinaryNode tnode = (jalview.datamodel.BinaryNode) l
394 if (tnode instanceof jalview.datamodel.SequenceNode)
396 if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
398 Object assocseq = ((jalview.datamodel.SequenceNode) tnode)
400 if (assocseq instanceof SequenceI)
402 Vobject vobj = this.getjv2vObj(assocseq);
405 Treenode node = new Treenode();
406 if (newick.isRegisterable())
408 this.cdoc.registerObject(newick);
409 node.addTreeId(newick);
411 node.setNodespec(makeNodeSpec(nodespecs, tnode));
412 node.setName(tnode.getName());
413 Vref vr = new Vref();
416 tnv.addElement(node);
420 System.err.println("WARNING: Unassociated treeNode "
421 + tnode.element().toString() + " "
422 + ((tnode.getName() != null)
423 ? " label " + tnode.getName()
432 Treenode[] tn = new Treenode[tnv.size()];
436 return new Treenode[] {};
439 private String makeNodeSpec(Hashtable nodespecs,
440 jalview.datamodel.BinaryNode tnode)
442 String nname = new String(tnode.getName());
443 Integer nindx = (Integer) nodespecs.get(nname);
446 nindx = new Integer(1);
448 nname = nindx.toString() + " " + nname;
453 * call to match up Treenode specs to NJTree parsed from document object.
457 * as returned from NJTree.findLeaves( .., ..) ..
460 private jalview.datamodel.BinaryNode findNodeSpec(String nodespec,
464 String nspec = nodespec.substring(nodespec.indexOf(' ') + 1);
465 String oval = nodespec.substring(0, nodespec.indexOf(' '));
468 occurence = new Integer(oval).intValue();
469 } catch (Exception e)
471 System.err.println("Invalid nodespec '" + nodespec + "'");
474 jalview.datamodel.BinaryNode bn = null;
477 Enumeration en = leaves.elements();
478 while (en.hasMoreElements() && nocc < occurence)
480 bn = (jalview.datamodel.BinaryNode) en.nextElement();
481 if (bn instanceof jalview.datamodel.SequenceNode
482 && bn.getName().equals(nspec))
494 // todo: end refactor to vamsas library
496 * add jalview object to vamsas document
500 public void addToDocument()
502 tree = new uk.ac.vamsas.objects.core.Tree();
503 bindjvvobj(tp, tree);
504 tree.setTitle(tp.getTitle());
505 Newick newick = new Newick();
506 newick.setContent(tp.getTree().print());
507 newick.setTitle(tp.getTitle());
508 tree.addNewick(newick);
509 tree.setProvenance(makeTreeProvenance(jal, tp));
510 tree.setTreenode(makeTreeNodes(tp.getTree(), newick));
512 alignment.addTree(tree);
516 * note: this function assumes that all sequence and alignment objects
517 * referenced in input data has already been associated with jalview objects.
521 * @return Object[] { AlignmentView, AlignmentI - reference alignment for
524 public Object[] recoverInputData(Provenance tp)
526 AlignmentViewport javport = null;
527 jalview.datamodel.AlignmentI jal = null;
528 jalview.datamodel.CigarArray view = null;
529 for (int pe = 0; pe < tp.getEntryCount(); pe++)
531 if (tp.getEntry(pe).getInputCount() > 0)
533 if (tp.getEntry(pe).getInputCount() > 1)
536 "Ignoring additional input spec in provenance entry "
537 + tp.getEntry(pe).toString());
539 // LATER: deal sensibly with multiple inputs
540 Input vInput = tp.getEntry(pe).getInput(0);
541 // is this the whole alignment or a specific set of sequences ?
542 if (vInput.getObjRefCount() == 0)
544 if (tree.getV_parent() != null && tree
545 .getV_parent() instanceof uk.ac.vamsas.objects.core.Alignment)
547 javport = getViewport(tree.getV_parent());
548 jal = javport.getAlignment();
549 view = javport.getAlignment().getCompactAlignment();
554 // Explicit reference - to alignment, sequences or what.
555 if (vInput.getObjRefCount() == 1 && vInput.getObjRef(
556 0) instanceof uk.ac.vamsas.objects.core.Alignment)
558 // recover an AlignmentView for the input data
559 javport = getViewport((Vobject) vInput.getObjRef(0));
560 jal = javport.getAlignment();
561 view = javport.getAlignment().getCompactAlignment();
563 else if (vInput.getObjRef(
564 0) instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
566 // recover an AlignmentView for the input data
567 javport = getViewport(
568 ((Vobject) vInput.getObjRef(0)).getV_parent());
569 jal = javport.getAlignment();
570 jalview.datamodel.SequenceI[] seqs = new jalview.datamodel.SequenceI[vInput
572 for (int i = 0, iSize = vInput.getObjRefCount(); i < iSize; i++)
574 SequenceI seq = (SequenceI) getvObj2jv(
575 (Vobject) vInput.getObjRef(i));
578 view = new jalview.datamodel.Alignment(seqs)
579 .getCompactAlignment();
583 int from = 1, to = jal.getWidth();
584 int offset = 0; // deleteRange modifies its frame of reference
585 for (int r = 0, s = vInput.getSegCount(); r < s; r++)
587 Seg visSeg = vInput.getSeg(r);
588 int se[] = getSegRange(visSeg, true); // jalview doesn't do
589 // bidirection alignments yet.
592 Cache.log.warn("Ignoring invalid segment in InputData spec.");
598 view.deleteRange(offset + from - 1, offset + se[0] - 2);
599 offset -= se[0] - from;
606 view.deleteRange(offset + from - 1, offset + to - 1); // final
612 return new Object[] { new AlignmentView(view), jal };
616 "Returning null for input data recovery from provenance.");
620 private AlignmentViewport getViewport(Vobject v_parent)
622 if (v_parent instanceof uk.ac.vamsas.objects.core.Alignment)
625 .findViewport((uk.ac.vamsas.objects.core.Alignment) v_parent);
630 public NewickFile getNewickTree()
635 public String getTitle()
640 public AlignmentView getInputData()
645 public boolean isValidTree()
654 if (ntree.getTree() != null)
659 } catch (Exception e)
661 Cache.log.debug("Failed to parse newick tree string", e);