Clover icon

jalviewX

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

File AlignmentView.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
45% of files have more coverage

Code metrics

240
424
29
2
1,241
936
178
0.42
14.62
14.5
6.14

Classes

Class Line # Actions
AlignmentView 35 413 172 442
0.3442136634.4%
AlignmentView.ScGroup 69 11 6 11
0.4210526342.1%
 

Contributing tests

This file is covered by 12 tests. .

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.datamodel;
22   
23    import jalview.util.MessageManager;
24    import jalview.util.ShiftList;
25   
26    import java.io.PrintStream;
27    import java.util.ArrayList;
28    import java.util.List;
29   
30    /**
31    * Transient object compactly representing a 'view' of an alignment - with
32    * discontinuities marked. Extended in Jalview 2.7 to optionally record sequence
33    * groups and specific selected regions on the alignment.
34    */
 
35    public class AlignmentView
36    {
37    private SeqCigar[] sequences = null;
38   
39    private int[] contigs = null;
40   
41    private int width = 0;
42   
43    private int firstCol = 0;
44   
45    /**
46    * one or more ScGroup objects, which are referenced by each seqCigar's group
47    * membership
48    */
49    private List<ScGroup> scGroups = null;
50   
51    private boolean isNa = false;
52   
53    /**
54    * false if the view concerns peptides
55    *
56    * @return
57    */
 
58  0 toggle public boolean isNa()
59    {
60  0 return isNa;
61    }
62   
63    /**
64    * Group defined over SeqCigars. Unlike AlignmentI associated groups, each
65    * SequenceGroup hold just the essential properties for the group, but no
66    * references to the sequences involved. SeqCigars hold references to the
67    * seuqenceGroup entities themselves.
68    */
 
69    private class ScGroup
70    {
71    public List<SeqCigar> seqs;
72   
73    public SequenceGroup sg;
74   
 
75  11 toggle ScGroup()
76    {
77  11 seqs = new ArrayList<SeqCigar>();
78    }
79   
80    /**
81    * @param seq
82    * @return true if seq was not a member before and was added to group
83    */
 
84  33 toggle public boolean add(SeqCigar seq)
85    {
86  33 if (!seq.isMemberOf(this))
87    {
88  33 seqs.add(seq);
89  33 seq.setGroupMembership(this);
90  33 return true;
91    }
92    else
93    {
94  0 return false;
95    }
96    }
97   
98    /**
99    *
100    * @param seq
101    * @return true if seq was a member and was removed from group
102    */
 
103  0 toggle public boolean remove(SeqCigar seq)
104    {
105  0 if (seq.removeGroupMembership(this))
106    {
107  0 seqs.remove(seq);
108  0 return true;
109    }
110  0 return false;
111    }
112   
 
113  0 toggle public int size()
114    {
115  0 return seqs.size();
116    }
117    }
118   
119    /**
120    * vector of selected seqCigars. This vector is also referenced by each
121    * seqCigar contained in it.
122    */
123    private ScGroup selected;
124   
125    /**
126    * Construct an alignmentView from a live jalview alignment view. Note -
127    * hidden rows will be excluded from alignmentView Note: JAL-1179
128    *
129    * @param alignment
130    * - alignment as referenced by an AlignViewport
131    * @param columnSelection
132    * -
133    * @param selection
134    * @param hasHiddenColumns
135    * - mark the hidden columns in columnSelection as hidden in the view
136    * @param selectedRegionOnly
137    * - when set, only include the selected region in the view,
138    * otherwise just mark the selected region on the constructed view.
139    * @param recordGroups
140    * - when set, any groups on the given alignment will be marked on
141    * the view
142    */
 
143  19 toggle public AlignmentView(AlignmentI alignment, HiddenColumns hidden,
144    SequenceGroup selection, boolean hasHiddenColumns,
145    boolean selectedRegionOnly, boolean recordGroups)
146    {
147    // refactored from AlignViewport.getAlignmentView(selectedOnly);
148  19 this(new jalview.datamodel.CigarArray(alignment,
149  19 (hasHiddenColumns ? hidden : null),
150  19 (selectedRegionOnly ? selection : null)),
151  19 (selectedRegionOnly && selection != null)
152    ? selection.getStartRes()
153    : 0);
154  19 isNa = alignment.isNucleotide();
155    // walk down SeqCigar array and Alignment Array - optionally restricted by
156    // selected region.
157    // test group membership for each sequence in each group, store membership
158    // and record non-empty groups in group list.
159    // record / sub-select selected region on the alignment view
160  19 SequenceI[] selseqs;
161  19 if (selection != null && selection.getSize() > 0)
162    {
163  6 List<SequenceI> sel = selection.getSequences(null);
164  6 this.selected = new ScGroup();
165  6 selseqs = selection.getSequencesInOrder(alignment,
166    selectedRegionOnly);
167    }
168    else
169    {
170  13 selseqs = alignment.getSequencesArray();
171    }
172   
173  19 List<List<SequenceI>> seqsets = new ArrayList<List<SequenceI>>();
174    // get the alignment's group list and make a copy
175  19 List<SequenceGroup> grps = new ArrayList<SequenceGroup>();
176  19 List<SequenceGroup> gg = alignment.getGroups();
177  19 grps.addAll(gg);
178  19 ScGroup[] sgrps = null;
179  19 boolean addedgps[] = null;
180  19 if (grps != null)
181    {
182  19 if (selection != null && selectedRegionOnly)
183    {
184    // trim annotation to the region being stored.
185    // strip out any groups that do not actually intersect with the
186    // visible and selected region
187  6 int ssel = selection.getStartRes(), esel = selection.getEndRes();
188  6 List<SequenceGroup> isg = new ArrayList<SequenceGroup>();
189  6 for (SequenceGroup sg : grps)
190    {
191  0 if (!(sg.getStartRes() > esel || sg.getEndRes() < ssel))
192    {
193    // adjust bounds of new group, if necessary.
194  0 if (sg.getStartRes() < ssel)
195    {
196  0 sg.setStartRes(ssel);
197    }
198  0 if (sg.getEndRes() > esel)
199    {
200  0 sg.setEndRes(esel);
201    }
202  0 sg.setStartRes(sg.getStartRes() - ssel + 1);
203  0 sg.setEndRes(sg.getEndRes() - ssel + 1);
204   
205  0 isg.add(sg);
206    }
207    }
208  6 grps = isg;
209    }
210   
211  19 sgrps = new ScGroup[grps.size()];
212  19 addedgps = new boolean[grps.size()];
213  24 for (int g = 0; g < sgrps.length; g++)
214    {
215  5 SequenceGroup sg = grps.get(g);
216  5 sgrps[g] = new ScGroup();
217  5 sgrps[g].sg = new SequenceGroup(sg);
218  5 addedgps[g] = false;
219    // can't set entry 0 in an empty list
220    // seqsets.set(g, sg.getSequences(null));
221  5 seqsets.add(sg.getSequences());
222    }
223    // seqsets now contains vectors (should be sets) for each group, so we can
224    // track when we've done with the group
225    }
226  19 int csi = 0;
227  84 for (int i = 0; i < selseqs.length; i++)
228    {
229  65 if (selseqs[i] != null)
230    {
231  65 if (selection != null && selection.getSize() > 0
232    && !selectedRegionOnly)
233    {
234  0 selected.add(sequences[csi]);
235    }
236  65 if (seqsets != null)
237    {
238  230 for (int sg = 0; sg < sgrps.length; sg++)
239    {
240  165 if ((seqsets.get(sg)).contains(selseqs[i]))
241    {
242  33 sgrps[sg].sg.deleteSequence(selseqs[i], false);
243  33 sgrps[sg].add(sequences[csi]);
244  33 if (!addedgps[sg])
245    {
246  5 if (scGroups == null)
247    {
248  1 scGroups = new ArrayList<ScGroup>();
249    }
250  5 addedgps[sg] = true;
251  5 scGroups.add(sgrps[sg]);
252    }
253    }
254    }
255    }
256  65 csi++;
257    }
258    }
259    // finally, delete the remaining sequences (if any) not selected
260  24 for (int sg = 0; sg < sgrps.length; sg++)
261    {
262  5 SequenceI[] sqs = sgrps[sg].sg.getSequencesAsArray(null);
263  5 for (int si = 0; si < sqs.length; si++)
264    {
265  0 sgrps[sg].sg.deleteSequence(sqs[si], false);
266    }
267  5 sgrps[sg] = null;
268    }
269    }
270   
271    /**
272    * construct an alignmentView from a SeqCigarArray. Errors are thrown if the
273    * seqcigararray.isSeqCigarArray() flag is not set.
274    */
 
275  20 toggle public AlignmentView(CigarArray seqcigararray)
276    {
277  20 if (!seqcigararray.isSeqCigarArray())
278    {
279  0 throw new Error(
280    "Implementation Error - can only make an alignment view from a CigarArray of sequences.");
281    }
282    // contigs = seqcigararray.applyDeletions();
283  20 contigs = seqcigararray.getDeletedRegions();
284  20 sequences = seqcigararray.getSeqCigarArray();
285  20 width = seqcigararray.getWidth(); // visible width
286    }
287   
288    /**
289    * Create an alignmentView where the first column corresponds with the
290    * 'firstcol' column of some reference alignment
291    *
292    * @param sdata
293    * @param firstcol
294    */
 
295  19 toggle public AlignmentView(CigarArray sdata, int firstcol)
296    {
297  19 this(sdata);
298  19 firstCol = firstcol;
299    }
300   
 
301  0 toggle public void setSequences(SeqCigar[] sequences)
302    {
303  0 this.sequences = sequences;
304    }
305   
 
306  0 toggle public void setContigs(int[] contigs)
307    {
308  0 this.contigs = contigs;
309    }
310   
 
311  6 toggle public SeqCigar[] getSequences()
312    {
313  6 return sequences;
314    }
315   
316    /**
317    * @see CigarArray.getDeletedRegions
318    * @return int[] { vis_start, sym_start, length }
319    */
 
320  0 toggle public int[] getContigs()
321    {
322  0 return contigs;
323    }
324   
325    /**
326    * get the full alignment and a columnselection object marking the hidden
327    * regions
328    *
329    * @param gapCharacter
330    * char
331    * @return Object[] { SequenceI[], ColumnSelection}
332    */
 
333  3 toggle public Object[] getAlignmentAndHiddenColumns(char gapCharacter)
334    {
335  3 HiddenColumns hidden = new HiddenColumns();
336   
337  3 return new Object[] { SeqCigar.createAlignmentSequences(sequences,
338    gapCharacter, hidden, contigs),
339    hidden };
340    }
341   
342    /**
343    * return the visible alignment corresponding to this view. Sequences in this
344    * alignment are edited versions of the parent sequences - where hidden
345    * regions have been removed. NOTE: the sequence data in this alignment is not
346    * complete!
347    *
348    * @param c
349    * @return
350    */
 
351  2 toggle public AlignmentI getVisibleAlignment(char c)
352    {
353  2 SequenceI[] aln = getVisibleSeqs(c);
354   
355  2 AlignmentI vcal = new Alignment(aln);
356  2 addPrunedGroupsInOrder(vcal, -1, -1, true);
357  2 return vcal;
358    }
359   
360    /**
361    * add groups from view to the given alignment
362    *
363    * @param vcal
364    * @param gstart
365    * -1 or 0 to width-1
366    * @param gend
367    * -1 or gstart to width-1
368    * @param viscontigs
369    * - true if vcal is alignment of the visible regions of the view
370    * (e.g. as returned from getVisibleAlignment)
371    */
 
372  4 toggle private void addPrunedGroupsInOrder(AlignmentI vcal, int gstart, int gend,
373    boolean viscontigs)
374    {
375  4 boolean r = false;
376  4 if (gstart > -1 && gstart <= gend)
377    {
378  2 r = true;
379    }
380   
381  4 SequenceI[] aln = vcal.getSequencesArray();
382    {
383    /**
384    * prune any groups to the visible coordinates of the alignment.
385    */
386    {
387  4 int nvg = (scGroups != null) ? scGroups.size() : 0;
388  4 if (nvg > 0)
389    {
390  2 SequenceGroup[] nsg = new SequenceGroup[nvg];
391  12 for (int g = 0; g < nvg; g++)
392    {
393  10 SequenceGroup sg = scGroups.get(g).sg;
394  10 if (r)
395    {
396  10 if (sg.getStartRes() > gend || sg.getEndRes() < gstart)
397    {
398    // Skip this group
399  0 nsg[g] = null;
400  0 continue;
401    }
402    }
403   
404    // clone group properties
405  10 nsg[g] = new SequenceGroup(sg);
406   
407    // may need to shift/trim start and end ?
408  10 if (r && !viscontigs)
409    {
410    // Not fully tested code - routine not yet called with
411    // viscontigs==false
412  0 if (nsg[g].getStartRes() < gstart)
413    {
414  0 nsg[g].setStartRes(0);
415    }
416    else
417    {
418  0 nsg[g].setStartRes(nsg[g].getStartRes() - gstart);
419  0 nsg[g].setEndRes(nsg[g].getEndRes() - gstart);
420    }
421  0 if (nsg[g].getEndRes() > (gend - gstart))
422    {
423  0 nsg[g].setEndRes(gend - gstart);
424    }
425    }
426    }
427  2 if (viscontigs)
428    {
429    // prune groups to cover just the visible positions between
430    // gstart/gend.
431  2 if (contigs != null)
432    {
433  0 int p = 0;
434  0 ShiftList prune = new ShiftList();
435  0 if (r)
436    {
437    // adjust for start of alignment within visible window.
438  0 prune.addShift(gstart, -gstart); //
439    }
440  0 for (int h = 0; h < contigs.length; h += 3)
441    {
442    {
443  0 prune.addShift(p + contigs[h + 1],
444    contigs[h + 2] - contigs[h + 1]);
445    }
446  0 p = contigs[h + 1] + contigs[h + 2];
447    }
448  0 for (int g = 0; g < nsg.length; g++)
449    {
450  0 if (nsg[g] != null)
451    {
452  0 int s = nsg[g].getStartRes(), t = nsg[g].getEndRes();
453  0 int w = 1 + t - s;
454  0 if (r)
455    {
456  0 if (s < gstart)
457    {
458  0 s = gstart;
459    }
460  0 if (t > gend)
461    {
462  0 t = gend;
463    }
464    }
465  0 s = prune.shift(s);
466  0 t = prune.shift(t);
467  0 nsg[g].setStartRes(s);
468  0 nsg[g].setEndRes(t);
469    }
470    }
471    }
472    }
473   
474  68 for (int nsq = 0; nsq < aln.length; nsq++)
475    {
476  396 for (int g = 0; g < nvg; g++)
477    {
478  330 if (nsg[g] != null
479    && sequences[nsq].isMemberOf(scGroups.get(g)))
480    {
481  66 nsg[g].addSequence(aln[nsq], false);
482    }
483    }
484    }
485  12 for (int g = 0; g < nvg; g++)
486    {
487  10 if (nsg[g] != null && nsg[g].getSize() > 0)
488    {
489  10 vcal.addGroup(nsg[g]);
490    }
491  10 nsg[g] = null;
492    }
493    }
494    }
495    }
496    }
497   
498    /**
499    * generate sequence array corresponding to the visible parts of the
500    * alignment.
501    *
502    * @param c
503    * gap character to use to recreate the alignment
504    * @return
505    */
 
506  2 toggle private SequenceI[] getVisibleSeqs(char c)
507    {
508  2 SequenceI[] aln = new SequenceI[sequences.length];
509  5 for (int i = 0, j = sequences.length; i < j; i++)
510    {
511  3 aln[i] = sequences[i].getSeq(c);
512    // Remove hidden regions from sequence
513  3 aln[i].setSequence(getASequenceString(c, i));
514    }
515  2 return aln;
516    }
517   
518    /**
519    * creates new alignment objects for all contiguous visible segments
520    *
521    * @param c
522    * @param start
523    * @param end
524    * @param regionOfInterest
525    * specify which sequences to include (or null to include all
526    * sequences)
527    * @return AlignmentI[] - all alignments where each sequence is a subsequence
528    * constructed from visible contig regions of view
529    */
 
530  2 toggle public AlignmentI[] getVisibleContigAlignments(char c)
531    {
532  2 int nvc = 0;
533  2 int[] vcontigs = getVisibleContigs();
534  2 SequenceI[][] contigviews = getVisibleContigs(c);
535  2 AlignmentI[] vcals = new AlignmentI[contigviews.length];
536  4 for (nvc = 0; nvc < contigviews.length; nvc++)
537    {
538  2 vcals[nvc] = new Alignment(contigviews[nvc]);
539  2 if (scGroups != null && scGroups.size() > 0)
540    {
541  2 addPrunedGroupsInOrder(vcals[nvc], vcontigs[nvc * 2],
542    vcontigs[nvc * 2 + 1], true);
543    }
544    }
545  2 return vcals;
546    }
547   
548    /**
549    * build a string excluding hidden regions from a particular sequence in the
550    * view
551    *
552    * @param c
553    * @param n
554    * @return
555    */
 
556  9 toggle private String getASequenceString(char c, int n)
557    {
558  9 String sqn;
559  9 String fullseq = sequences[n].getSequenceString(c);
560  9 if (contigs != null)
561    {
562  0 sqn = "";
563  0 int p = 0;
564  0 for (int h = 0; h < contigs.length; h += 3)
565    {
566  0 sqn += fullseq.substring(p, contigs[h + 1]);
567  0 p = contigs[h + 1] + contigs[h + 2];
568    }
569  0 sqn += fullseq.substring(p);
570    }
571    else
572    {
573  9 sqn = fullseq;
574    }
575  9 return sqn;
576    }
577   
578    /**
579    * get an array of visible sequence strings for a view on an alignment using
580    * the given gap character uses getASequenceString
581    *
582    * @param c
583    * char
584    * @return String[]
585    */
 
586  4 toggle public String[] getSequenceStrings(char c)
587    {
588  4 String[] seqs = new String[sequences.length];
589  10 for (int n = 0; n < sequences.length; n++)
590    {
591  6 seqs[n] = getASequenceString(c, n);
592    }
593  4 return seqs;
594    }
595   
596    /**
597    *
598    * @return visible number of columns in alignment view
599    */
 
600  0 toggle public int getWidth()
601    {
602  0 return width;
603    }
604   
 
605  0 toggle protected void setWidth(int width)
606    {
607  0 this.width = width;
608    }
609   
610    /**
611    * get the contiguous subalignments in an alignment view.
612    *
613    * @param gapCharacter
614    * char
615    * @return SequenceI[][]
616    */
 
617  2 toggle public SequenceI[][] getVisibleContigs(char gapCharacter)
618    {
619  2 SequenceI[][] smsa;
620  2 int njobs = 1;
621  2 if (sequences == null || width <= 0)
622    {
623  0 return null;
624    }
625  2 if (contigs != null && contigs.length > 0)
626    {
627  0 int start = 0;
628  0 njobs = 0;
629  0 int fwidth = width;
630  0 for (int contig = 0; contig < contigs.length; contig += 3)
631    {
632  0 if ((contigs[contig + 1] - start) > 0)
633    {
634  0 njobs++;
635    }
636  0 fwidth += contigs[contig + 2]; // end up with full region width
637    // (including hidden regions)
638  0 start = contigs[contig + 1] + contigs[contig + 2];
639    }
640  0 if (start < fwidth)
641    {
642  0 njobs++;
643    }
644  0 smsa = new SequenceI[njobs][];
645  0 start = 0;
646  0 int j = 0;
647  0 for (int contig = 0; contig < contigs.length; contig += 3)
648    {
649  0 if (contigs[contig + 1] - start > 0)
650    {
651  0 SequenceI mseq[] = new SequenceI[sequences.length];
652  0 for (int s = 0; s < mseq.length; s++)
653    {
654  0 mseq[s] = sequences[s].getSeq(gapCharacter)
655    .getSubSequence(start, contigs[contig + 1]);
656    }
657  0 smsa[j] = mseq;
658  0 j++;
659    }
660  0 start = contigs[contig + 1] + contigs[contig + 2];
661    }
662  0 if (start < fwidth)
663    {
664  0 SequenceI mseq[] = new SequenceI[sequences.length];
665  0 for (int s = 0; s < mseq.length; s++)
666    {
667  0 mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,
668    fwidth + 1);
669    }
670  0 smsa[j] = mseq;
671  0 j++;
672    }
673    }
674    else
675    {
676  2 smsa = new SequenceI[1][];
677  2 smsa[0] = new SequenceI[sequences.length];
678  68 for (int s = 0; s < sequences.length; s++)
679    {
680  66 smsa[0][s] = sequences[s].getSeq(gapCharacter);
681    }
682    }
683  2 return smsa;
684    }
685   
686    /**
687    * return full msa and hidden regions with visible blocks replaced with new
688    * sub alignments
689    *
690    * @param nvismsa
691    * SequenceI[][]
692    * @param orders
693    * AlignmentOrder[] corresponding to each SequenceI[] block.
694    * @return Object[]
695    */
 
