1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.io.vamsas

File Tree.java

 

Coverage histogram

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

Code metrics

86
217
21
1
663
484
78
0.36
10.33
21
3.71

Classes

Class
Line #
Actions
Tree 55 217 78
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.Console;
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 Console.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 Console.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.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 Console.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 Console.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 Console.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 Console.warn("Not updating SequenceTreeMap for " + tree.getVorbaId());
323  0 return;
324    }
325  0 Vector<BinaryNode> leaves = tp.getTree()
326    .findLeaves(tp.getTree().getTopNode());
327  0 Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
328    // particular tree
329  0 int sz = tn.length;
330  0 int i = 0;
331   
332  0 while (i < sz)
333    {
334  0 Treenode node = tn[i++];
335  0 BinaryNode mappednode = findNodeSpec(node.getNodespec(), leaves);
336  0 if (mappednode != null && mappednode instanceof SequenceNode)
337    {
338  0 SequenceNode leaf = (SequenceNode) mappednode;
339    // check if we can make the specified association
340  0 Object jvseq = null;
341  0 int vrf = 0, refv = 0;
342  0 while (jvseq == null && vrf < node.getVrefCount())
343    {
344  0 if (refv < node.getVref(vrf).getRefsCount())
345    {
346  0 Object noderef = node.getVref(vrf).getRefs(refv++);
347  0 if (noderef instanceof AlignmentSequence)
348    {
349    // we only make these kind of associations
350  0 jvseq = getvObj2jv((Vobject) noderef);
351    }
352    }
353    else
354    {
355  0 refv = 0;
356  0 vrf++;
357    }
358    }
359  0 if (jvseq instanceof SequenceI)
360    {
361  0 leaf.setElement((SequenceI) jvseq);
362  0 leaf.setPlaceholder(false);
363    }
364    else
365    {
366  0 leaf.setPlaceholder(true);
367  0 leaf.setElement(
368    new Sequence(leaf.getName(), "THISISAPLACEHLDER"));
369    }
370    }
371    }
372    }
373   
374    // / TODO: refactor to vamsas :start
375    /**
376    * construct treenode mappings for mapped sequences
377    *
378    * @param treeModel
379    * @param newick
380    * @return
381    */
 
382  0 toggle public Treenode[] makeTreeNodes(TreeModel treeModel, Newick newick)
383    {
384  0 Vector<BinaryNode> leaves = treeModel
385    .findLeaves(treeModel.getTopNode());
386  0 Vector tnv = new Vector();
387  0 Enumeration l = leaves.elements();
388  0 Hashtable nodespecs = new Hashtable();
389  0 while (l.hasMoreElements())
390    {
391  0 jalview.datamodel.BinaryNode tnode = (jalview.datamodel.BinaryNode) l
392    .nextElement();
393  0 if (tnode instanceof jalview.datamodel.SequenceNode)
394    {
395  0 if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
396    {
397  0 Object assocseq = ((BinaryNode) tnode).element();
398  0 if (assocseq instanceof SequenceI)
399    {
400  0 Vobject vobj = this.getjv2vObj(assocseq);
401  0 if (vobj != null)
402    {
403  0 Treenode node = new Treenode();
404  0 if (newick.isRegisterable())
405    {
406  0 this.cdoc.registerObject(newick);
407  0 node.addTreeId(newick);
408    }
409  0 node.setNodespec(makeNodeSpec(nodespecs, tnode));
410  0 node.setName(tnode.getName());
411  0 Vref vr = new Vref();
412  0 vr.addRefs(vobj);
413  0 node.addVref(vr);
414  0 tnv.addElement(node);
415    }
416    else
417    {
418  0 jalview.bin.Console
419    .errPrintln("WARNING: Unassociated treeNode "
420    + tnode.element().toString() + " "
421  0 + ((tnode.getName() != null)
422    ? " label " + tnode.getName()
423    : ""));
424    }
425    }
426    }
427    }
428    }
429  0 if (tnv.size() > 0)
430    {
431  0 Treenode[] tn = new Treenode[tnv.size()];
432  0 tnv.copyInto(tn);
433  0 return tn;
434    }
435  0 return new Treenode[] {};
436    }
437   
 
