Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.io.vamsas

File Tree.java

 

Coverage histogram

../../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

86
217
21
1
665
486
78
0.36
10.33
21
3.71

Classes

Class Line # Actions
Tree 55 217 78 324
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.io.vamsas;
22   
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;
37   
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;
43   
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;
54   
 
55    public class Tree extends DatastoreItem
56    {
57    AlignmentI jal;
58   
59    TreePanel tp;
60   
61    uk.ac.vamsas.objects.core.Tree tree;
62   
63    uk.ac.vamsas.objects.core.Alignment alignment; // may be null => dataset or
64   
65    // other kind of tree
66    private NewickFile ntree;
67   
68    private String title;
69   
70    private AlignmentView inputData = null;
71   
 
72  0 toggle public static void updateFrom(VamsasAppDatastore datastore,
73    jalview.gui.AlignFrame alignFrame,
74    uk.ac.vamsas.objects.core.Tree vtree)
75    {
76  0 Tree toTree = new Tree(datastore, alignFrame, vtree);
77    }
78   
 
79  0 toggle public Tree(VamsasAppDatastore datastore,
80    jalview.gui.AlignFrame alignFrame,
81    uk.ac.vamsas.objects.core.Tree vtree)
82    {
83  0 super(datastore, vtree, TreePanel.class);
84  0 doJvUpdate();
85    }
86   
 
87  0 toggle private NewickFile getNtree() throws IOException
88    {
89  0 return new jalview.io.NewickFile(tree.getNewick(0).getContent());
90    }
91   
 
92  0 toggle public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2,
93    uk.ac.vamsas.objects.core.Alignment alignment2)
94    {
95  0 super(datastore, tp2, uk.ac.vamsas.objects.core.Tree.class);
96   
97  0 jal = jal2;
98  0 tp = (TreePanel) jvobj;
99  0 alignment = alignment2;
100   
101  0 tree = (uk.ac.vamsas.objects.core.Tree) vobj;
102  0 doSync();
103    }
104   
105    /*
106    * (non-Javadoc)
107    *
108    * @see jalview.io.vamsas.DatastoreItem#addFromDocument()
109    */
 
110  0 toggle @Override
111    public void addFromDocument()
112    {
113  0 tree = (uk.ac.vamsas.objects.core.Tree) vobj; // vtree;
114  0 TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
115    // make a new tree
116  0 Object[] idata = recoverInputData(tree.getProvenance());
117  0 try
118    {
119  0 if (idata != null && idata[0] != null)
120    {
121  0 inputData = (AlignmentView) idata[0];
122    }
123  0 ntree = getNtree();
124  0 title = tree.getNewick(0).getTitle();
125  0 if (title == null || title.length() == 0)
126    {
127  0 title = tree.getTitle(); // hack!!!!
128    }
129    } catch (Exception e)
130    {
131  0 Cache.log.warn("Problems parsing treefile '"
132    + tree.getNewick(0).getContent() + "'", e);
133    }
134    }
135   
136    /*
137    * (non-Javadoc)
138    *
139    * @see jalview.io.vamsas.DatastoreItem#conflict()
140    */
 
141  0 toggle @Override
142    public void conflict()
143    {
144  0 Cache.log.info(
145    "Update (with conflict) from vamsas document to alignment associated tree not implemented yet.");
146    }
147   
148    /*
149    * (non-Javadoc)
150    *
151    * @see jalview.io.vamsas.DatastoreItem#update()
152    */
 
153  0 toggle @Override
154    public void updateToDoc()
155    {
156  0 if (isModifiable(tree.getModifiable()))
157    {
158    // synchronize(); // update();
159    // verify any changes.
160  0 log.info("TODO: Update tree in document from jalview.");
161    }
162    else
163    {
164    // handle conflict
165  0 log.info(
166    "TODO: Add the locally modified tree in Jalview as a new tree in document, leaving locked tree unchanged.");
167    }
168    }
169   
170    /*
171    * (non-Javadoc)
172    *
173    * @see jalview.io.vamsas.DatastoreItem#updateFromDoc()
174    */
 