696  0 toggle public Object[] getUpdatedView(SequenceI[][] nvismsa,
697    AlignmentOrder[] orders, char gapCharacter)
698    {
699  0 if (sequences == null || width <= 0)
700    {
701  0 throw new Error(MessageManager
702    .getString("error.empty_view_cannot_be_updated"));
703    }
704  0 if (nvismsa == null)
705    {
706  0 throw new Error(
707    "nvismsa==null. use getAlignmentAndColumnSelection() instead.");
708    }
709  0 if (contigs != null && contigs.length > 0)
710    {
711  0 SequenceI[] alignment = new SequenceI[sequences.length];
712    // ColumnSelection columnselection = new ColumnSelection();
713  0 HiddenColumns hidden = new HiddenColumns();
714  0 if (contigs != null && contigs.length > 0)
715    {
716  0 int start = 0;
717  0 int nwidth = 0;
718  0 int owidth = width;
719  0 int j = 0;
720  0 for (int contig = 0; contig < contigs.length; contig += 3)
721    {
722  0 owidth += contigs[contig + 2]; // recover final column width
723  0 if (contigs[contig + 1] - start > 0)
724    {
725  0 int swidth = 0; // subalignment width
726  0 if (nvismsa[j] != null)
727    {
728  0 SequenceI mseq[] = nvismsa[j];
729  0 AlignmentOrder order = (orders == null) ? null : orders[j];
730  0 j++;
731  0 if (mseq.length != sequences.length)
732    {
733  0 throw new Error(MessageManager.formatMessage(
734    "error.mismatch_between_number_of_sequences_in_block",
735    new String[]
736    { Integer.valueOf(j).toString(),
737    Integer.valueOf(mseq.length).toString(),
738    Integer.valueOf(sequences.length)
739    .toString() }));
740    }
741  0 swidth = mseq[0].getLength(); // JBPNote: could ensure padded
742    // here.
743  0 for (int s = 0; s < mseq.length; s++)
744    {
745  0 if (alignment[s] == null)
746    {
747  0 alignment[s] = mseq[s];
748    }
749    else
750    {
751  0 alignment[s]
752    .setSequence(alignment[s].getSequenceAsString()
753    + mseq[s].getSequenceAsString());
754  0 if (mseq[s].getStart() <= mseq[s].getEnd())
755    {
756  0 alignment[s].setEnd(mseq[s].getEnd());
757    }
758  0 if (order != null)
759    {
760  0 order.updateSequence(mseq[s], alignment[s]);
761    }
762    }
763    }
764    }
765    else
766    {
767    // recover original alignment block or place gaps
768  0 if (true)
769    {
770    // recover input data
771  0 for (int s = 0; s < sequences.length; s++)
772    {
773  0 SequenceI oseq = sequences[s].getSeq(gapCharacter)
774    .getSubSequence(start, contigs[contig + 1]);
775  0 if (swidth < oseq.getLength())
776    {
777  0 swidth = oseq.getLength();
778    }
779  0 if (alignment[s] == null)
780    {
781  0 alignment[s] = oseq;
782    }
783    else
784    {
785  0 alignment[s]
786    .setSequence(alignment[s].getSequenceAsString()
787    + oseq.getSequenceAsString());
788  0 if (oseq.getEnd() >= oseq.getStart())
789    {
790  0 alignment[s].setEnd(oseq.getEnd());
791    }
792    }
793    }
794   
795    }
796  0 j++;
797    }
798  0 nwidth += swidth;
799    }
800    // advance to begining of visible region
801  0 start = contigs[contig + 1] + contigs[contig + 2];
802    // add hidden segment to right of next region
803  0 for (int s = 0; s < sequences.length; s++)
804    {
805  0 SequenceI hseq = sequences[s].getSeq(gapCharacter)
806    .getSubSequence(contigs[contig + 1], start);
807  0 if (alignment[s] == null)
808    {
809  0 alignment[s] = hseq;
810    }
811    else
812    {
813  0 alignment[s].setSequence(alignment[s].getSequenceAsString()
814    + hseq.getSequenceAsString());
815  0 if (hseq.getEnd() >= hseq.getStart())
816    {
817  0 alignment[s].setEnd(hseq.getEnd());
818    }
819    }
820    }
821    // mark hidden segment as hidden in the new alignment
822  0 hidden.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
823  0 nwidth += contigs[contig + 2];
824    }
825    // Do final segment - if it exists
826  0 if (j < nvismsa.length)
827    {
828  0 int swidth = 0;
829  0 if (nvismsa[j] != null)
830    {
831  0 SequenceI mseq[] = nvismsa[j];
832  0 AlignmentOrder order = (orders != null) ? orders[j] : null;
833  0 swidth = mseq[0].getLength();
834  0 for (int s = 0; s < mseq.length; s++)
835    {
836  0 if (alignment[s] == null)
837    {
838  0 alignment[s] = mseq[s];
839    }
840    else
841    {
842  0 alignment[s].setSequence(alignment[s].getSequenceAsString()
843    + mseq[s].getSequenceAsString());
844  0 if (mseq[s].getEnd() >= mseq[s].getStart())
845    {
846  0 alignment[s].setEnd(mseq[s].getEnd());
847    }
848  0 if (order != null)
849    {
850  0 order.updateSequence(mseq[s], alignment[s]);
851    }
852    }
853    }
854    }
855    else
856    {
857  0 if (start < owidth)
858    {
859    // recover input data or place gaps
860  0 if (true)
861    {
862    // recover input data
863  0 for (int s = 0; s < sequences.length; s++)
864    {
865  0 SequenceI oseq = sequences[s].getSeq(gapCharacter)
866    .getSubSequence(start, owidth + 1);
867  0 if (swidth < oseq.getLength())
868    {
869  0 swidth = oseq.getLength();
870    }
871  0 if (alignment[s] == null)
872    {
873  0 alignment[s] = oseq;
874    }
875    else
876    {
877  0 alignment[s]
878    .setSequence(alignment[s].getSequenceAsString()
879    + oseq.getSequenceAsString());
880  0 if (oseq.getEnd() >= oseq.getStart())
881    {
882  0 alignment[s].setEnd(oseq.getEnd());
883    }
884    }
885    }
886  0 nwidth += swidth;
887    }
888    else
889    {
890    // place gaps.
891  0 throw new Error(MessageManager
892    .getString("error.padding_not_yet_implemented"));
893    }
894    }
895    }
896    }
897    }
898  0 return new Object[] { alignment, hidden };
899    }
900    else
901    {
902  0 if (nvismsa.length != 1)
903    {
904  0 throw new Error(MessageManager.formatMessage(
905    "error.mismatch_between_visible_blocks_to_update_and_number_of_contigs_in_view",
906    new String[]
907    { Integer.valueOf(nvismsa.length).toString() }));
908    }
909  0 if (nvismsa[0] != null)
910    {
911  0 return new Object[] { nvismsa[0], new HiddenColumns() };
912    }
913    else
914    {
915  0 return getAlignmentAndHiddenColumns(gapCharacter);
916    }
917    }
918    }
919   
920    /**
921    * returns simple array of start end positions of visible range on alignment.
922    * vis_start and vis_end are inclusive - use
923    * SequenceI.getSubSequence(vis_start, vis_end+1) to recover visible sequence
924    * from underlying alignment.
925    *
926    * @return int[] { start_i, end_i } for 1<i<n visible regions.
927    */
 