438  0 toggle private String makeNodeSpec(Hashtable nodespecs,
439    jalview.datamodel.BinaryNode tnode)
440    {
441  0 String nname = new String(tnode.getName());
442  0 Integer nindx = (Integer) nodespecs.get(nname);
443  0 if (nindx == null)
444    {
445  0 nindx = Integer.valueOf(1);
446    }
447  0 nname = nindx.toString() + " " + nname;
448  0 return nname;
449    }
450   
451    /**
452    * call to match up Treenode specs to NJTree parsed from document object.
453    *
454    * @param nodespec
455    * @param leaves
456    * as returned from NJTree.findLeaves( .., ..) ..
457    * @return
458    */
 
459  0 toggle private jalview.datamodel.BinaryNode findNodeSpec(String nodespec,
460    Vector leaves)
461    {
462  0 int occurence = -1;
463  0 String nspec = nodespec.substring(nodespec.indexOf(' ') + 1);
464  0 String oval = nodespec.substring(0, nodespec.indexOf(' '));
465  0 try
466    {
467  0 occurence = Integer.valueOf(oval).intValue();
468    } catch (Exception e)
469    {
470  0 jalview.bin.Console.errPrintln("Invalid nodespec '" + nodespec + "'");
471  0 return null;
472    }
473  0 jalview.datamodel.BinaryNode bn = null;
474   
475  0 int nocc = 0;
476  0 Enumeration en = leaves.elements();
477  0 while (en.hasMoreElements() && nocc < occurence)
478    {
479  0 bn = (jalview.datamodel.BinaryNode) en.nextElement();
480  0 if (bn instanceof jalview.datamodel.SequenceNode
481    && bn.getName().equals(nspec))
482    {
483  0 --occurence;
484    }
485    else
486    {
487  0 bn = null;
488    }
489    }
490  0 return bn;
491    }
492   
493    // todo: end refactor to vamsas library
494    /**
495    * add jalview object to vamsas document
496    *
497    */
 
498  0 toggle @Override
499    public void addToDocument()
500    {
501  0 tree = new uk.ac.vamsas.objects.core.Tree();
502  0 bindjvvobj(tp, tree);
503  0 tree.setTitle(tp.getTitle());
504  0 Newick newick = new Newick();
505  0 newick.setContent(tp.getTree().print());
506  0 newick.setTitle(tp.getTitle());
507  0 tree.addNewick(newick);
508  0 tree.setProvenance(makeTreeProvenance(jal, tp));
509  0 tree.setTreenode(makeTreeNodes(tp.getTree(), newick));
510   
511  0 alignment.addTree(tree);
512    }
513   
514    /**
515    * note: this function assumes that all sequence and alignment objects
516    * referenced in input data has already been associated with jalview objects.
517    *
518    * @param tp
519    * @param alignFrame
520    * @return Object[] { AlignmentView, AlignmentI - reference alignment for
521    * input }
522    */
 