175  0 toggle @Override
176    public void updateFromDoc()
177    {
178    // should probably just open a new tree panel in the same place as the old
179    // one
180    // TODO: Tree.updateFromDoc
181    /*
182    * TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
183    *
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); }
191    */
192  0 log.debug("Update the local tree in jalview from the document.");
193   
194  0 if (isModifiable(tree.getModifiable()))
195    {
196    // synchronize(); // update();
197    // verify any changes.
198  0 log.debug("Update tree in document from jalview.");
199    }
200    else
201    {
202    // handle conflict
203  0 log.debug("Add modified jalview tree as new tree in document.");
204    }
205    }
206   
207    /**
208    * correctly creates provenance for trees calculated on an alignment by
209    * jalview.
210    *
211    * @param jal
212    * @param tp
213    * @return
214    */
 
215  0 toggle private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
216    {
217  0 Cache.log.debug("Making Tree provenance for " + tp.getTitle());
218  0 Provenance prov = new Provenance();
219  0 prov.addEntry(new Entry());
220  0 prov.getEntry(0).setAction("imported " + tp.getTitle());
221  0 prov.getEntry(0).setUser(provEntry.getUser());
222  0 prov.getEntry(0).setApp(provEntry.getApp());
223  0 prov.getEntry(0).setDate(provEntry.getDate());
224   
225  0 AlignmentView originalData = tp.getTree().getOriginalData();
226  0 if (originalData != null)
227    {
228  0 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
231    // in
232    // the document.
233  0 Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal,
234    tp.getTree().getOriginalData().getSequences()));
235  0 Object[] alsqs = new Object[alsqrefs.size()];
236  0 alsqrefs.copyInto(alsqs);
237  0 vInput.setObjRef(alsqs);
238    // now create main provenance data
239  0 prov.getEntry(0).setAction("created " + tp.getTitle());
240  0 prov.getEntry(0).addInput(vInput);
241    // jalview's special input parameter for distance matrix calculations
242  0 vInput.setName("jalview:seqdist"); // TODO: settle on appropriate name.
243  0 prov.getEntry(0).addParam(new Param());
244  0 prov.getEntry(0).getParam(0).setName("treeType");
245  0 prov.getEntry(0).getParam(0).setType("utf8");
246  0 prov.getEntry(0).getParam(0)
247    .setContent(TreeBuilder.NEIGHBOUR_JOINING);
248    // TODO: type of tree is a general parameter
249  0 int ranges[] = originalData.getVisibleContigs();
250    // VisibleContigs are with respect to alignment coordinates. Still need
251    // offsets
252  0 int start = tp.getTree().getOriginalData().getAlignmentOrigin();
253  0 for (int r = 0; r < ranges.length; r += 2)
254    {
255  0 Seg visSeg = new Seg();
256  0 visSeg.setStart(1 + start + ranges[r]);
257  0 visSeg.setEnd(start + ranges[r + 1]);
258  0 visSeg.setInclusive(true);
259  0 vInput.addSeg(visSeg);
260    }
261    }
262  0 Cache.log.debug("Finished Tree provenance for " + tp.getTitle());
263  0 return prov;
264    }
265   
266    /**
267    * look up SeqCigars in an existing alignment.
268    *
269    * @param jal
270    * @param sequences
271    * @return vector of alignment sequences in order of SeqCigar array (but
272    * missing unfound seqcigars)
273    */
 
274  0 toggle private Vector<SequenceI> findAlignmentSequences(AlignmentI jal,
275    SeqCigar[] sequences)
276    {
277  0 SeqCigar[] tseqs = new SeqCigar[sequences.length];
278  0 System.arraycopy(sequences, 0, tseqs, 0, sequences.length);
279  0 Vector<SequenceI> alsq = new Vector<>();
280  0 List<SequenceI> jalsqs = jal.getSequences();
281  0 synchronized (jalsqs)
282    {
283  0 for (SequenceI asq : jalsqs)
284    {
285  0 for (int t = 0; t < sequences.length; t++)
286    {
287  0 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())
291    {
292  0 tseqs[t] = null;
293  0 alsq.add(asq);
294    }
295    }
296    }
297    }
298  0 if (alsq.size() < sequences.length)
299    {
300  0 Cache.log.warn(
301    "Not recovered all alignment sequences for given set of input sequence CIGARS");
302    }
303  0 return alsq;
304    }
305   
306    /**
307    *
308    * Update jalview newick representation with TreeNode map
309    *
310    * @param tp
311    * the treepanel that this tree is bound to.
312    */
 