928  19 toggle public int[] getVisibleContigs()
929    {
930  19 if (contigs != null && contigs.length > 0)
931    {
932  8 int start = 0;
933  8 int nvis = 0;
934  8 int fwidth = width;
935  22 for (int contig = 0; contig < contigs.length; contig += 3)
936    {
937  14 if ((contigs[contig + 1] - start) > 0)
938    {
939  7 nvis++;
940    }
941  14 fwidth += contigs[contig + 2]; // end up with full region width
942    // (including hidden regions)
943  14 start = contigs[contig + 1] + contigs[contig + 2];
944    }
945  8 if (start < fwidth)
946    {
947  3 nvis++;
948    }
949  8 int viscontigs[] = new int[nvis * 2];
950  8 nvis = 0;
951  8 start = 0;
952  22 for (int contig = 0; contig < contigs.length; contig += 3)
953    {
954  14 if ((contigs[contig + 1] - start) > 0)
955    {
956  7 viscontigs[nvis] = start;
957  7 viscontigs[nvis + 1] = contigs[contig + 1] - 1; // end is inclusive
958  7 nvis += 2;
959    }
960  14 start = contigs[contig + 1] + contigs[contig + 2];
961    }
962  8 if (start < fwidth)
963    {
964  3 viscontigs[nvis] = start;
965  3 viscontigs[nvis + 1] = fwidth - 1; // end is inclusive
966  3 nvis += 2;
967    }
968  8 return viscontigs;
969    }
970    else
971    {
972  11 return new int[] { 0, width - 1 };
973    }
974    }
975   
976    /**
977    *
978    * @return position of first visible column of AlignmentView within its
979    * parent's alignment reference frame
980    */
 
