2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3 * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 package jalview.io.vamsas;
21 import java.io.IOException;
22 import java.util.Enumeration;
23 import java.util.Hashtable;
24 import java.util.Vector;
26 import jalview.analysis.NJTree;
27 import jalview.analysis.SequenceIdMatcher;
28 import jalview.bin.Cache;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.AlignmentView;
31 import jalview.datamodel.BinaryNode;
32 import jalview.datamodel.SeqCigar;
33 import jalview.datamodel.Sequence;
34 import jalview.datamodel.SequenceI;
35 import jalview.datamodel.SequenceNode;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.AlignViewport;
38 import jalview.gui.TreePanel;
39 import jalview.io.NewickFile;
40 import jalview.io.VamsasAppDatastore;
41 import uk.ac.vamsas.client.Vobject;
42 import uk.ac.vamsas.objects.core.AlignmentSequence;
43 import uk.ac.vamsas.objects.core.Entry;
44 import uk.ac.vamsas.objects.core.Input;
45 import uk.ac.vamsas.objects.core.Newick;
46 import uk.ac.vamsas.objects.core.Param;
47 import uk.ac.vamsas.objects.core.Provenance;
48 import uk.ac.vamsas.objects.core.Seg;
49 import uk.ac.vamsas.objects.core.Treenode;
50 import uk.ac.vamsas.objects.core.Vref;
52 public class Tree extends DatastoreItem
58 uk.ac.vamsas.objects.core.Tree tree;
60 uk.ac.vamsas.objects.core.Alignment alignment; // may be null => dataset or
63 private NewickFile ntree;
67 private AlignmentView inputData = null;
69 public static void updateFrom(VamsasAppDatastore datastore,
70 jalview.gui.AlignFrame alignFrame,
71 uk.ac.vamsas.objects.core.Tree vtree)
73 Tree toTree = new Tree(datastore, alignFrame, vtree);
77 public Tree(VamsasAppDatastore datastore,
78 jalview.gui.AlignFrame alignFrame,
79 uk.ac.vamsas.objects.core.Tree vtree)
83 TreePanel tp = (TreePanel) getvObj2jv(tree);
89 .info("Update from vamsas document to alignment associated tree not implemented yet.");
95 Object[] idata = recoverInputData(tree.getProvenance());
98 if (idata != null && idata[0] != null)
100 inputData = (AlignmentView) idata[0];
103 title = tree.getNewick(0).getTitle();
104 if (title == null || title.length() == 0)
106 title = tree.getTitle(); // hack!!!!
108 } catch (Exception e)
110 Cache.log.warn("Problems parsing treefile '"
111 + tree.getNewick(0).getContent() + "'", e);
116 private NewickFile getNtree() throws IOException
118 return new jalview.io.NewickFile(tree.getNewick(0).getContent());
121 public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2,
122 uk.ac.vamsas.objects.core.Alignment alignment2)
128 alignment = alignment2;
130 tree = (uk.ac.vamsas.objects.core.Tree) getjv2vObj(tp);
137 if (isModifiable(tree.getModifiable()))
139 // synchronize(); // update();
140 // verify any changes.
141 System.out.println("Update tree in document.");
146 System.out.println("Add modified tree as new tree in document.");
152 * correctly creates provenance for trees calculated on an alignment by
159 private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
161 Cache.log.debug("Making Tree provenance for " + tp.getTitle());
162 Provenance prov = new Provenance();
163 prov.addEntry(new Entry());
164 prov.getEntry(0).setAction("imported " + tp.getTitle());
165 prov.getEntry(0).setUser(provEntry.getUser());
166 prov.getEntry(0).setApp(provEntry.getApp());
167 prov.getEntry(0).setDate(provEntry.getDate());
168 if (tp.getTree().hasOriginalSequenceData())
170 Input vInput = new Input();
171 // LATER: check to see if tree input data is contained in this alignment -
172 // or just correctly resolve the tree's seqData to the correct alignment
175 Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal, tp
176 .getTree().seqData.getSequences()));
177 Object[] alsqs = new Object[alsqrefs.size()];
178 alsqrefs.copyInto(alsqs);
179 vInput.setObjRef(alsqs);
180 // now create main provenance data
181 prov.getEntry(0).setAction("created " + tp.getTitle());
182 prov.getEntry(0).addInput(vInput);
183 // jalview's special input parameter for distance matrix calculations
184 vInput.setName("jalview:seqdist"); // TODO: settle on appropriate name.
185 prov.getEntry(0).addParam(new Param());
186 prov.getEntry(0).getParam(0).setName("treeType");
187 prov.getEntry(0).getParam(0).setType("utf8");
188 prov.getEntry(0).getParam(0).setContent("NJ"); // TODO: type of tree is a
190 int ranges[] = tp.getTree().seqData.getVisibleContigs();
191 // VisibleContigs are with respect to alignment coordinates. Still need
193 int start = tp.getTree().seqData.getAlignmentOrigin();
194 for (int r = 0; r < ranges.length; r += 2)
196 Seg visSeg = new Seg();
197 visSeg.setStart(1 + start + ranges[r]);
198 visSeg.setEnd(start + ranges[r + 1]);
199 visSeg.setInclusive(true);
200 vInput.addSeg(visSeg);
203 Cache.log.debug("Finished Tree provenance for " + tp.getTitle());
208 * look up SeqCigars in an existing alignment.
212 * @return vector of alignment sequences in order of SeqCigar array (but
213 * missing unfound seqcigars)
215 private Vector findAlignmentSequences(AlignmentI jal, SeqCigar[] sequences)
217 SeqCigar[] tseqs = new SeqCigar[sequences.length];
218 System.arraycopy(sequences, 0, tseqs, 0, sequences.length);
219 Vector alsq = new Vector();
220 Enumeration as = jal.getSequences().elements();
221 while (as.hasMoreElements())
223 SequenceI asq = (SequenceI) as.nextElement();
224 for (int t = 0; t < sequences.length; t++)
227 && (tseqs[t].getRefSeq() == asq || tseqs[t].getRefSeq() == asq
228 .getDatasetSequence()))
229 // && tseqs[t].getStart()>=asq.getStart() &&
230 // tseqs[t].getEnd()<=asq.getEnd())
237 if (alsq.size() < sequences.length)
239 .warn("Not recovered all alignment sequences for given set of input sequence CIGARS");
245 * Update jalview newick representation with TreeNode map
248 * the treepanel that this tree is bound to.
250 public void UpdateSequenceTreeMap(TreePanel tp)
252 if (tp == null || tree == null)
254 Vector leaves = new Vector();
255 if (tp.getTree() == null)
257 Cache.log.warn("Not updating SequenceTreeMap for "
258 + tree.getVorbaId());
261 tp.getTree().findLeaves(tp.getTree().getTopNode(), leaves);
262 Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
269 Treenode node = tn[i++];
270 BinaryNode mappednode = findNodeSpec(node.getNodespec(), leaves);
271 if (mappednode != null && mappednode instanceof SequenceNode)
273 SequenceNode leaf = (SequenceNode) mappednode;
274 // check if we can make the specified association
276 int vrf = 0, refv = 0;
277 while (jvseq == null && vrf < node.getVrefCount())
279 if (refv < node.getVref(vrf).getRefsCount())
281 Object noderef = node.getVref(vrf).getRefs(refv++);
282 if (noderef instanceof AlignmentSequence)
284 // we only make these kind of associations
285 jvseq = getvObj2jv((Vobject) noderef);
294 if (jvseq instanceof SequenceI)
296 leaf.setElement(jvseq);
297 leaf.setPlaceholder(false);
301 leaf.setPlaceholder(true);
303 .setElement(new Sequence(leaf.getName(),
304 "THISISAPLACEHLDER"));
310 // / TODO: refactor to vamsas :start
312 * construct treenode mappings for mapped sequences
318 public Treenode[] makeTreeNodes(NJTree ntree, Newick newick)
320 Vector leaves = new Vector();
321 ntree.findLeaves(ntree.getTopNode(), leaves);
322 Vector tnv = new Vector();
323 Enumeration l = leaves.elements();
324 Hashtable nodespecs = new Hashtable();
325 while (l.hasMoreElements())
327 jalview.datamodel.BinaryNode tnode = (jalview.datamodel.BinaryNode) l
329 if (tnode instanceof jalview.datamodel.SequenceNode)
331 if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
333 Object assocseq = ((jalview.datamodel.SequenceNode) tnode)
335 if (assocseq instanceof SequenceI)
337 Vobject vobj = this.getjv2vObj(assocseq);
340 Treenode node = new Treenode();
341 if (newick.isRegisterable())
343 this.cdoc.registerObject(newick);
344 node.addTreeId(newick);
346 node.setNodespec(makeNodeSpec(nodespecs, tnode));
347 node.setName(tnode.getName());
348 Vref vr = new Vref();
351 tnv.addElement(node);
355 System.err.println("WARNING: Unassociated treeNode "
356 + tnode.element().toString()
358 + ((tnode.getName() != null) ? " label "
359 + tnode.getName() : ""));
367 Treenode[] tn = new Treenode[tnv.size()];
371 return new Treenode[]
375 private String makeNodeSpec(Hashtable nodespecs,
376 jalview.datamodel.BinaryNode tnode)
378 String nname = new String(tnode.getName());
379 Integer nindx = (Integer) nodespecs.get(nname);
382 nindx = new Integer(1);
384 nname = nindx.toString() + " " + nname;
389 * call to match up Treenode specs to NJTree parsed from document object.
393 * as returned from NJTree.findLeaves( .., ..) ..
396 private jalview.datamodel.BinaryNode findNodeSpec(String nodespec,
400 String nspec = nodespec.substring(nodespec.indexOf(' ') + 1);
401 String oval = nodespec.substring(0, nodespec.indexOf(' '));
404 occurence = new Integer(oval).intValue();
405 } catch (Exception e)
407 System.err.println("Invalid nodespec '" + nodespec + "'");
410 jalview.datamodel.BinaryNode bn = null;
413 Enumeration en = leaves.elements();
414 while (en.hasMoreElements() && nocc < occurence)
416 bn = (jalview.datamodel.BinaryNode) en.nextElement();
417 if (bn instanceof jalview.datamodel.SequenceNode
418 && bn.getName().equals(nspec))
428 // todo: end refactor to vamsas library
430 * add jalview object to vamsas document
435 tree = new uk.ac.vamsas.objects.core.Tree();
436 bindjvvobj(tp, tree);
437 tree.setTitle(tp.getTitle());
438 Newick newick = new Newick();
439 newick.setContent(tp.getTree().toString());
440 newick.setTitle(tp.getTitle());
441 tree.addNewick(newick);
442 tree.setProvenance(makeTreeProvenance(jal, tp));
443 tree.setTreenode(makeTreeNodes(tp.getTree(), newick));
445 alignment.addTree(tree);
449 * note: this function assumes that all sequence and alignment objects
450 * referenced in input data has already been associated with jalview objects.
454 * @return Object[] { AlignmentView, AlignmentI - reference alignment for
457 public Object[] recoverInputData(Provenance tp)
459 AlignViewport javport = null;
460 jalview.datamodel.AlignmentI jal = null;
461 jalview.datamodel.CigarArray view = null;
462 for (int pe = 0; pe < tp.getEntryCount(); pe++)
464 if (tp.getEntry(pe).getInputCount() > 0)
466 if (tp.getEntry(pe).getInputCount() > 1)
469 .warn("Ignoring additional input spec in provenance entry "
470 + tp.getEntry(pe).toString());
472 // LATER: deal sensibly with multiple inputs
473 Input vInput = tp.getEntry(pe).getInput(0);
474 // is this the whole alignment or a specific set of sequences ?
475 if (vInput.getObjRefCount() == 0)
477 if (tree.getV_parent() != null
478 && tree.getV_parent() instanceof uk.ac.vamsas.objects.core.Alignment)
480 javport = getViewport(tree.getV_parent());
481 jal = javport.getAlignment();
482 view = javport.getAlignment().getCompactAlignment();
487 // Explicit reference - to alignment, sequences or what.
488 if (vInput.getObjRefCount() == 1
489 && vInput.getObjRef(0) instanceof uk.ac.vamsas.objects.core.Alignment)
491 // recover an AlignmentView for the input data
492 javport = getViewport((Vobject) vInput.getObjRef(0));
493 jal = javport.getAlignment();
494 view = javport.getAlignment().getCompactAlignment();
496 else if (vInput.getObjRef(0) instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
498 // recover an AlignmentView for the input data
499 javport = getViewport(((Vobject) vInput.getObjRef(0))
501 jal = javport.getAlignment();
502 jalview.datamodel.SequenceI[] seqs = new jalview.datamodel.SequenceI[vInput
504 for (int i = 0, iSize = vInput.getObjRefCount(); i < iSize; i++)
506 SequenceI seq = (SequenceI) getvObj2jv((Vobject) vInput
510 view = new jalview.datamodel.Alignment(seqs)
511 .getCompactAlignment();
515 int from = 1, to = jal.getWidth();
516 int offset = 0; // deleteRange modifies its frame of reference
517 for (int r = 0, s = vInput.getSegCount(); r < s; r++)
519 Seg visSeg = vInput.getSeg(r);
520 int se[] = getSegRange(visSeg, true); // jalview doesn't do
521 // bidirection alignments yet.
524 Cache.log.warn("Ignoring invalid segment in InputData spec.");
530 view.deleteRange(offset + from - 1, offset + se[0] - 2);
531 offset -= se[0] - from;
538 view.deleteRange(offset + from - 1, offset + to - 1); // final
545 { new AlignmentView(view), jal };
549 .debug("Returning null for input data recovery from provenance.");
553 private AlignViewport getViewport(Vobject v_parent)
555 if (v_parent instanceof uk.ac.vamsas.objects.core.Alignment)
558 .findViewport((uk.ac.vamsas.objects.core.Alignment) v_parent);
563 public NewickFile getNewickTree()
568 public String getTitle()
573 public AlignmentView getInputData()
578 public boolean isValidTree()
587 if (ntree.getTree() != null)
592 } catch (Exception e)
594 Cache.log.debug("Failed to parse newick tree string", e);