313  0 toggle public void UpdateSequenceTreeMap(TreePanel tp)
314    {
315  0 if (tp == null || tree == null)
316    {
317  0 return;
318    }
319   
320  0 if (tp.getTree() == null)
321    {
322  0 Cache.log.warn(
323    "Not updating SequenceTreeMap for " + tree.getVorbaId());
324  0 return;
325    }
326  0 Vector<SequenceNode> leaves = tp.getTree()
327    .findLeaves(tp.getTree().getTopNode());
328  0 Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
329    // particular tree
330  0 int sz = tn.length;
331  0 int i = 0;
332   
333  0 while (i < sz)
334    {
335  0 Treenode node = tn[i++];
336  0 BinaryNode mappednode = findNodeSpec(node.getNodespec(), leaves);
337  0 if (mappednode != null && mappednode instanceof SequenceNode)
338    {
339  0 SequenceNode leaf = (SequenceNode) mappednode;
340    // check if we can make the specified association
341  0 Object jvseq = null;
342  0 int vrf = 0, refv = 0;
343  0 while (jvseq == null && vrf < node.getVrefCount())
344    {
345  0 if (refv < node.getVref(vrf).getRefsCount())
346    {
347  0 Object noderef = node.getVref(vrf).getRefs(refv++);
348  0 if (noderef instanceof AlignmentSequence)
349    {
350    // we only make these kind of associations
351  0 jvseq = getvObj2jv((Vobject) noderef);
352    }
353    }
354    else
355    {
356  0 refv = 0;
357  0 vrf++;
358    }
359    }
360  0 if (jvseq instanceof SequenceI)
361    {
362  0 leaf.setElement(jvseq);
363  0 leaf.setPlaceholder(false);
364    }
365    else
366    {
367  0 leaf.setPlaceholder(true);
368  0 leaf.setElement(
369    new Sequence(leaf.getName(), "THISISAPLACEHLDER"));
370    }
371    }
372    }
373    }
374   
375    // / TODO: refactor to vamsas :start
376    /**
377    * construct treenode mappings for mapped sequences
378    *
379    * @param treeModel
380    * @param newick
381    * @return
382    */
 
383  0 toggle public Treenode[] makeTreeNodes(TreeModel treeModel, Newick newick)
384    {
385  0 Vector<SequenceNode> leaves = treeModel
386    .findLeaves(treeModel.getTopNode());
387  0 Vector tnv = new Vector();
388  0 Enumeration l = leaves.elements();
389  0 Hashtable nodespecs = new Hashtable();
390  0 while (l.hasMoreElements())
391    {
392  0 jalview.datamodel.BinaryNode tnode = (jalview.datamodel.BinaryNode) l
393    .nextElement();
394  0 if (tnode instanceof jalview.datamodel.SequenceNode)
395    {
396  0 if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
397    {
398  0 Object assocseq = ((jalview.datamodel.SequenceNode) tnode)
399    .element();
400  0 if (assocseq instanceof SequenceI)
401    {
402  0 Vobject vobj = this.getjv2vObj(assocseq);
403  0 if (vobj != null)
404    {
405  0 Treenode node = new Treenode();
406  0 if (newick.isRegisterable())
407    {
408  0 this.cdoc.registerObject(newick);
409  0 node.addTreeId(newick);
410    }
411  0 node.setNodespec(makeNodeSpec(nodespecs, tnode));
412  0 node.setName(tnode.getName());
413  0 Vref vr = new Vref();
414  0 vr.addRefs(vobj);
415  0 node.addVref(vr);
416  0 tnv.addElement(node);
417    }
418    else
419    {
420  0 System.err.println("WARNING: Unassociated treeNode "
421    + tnode.element().toString() + " "
422  0 + ((tnode.getName() != null)
423    ? " label " + tnode.getName()
424    : ""));
425    }
426    }
427    }
428    }
429    }
430  0 if (tnv.size() > 0)
431    {
432  0 Treenode[] tn = new Treenode[tnv.size()];
433  0 tnv.copyInto(tn);
434  0 return tn;
435    }
436  0 return new Treenode[] {};
437    }
438   
 