981  0 toggle public int getAlignmentOrigin()
982    {
983  0 return firstCol;
984    }
985   
986    /**
987    * compute a deletion map for the current view according to the given
988    * gap/match map
989    *
990    * @param gapMap
991    * (as returned from SequenceI.gapMap())
992    * @return int[] {intersection of visible regions with gapMap)
993    */
 
994  0 toggle public int[] getVisibleContigMapFor(int[] gapMap)
995    {
996  0 int[] delMap = null;
997  0 int[] viscontigs = getVisibleContigs();
998  0 int spos = 0;
999  0 int i = 0;
1000  0 if (viscontigs != null)
1001    {
1002    // viscontigs maps from a subset of the gapMap to the gapMap, so it will
1003    // always be equal to or shorter than gapMap
1004  0 delMap = new int[gapMap.length];
1005  0 for (int contig = 0; contig < viscontigs.length; contig += 2)
1006    {
1007   
1008  0 while (spos < gapMap.length && gapMap[spos] < viscontigs[contig])
1009    {
1010  0 spos++;
1011    }
1012  0 while (spos < gapMap.length
1013    && gapMap[spos] <= viscontigs[contig + 1])
1014    {
1015  0 delMap[i++] = spos++;
1016    }
1017    }
1018  0 int tmap[] = new int[i];
1019  0 System.arraycopy(delMap, 0, tmap, 0, i);
1020  0 delMap = tmap;
1021    }
1022  0 return delMap;
1023    }
1024   
1025    /**
1026    * apply the getSeq(gc) method to each sequence cigar, and return the array of
1027    * edited sequences, optionally with hidden regions removed.
1028    *
1029    * @param gc
1030    * gap character to use for insertions
1031    * @param delete
1032    * remove hidden regions from sequences. Note: currently implemented
1033    * in a memory inefficient way - space needed is 2*result set for
1034    * deletion
1035    *
1036    * @return SequenceI[]
1037    */
 
