Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.datamodel

File AlignmentView.java

 

Coverage histogram

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

Code metrics

240
432
31
2
1,268
955
180
0.42
13.94
15.5
5.81

Classes

Class Line # Actions
AlignmentView 36 417 173
0.410898441.1%
AlignmentView.ScGroup 70 15 7
0.3333333433.3%
 

Contributing tests

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