439  0 toggle private String makeNodeSpec(Hashtable nodespecs,
440    jalview.datamodel.BinaryNode tnode)
441    {
442  0 String nname = new String(tnode.getName());
443  0 Integer nindx = (Integer) nodespecs.get(nname);
444  0 if (nindx == null)
445    {
446  0 nindx = new Integer(1);
447    }
448  0 nname = nindx.toString() + " " + nname;
449  0 return nname;
450    }
451   
452    /**
453    * call to match up Treenode specs to NJTree parsed from document object.
454    *
455    * @param nodespec
456    * @param leaves
457    * as returned from NJTree.findLeaves( .., ..) ..
458    * @return
459    */
 
460  0 toggle private jalview.datamodel.BinaryNode findNodeSpec(String nodespec,
461    Vector leaves)
462    {
463  0 int occurence = -1;
464  0 String nspec = nodespec.substring(nodespec.indexOf(' ') + 1);
465  0 String oval = nodespec.substring(0, nodespec.indexOf(' '));
466  0 try
467    {
468  0 occurence = new Integer(oval).intValue();
469    } catch (Exception e)
470    {
471  0 System.err.println("Invalid nodespec '" + nodespec + "'");
472  0 return null;
473    }
474  0 jalview.datamodel.BinaryNode bn = null;
475   
476  0 int nocc = 0;
477  0 Enumeration en = leaves.elements();
478  0 while (en.hasMoreElements() && nocc < occurence)
479    {
480  0 bn = (jalview.datamodel.BinaryNode) en.nextElement();
481  0 if (bn instanceof jalview.datamodel.SequenceNode
482    && bn.getName().equals(nspec))
483    {
484  0 --occurence;
485    }
486    else
487    {
488  0 bn = null;
489    }
490    }
491  0 return bn;
492    }
493   
494    // todo: end refactor to vamsas library
495    /**
496    * add jalview object to vamsas document
497    *
498    */
 
499  0 toggle @Override
500    public void addToDocument()
501    {
502  0 tree = new uk.ac.vamsas.objects.core.Tree();
503  0 bindjvvobj(tp, tree);
504  0 tree.setTitle(tp.getTitle());
505  0 Newick newick = new Newick();
506  0 newick.setContent(tp.getTree().print());
507  0 newick.setTitle(tp.getTitle());
508  0 tree.addNewick(newick);
509  0 tree.setProvenance(makeTreeProvenance(jal, tp));
510  0 tree.setTreenode(makeTreeNodes(tp.getTree(), newick));
511   
512  0 alignment.addTree(tree);
513    }
514   
515    /**
516    * note: this function assumes that all sequence and alignment objects
517    * referenced in input data has already been associated with jalview objects.
518    *
519    * @param tp
520    * @param alignFrame
521    * @return Object[] { AlignmentView, AlignmentI - reference alignment for
522    * input }
523    */
 