1038  0 toggle public SequenceI[] getEditedSequences(char gc, boolean delete)
1039    {
1040  0 SeqCigar[] msf = getSequences();
1041  0 SequenceI[] aln = new SequenceI[msf.length];
1042  0 for (int i = 0, j = msf.length; i < j; i++)
1043    {
1044  0 aln[i] = msf[i].getSeq(gc);
1045    }
1046  0 if (delete)
1047    {
1048  0 String[] sqs = getSequenceStrings(gc);
1049  0 for (int i = 0; i < sqs.length; i++)
1050    {
1051  0 aln[i].setSequence(sqs[i]);
1052  0 sqs[i] = null;
1053    }
1054    }
1055  0 return aln;
1056    }
1057   
 
1058  0 toggle public static void summariseAlignmentView(AlignmentView view,
1059    PrintStream os)
1060    {
1061  0 os.print("View has " + view.sequences.length + " of which ");
1062  0 if (view.selected == null)
1063    {
1064  0 os.print("None");
1065    }
1066    else
1067    {
1068  0 os.print(" " + view.selected.size());
1069    }
1070  0 os.println(" are selected.");
1071  0 os.print("View is " + view.getWidth() + " columns wide");
1072  0 int viswid = 0;
1073  0 int[] contigs = view.getContigs();
1074  0 if (contigs != null)
1075    {
1076  0 viswid = view.width;
1077  0 for (int i = 0; i < contigs.length; i += 3)
1078    {
1079  0 viswid += contigs[i + 2];
1080    }
1081  0 os.println("with " + viswid + " visible columns spread over "
1082    + contigs.length / 3 + " regions.");
1083    }
1084    else
1085    {
1086  0 viswid = view.width;
1087  0 os.println(".");
1088    }
1089  0 if (view.scGroups != null)
1090    {
1091  0 os.println("There are " + view.scGroups.size()
1092    + " groups defined on the view.");
1093  0 for (int g = 0; g < view.scGroups.size(); g++)
1094    {
1095  0 ScGroup sgr = view.scGroups.get(g);
1096  0 os.println("Group " + g + ": Name = " + sgr.sg.getName()
1097    + " Contains " + sgr.seqs.size() + " Seqs.");
1098  0 os.println("This group runs from " + sgr.sg.getStartRes() + " to "
1099    + sgr.sg.getEndRes());
1100  0 for (int s = 0; s < sgr.seqs.size(); s++)
1101    {
1102    // JBPnote this should be a unit test for ScGroup
1103  0 if (!sgr.seqs.get(s).isMemberOf(sgr))
1104    {
1105  0 os.println("** WARNING: sequence " + sgr.seqs.get(s).toString()
1106    + " is not marked as member of group.");
1107    }
1108    }
1109    }
1110  0 AlignmentI visal = view.getVisibleAlignment('-');
1111  0 if (visal != null)
1112    {
1113  0 os.println("Vis. alignment is " + visal.getWidth()
1114    + " wide and has " + visal.getHeight() + " seqs.");
1115  0 if (visal.getGroups() != null && visal.getGroups().size() > 0)
1116    {
1117   
1118  0 int i = 1;
1119  0 for (SequenceGroup sg : visal.getGroups())
1120    {
1121  0 os.println("Group " + (i++) + " begins at column "
1122    + sg.getStartRes() + " and ends at " + sg.getEndRes());
1123    }
1124    }
1125    }
1126    }
1127    }
1128   
 