523  0 toggle public Object[] recoverInputData(Provenance tp)
524    {
525  0 AlignmentViewport javport = null;
526  0 jalview.datamodel.AlignmentI jal = null;
527  0 jalview.datamodel.CigarArray view = null;
528  0 for (int pe = 0; pe < tp.getEntryCount(); pe++)
529    {
530  0 if (tp.getEntry(pe).getInputCount() > 0)
531    {
532  0 if (tp.getEntry(pe).getInputCount() > 1)
533    {
534  0 Console.warn("Ignoring additional input spec in provenance entry "
535    + tp.getEntry(pe).toString());
536    }
537    // LATER: deal sensibly with multiple inputs
538  0 Input vInput = tp.getEntry(pe).getInput(0);
539    // is this the whole alignment or a specific set of sequences ?
540  0 if (vInput.getObjRefCount() == 0)
541    {
542  0 if (tree.getV_parent() != null && tree
543    .getV_parent() instanceof uk.ac.vamsas.objects.core.Alignment)
544    {
545  0 javport = getViewport(tree.getV_parent());
546  0 jal = javport.getAlignment();
547  0 view = javport.getAlignment().getCompactAlignment();
548    }
549    }
550    else
551    {
552    // Explicit reference - to alignment, sequences or what.
553  0 if (vInput.getObjRefCount() == 1 && vInput.getObjRef(
554    0) instanceof uk.ac.vamsas.objects.core.Alignment)
555    {
556    // recover an AlignmentView for the input data
557  0 javport = getViewport((Vobject) vInput.getObjRef(0));
558  0 jal = javport.getAlignment();
559  0 view = javport.getAlignment().getCompactAlignment();
560    }
561  0 else if (vInput.getObjRef(
562    0) instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
563    {
564    // recover an AlignmentView for the input data
565  0 javport = getViewport(
566    ((Vobject) vInput.getObjRef(0)).getV_parent());
567  0 jal = javport.getAlignment();
568  0 jalview.datamodel.SequenceI[] seqs = new jalview.datamodel.SequenceI[vInput
569    .getObjRefCount()];
570  0 for (int i = 0, iSize = vInput.getObjRefCount(); i < iSize; i++)
571    {
572  0 SequenceI seq = (SequenceI) getvObj2jv(
573    (Vobject) vInput.getObjRef(i));
574  0 seqs[i] = seq;
575    }
576  0 view = new jalview.datamodel.Alignment(seqs)
577    .getCompactAlignment();
578   
579    }
580    }
581  0 int from = 1, to = jal.getWidth();
582  0 int offset = 0; // deleteRange modifies its frame of reference
583  0 for (int r = 0, s = vInput.getSegCount(); r < s; r++)
584    {
585  0 Seg visSeg = vInput.getSeg(r);
586  0 int se[] = getSegRange(visSeg, true); // jalview doesn't do
587    // bidirection alignments yet.
588  0 if (to < se[1])
589    {
590  0 Console.warn("Ignoring invalid segment in InputData spec.");
591    }
592    else
593    {
594  0 if (se[0] > from)
595    {
596  0 view.deleteRange(offset + from - 1, offset + se[0] - 2);
597  0 offset -= se[0] - from;
598    }
599  0 from = se[1] + 1;
600    }
601    }
602  0 if (from < to)
603    {
604  0 view.deleteRange(offset + from - 1, offset + to - 1); // final
605    // deletion -
606    // TODO: check
607    // off by
608    // one for to
609    }
610  0 return new Object[] { new AlignmentView(view), jal };
611    }
612    }
613  0 Console.debug(
614    "Returning null for input data recovery from provenance.");
615  0 return null;
616    }
617   
 
618  0 toggle private AlignmentViewport getViewport(Vobject v_parent)
619    {
620  0 if (v_parent instanceof uk.ac.vamsas.objects.core.Alignment)
621    {
622  0 return datastore
623    .findViewport((uk.ac.vamsas.objects.core.Alignment) v_parent);
624    }
625  0 return null;
626    }
627   
 
628  0 toggle public NewickFile getNewickTree()
629    {
630  0 return ntree;
631    }
632   
 
633  0 toggle public String getTitle()
634    {
635  0 return title;
636    }
637   
 
638  0 toggle public AlignmentView getInputData()
639    {
640  0 return inputData;
641    }
642   
 
643  0 toggle public boolean isValidTree()
644    {
645  0 try
646    {
647  0 if (ntree == null)
648    {
649  0 return false;
650    }
651  0 ntree.parse();
652  0 if (ntree.getTree() != null)
653    {
654  0 ntree = getNtree();
655    }
656  0 return true;
657    } catch (Exception e)
658    {
659  0 Console.debug("Failed to parse newick tree string", e);
660    }
661  0 return false;
662    }
663    }