524  0 toggle public Object[] recoverInputData(Provenance tp)
525    {
526  0 AlignmentViewport javport = null;
527  0 jalview.datamodel.AlignmentI jal = null;
528  0 jalview.datamodel.CigarArray view = null;
529  0 for (int pe = 0; pe < tp.getEntryCount(); pe++)
530    {
531  0 if (tp.getEntry(pe).getInputCount() > 0)
532    {
533  0 if (tp.getEntry(pe).getInputCount() > 1)
534    {
535  0 Cache.log.warn(
536    "Ignoring additional input spec in provenance entry "
537    + tp.getEntry(pe).toString());
538    }
539    // LATER: deal sensibly with multiple inputs
540  0 Input vInput = tp.getEntry(pe).getInput(0);
541    // is this the whole alignment or a specific set of sequences ?
542  0 if (vInput.getObjRefCount() == 0)
543    {
544  0 if (tree.getV_parent() != null && tree
545    .getV_parent() instanceof uk.ac.vamsas.objects.core.Alignment)
546    {
547  0 javport = getViewport(tree.getV_parent());
548  0 jal = javport.getAlignment();
549  0 view = javport.getAlignment().getCompactAlignment();
550    }
551    }
552    else
553    {
554    // Explicit reference - to alignment, sequences or what.
555  0 if (vInput.getObjRefCount() == 1 && vInput.getObjRef(
556    0) instanceof uk.ac.vamsas.objects.core.Alignment)
557    {
558    // recover an AlignmentView for the input data
559  0 javport = getViewport((Vobject) vInput.getObjRef(0));
560  0 jal = javport.getAlignment();
561  0 view = javport.getAlignment().getCompactAlignment();
562    }
563  0 else if (vInput.getObjRef(
564    0) instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
565    {
566    // recover an AlignmentView for the input data
567  0 javport = getViewport(
568    ((Vobject) vInput.getObjRef(0)).getV_parent());
569  0 jal = javport.getAlignment();
570  0 jalview.datamodel.SequenceI[] seqs = new jalview.datamodel.SequenceI[vInput
571    .getObjRefCount()];
572  0 for (int i = 0, iSize = vInput.getObjRefCount(); i < iSize; i++)
573    {
574  0 SequenceI seq = (SequenceI) getvObj2jv(
575    (Vobject) vInput.getObjRef(i));
576  0 seqs[i] = seq;
577    }
578  0 view = new jalview.datamodel.Alignment(seqs)
579    .getCompactAlignment();
580   
581    }
582    }
583  0 int from = 1, to = jal.getWidth();
584  0 int offset = 0; // deleteRange modifies its frame of reference
585  0 for (int r = 0, s = vInput.getSegCount(); r < s; r++)
586    {
587  0 Seg visSeg = vInput.getSeg(r);
588  0 int se[] = getSegRange(visSeg, true); // jalview doesn't do
589    // bidirection alignments yet.
590  0 if (to < se[1])
591    {
592  0 Cache.log.warn("Ignoring invalid segment in InputData spec.");
593    }
594    else
595    {
596  0 if (se[0] > from)
597    {
598  0 view.deleteRange(offset + from - 1, offset + se[0] - 2);
599  0 offset -= se[0] - from;
600    }
601  0 from = se[1] + 1;
602    }
603    }
604  0 if (from < to)
605    {
606  0 view.deleteRange(offset + from - 1, offset + to - 1); // final
607    // deletion -
608    // TODO: check
609    // off by
610    // one for to
611    }
612  0 return new Object[] { new AlignmentView(view), jal };
613    }
614    }
615  0 Cache.log.debug(
616    "Returning null for input data recovery from provenance.");
617  0 return null;
618    }
619   
 
620  0 toggle private AlignmentViewport getViewport(Vobject v_parent)
621    {
622  0 if (v_parent instanceof uk.ac.vamsas.objects.core.Alignment)
623    {
624  0 return datastore
625    .findViewport((uk.ac.vamsas.objects.core.Alignment) v_parent);
626    }
627  0 return null;
628    }
629   
 
630  0 toggle public NewickFile getNewickTree()
631    {
632  0 return ntree;
633    }
634   
 
635  0 toggle public String getTitle()
636    {
637  0 return title;
638    }
639   
 
640  0 toggle public AlignmentView getInputData()
641    {
642  0 return inputData;
643    }
644   
 
645  0 toggle public boolean isValidTree()
646    {
647  0 try
648    {
649  0 if (ntree == null)
650    {
651  0 return false;
652    }
653  0 ntree.parse();
654  0 if (ntree.getTree() != null)
655    {
656  0 ntree = getNtree();
657    }
658  0 return true;
659    } catch (Exception e)
660    {
661  0 Cache.log.debug("Failed to parse newick tree string", e);
662    }
663  0 return false;
664    }
665    }