1129  0 toggle public static void testSelectionViews(AlignmentI alignment,
1130    HiddenColumns hidden, SequenceGroup selection)
1131    {
1132  0 System.out.println("Testing standard view creation:\n");
1133  0 AlignmentView view = null;
1134  0 try
1135    {
1136  0 System.out.println(
1137    "View with no hidden columns, no limit to selection, no groups to be collected:");
1138  0 view = new AlignmentView(alignment, hidden, selection, false, false,
1139    false);
1140  0 summariseAlignmentView(view, System.out);
1141   
1142    } catch (Exception e)
1143    {
1144  0 e.printStackTrace();
1145  0 System.err.println(
1146    "Failed to generate alignment with selection but no groups marked.");
1147    }
1148  0 try
1149    {
1150  0 System.out.println(
1151    "View with no hidden columns, no limit to selection, and all groups to be collected:");
1152  0 view = new AlignmentView(alignment, hidden, selection, false, false,
1153    true);
1154  0 summariseAlignmentView(view, System.out);
1155    } catch (Exception e)
1156    {
1157  0 e.printStackTrace();
1158  0 System.err.println(
1159    "Failed to generate alignment with selection marked but no groups marked.");
1160    }
1161  0 try
1162    {
1163  0 System.out.println(
1164    "View with no hidden columns, limited to selection and no groups to be collected:");
1165  0 view = new AlignmentView(alignment, hidden, selection, false, true,
1166    false);
1167  0 summariseAlignmentView(view, System.out);
1168    } catch (Exception e)
1169    {
1170  0 e.printStackTrace();
1171  0 System.err.println(
1172    "Failed to generate alignment with selection restricted but no groups marked.");
1173    }
1174  0 try
1175    {
1176  0 System.out.println(
1177    "View with no hidden columns, limited to selection, and all groups to be collected:");
1178  0 view = new AlignmentView(alignment, hidden, selection, false, true,
1179    true);
1180  0 summariseAlignmentView(view, System.out);
1181    } catch (Exception e)
1182    {
1183  0 e.printStackTrace();
1184  0 System.err.println(
1185    "Failed to generate alignment with selection restricted and groups marked.");
1186    }
1187  0 try
1188    {
1189  0 System.out.println(
1190    "View *with* hidden columns, no limit to selection, no groups to be collected:");
1191  0 view = new AlignmentView(alignment, hidden, selection, true, false,
1192    false);
1193  0 summariseAlignmentView(view, System.out);
1194    } catch (Exception e)
1195    {
1196  0 e.printStackTrace();
1197  0 System.err.println(
1198    "Failed to generate alignment with selection but no groups marked.");
1199    }
1200  0 try
1201    {
1202  0 System.out.println(
1203    "View *with* hidden columns, no limit to selection, and all groups to be collected:");
1204  0 view = new AlignmentView(alignment, hidden, selection, true, false,
1205    true);
1206  0 summariseAlignmentView(view, System.out);
1207    } catch (Exception e)
1208    {
1209  0 e.printStackTrace();
1210  0 System.err.println(
1211    "Failed to generate alignment with selection marked but no groups marked.");
1212    }
1213  0 try
1214    {
1215  0 System.out.println(
1216    "View *with* hidden columns, limited to selection and no groups to be collected:");
1217  0 view = new AlignmentView(alignment, hidden, selection, true, true,
1218    false);
1219  0 summariseAlignmentView(view, System.out);
1220    } catch (Exception e)
1221    {
1222  0 e.printStackTrace();
1223  0 System.err.println(
1224    "Failed to generate alignment with selection restricted but no groups marked.");
1225    }
1226  0 try
1227    {
1228  0 System.out.println(
1229    "View *with* hidden columns, limited to selection, and all groups to be collected:");
1230  0 view = new AlignmentView(alignment, hidden, selection, true, true,
1231    true);
1232  0 summariseAlignmentView(view, System.out);
1233    } catch (Exception e)
1234    {
1235  0 e.printStackTrace();
1236  0 System.err.println(
1237    "Failed to generate alignment with selection restricted and groups marked.");
1238    }
1239   
1240    }
1241    }