javadoc on contigs
[jalview.git] / src / jalview / datamodel / AlignmentView.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.datamodel;
20
21
22
23 /**
24  * <p>Title: </p>
25  *
26  * <p>Description: </p>
27  *
28  * <p>Copyright: Copyright (c) 2004</p>
29  *
30  * <p>Company: Dundee University</p>
31  *
32  * @author not attributable
33  * @version 1.0
34  */
35 public class AlignmentView
36 {
37     /**
38      * Transient object compactly representing a 'view' of an alignment - with discontinuities marked.
39      */
40     private SeqCigar[] sequences = null;
41   private int[] contigs = null;
42   private int width=0;
43   public AlignmentView(CigarArray seqcigararray)
44   {
45     if (!seqcigararray.isSeqCigarArray())
46       throw new Error("Implementation Error - can only make an alignment view from a CigarArray of sequences.");
47     //contigs = seqcigararray.applyDeletions();
48     contigs = seqcigararray.getDeletedRegions();
49     sequences = seqcigararray.getSeqCigarArray();
50     width = seqcigararray.getWidth(); // visible width
51   }
52
53   public void setSequences(SeqCigar[] sequences)
54   {
55     this.sequences = sequences;
56   }
57
58   public void setContigs(int[] contigs)
59   {
60     this.contigs = contigs;
61   }
62
63   public SeqCigar[] getSequences()
64   {
65     return sequences;
66   }
67   /**
68    * @see CigarArray.getDeletedRegions
69    * @return int[] { vis_start, sym_start, length }
70    */
71   public int[] getContigs()
72   {
73     return contigs;
74   }
75   /**
76    * get the full alignment and a columnselection object marking the hidden regions
77    * @param gapCharacter char
78    * @return Object[] { SequenceI[], ColumnSelection}
79    */
80   public Object[] getAlignmentAndColumnSelection(char gapCharacter) {
81     ColumnSelection colsel = new ColumnSelection();
82
83     return new Object[] { SeqCigar.createAlignmentSequences(sequences, gapCharacter, colsel, contigs), colsel};
84   }
85   /**
86    * getSequenceStrings
87    *
88    * @param c char
89    * @return String[]
90    */
91   public String[] getSequenceStrings(char c)
92   {
93     String[] seqs=new String[sequences.length];
94     for (int n=0; n<sequences.length; n++) {
95       String fullseq = sequences[n].getSequenceString(c);
96       if (contigs != null)
97       {
98         seqs[n] = "";
99         int p = 0;
100         for (int h = 0; h < contigs.length; h += 3)
101         {
102           seqs[n] += fullseq.substring(p, contigs[h + 1]);
103           p = contigs[h + 1] + contigs[h + 2];
104         }
105         seqs[n] += fullseq.substring(p);
106       } else
107         seqs[n] = fullseq;
108     }
109     return seqs;
110   }
111   /**
112    *
113    * @return visible number of columns in alignment view
114    */
115   public int getWidth() {
116     return width;
117   }
118
119   protected void setWidth(int width) {
120     this.width = width;
121   }
122   /**
123    * get the contiguous subalignments in an alignment view.
124    * @param gapCharacter char
125    * @return SequenceI[][]
126    */
127   public SequenceI[][] getVisibleContigs(char gapCharacter) {
128     SequenceI[][] smsa;
129     int njobs = 1;
130     if (sequences==null || width<=0)
131       return null;
132     if (contigs != null && contigs.length > 0)
133     {
134       int start = 0;
135       njobs = 0;
136       int fwidth = width;
137       for (int contig = 0; contig < contigs.length; contig += 3)
138       {
139         if ( (contigs[contig + 1] - start) > 0)
140         {
141           njobs++;
142         }
143         fwidth += contigs[contig + 2]; // end up with full region width (including hidden regions)
144         start = contigs[contig + 1] + contigs[contig + 2];
145       }
146       if (start < fwidth)
147       {
148         njobs++;
149       }
150       smsa = new SequenceI[njobs][];
151       start = 0;
152       int j = 0;
153       for (int contig = 0; contig < contigs.length; contig += 3)
154       {
155         if (contigs[contig + 1] - start > 0)
156         {
157           SequenceI mseq[] = new SequenceI[sequences.length];
158           for (int s = 0; s < mseq.length; s++)
159           {
160             mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,
161                 contigs[contig + 1]);
162           }
163           smsa[j] = mseq;
164           j++;
165         }
166         start = contigs[contig + 1] + contigs[contig + 2];
167       }
168       if (start < fwidth)
169       {
170         SequenceI mseq[] = new SequenceI[sequences.length];
171         for (int s = 0; s < mseq.length; s++)
172         {
173           mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,
174               fwidth + 1);
175         }
176         smsa[j] = mseq;
177         j++;
178       }
179     }
180     else
181     {
182       smsa = new SequenceI[1][];
183       smsa[0] = new SequenceI[sequences.length];
184       for (int s = 0; s < sequences.length; s++)
185       {
186         smsa[0][s] = sequences[s].getSeq(gapCharacter);
187       }
188     }
189     return smsa;
190   }
191   /**
192    * return full msa and hidden regions with visible blocks replaced with new sub alignments
193    * @param nvismsa SequenceI[][]
194    * @param orders AlignmentOrder[] corresponding to each SequenceI[] block.
195    * @return Object[]
196    */
197   public Object[] getUpdatedView(SequenceI[][] nvismsa, AlignmentOrder[] orders, char gapCharacter) {
198     if (sequences == null || width <= 0)
199     {
200       throw new Error("empty view cannot be updated.");
201     }
202     if (nvismsa == null)
203       throw new Error(
204           "nvismsa==null. use getAlignmentAndColumnSelection() instead.");
205     if (contigs != null && contigs.length > 0)
206     {
207       SequenceI[] alignment = new SequenceI[sequences.length];
208       ColumnSelection columnselection = new ColumnSelection();
209       if (contigs != null && contigs.length > 0)
210       {
211         int start = 0;
212         int nwidth = 0;
213         int owidth = width;
214         int j = 0;
215         for (int contig = 0; contig < contigs.length; contig += 3)
216         {
217           owidth += contigs[contig + 2]; // recover final column width
218           if (contigs[contig + 1] - start > 0)
219           {
220             int swidth = 0; // subalignment width
221             if (nvismsa[j] != null)
222             {
223               SequenceI mseq[] = nvismsa[j];
224               AlignmentOrder order=(orders==null) ? null : orders[j];
225               j++;
226               if (mseq.length!=sequences.length)
227                 throw new Error("Mismatch between number of sequences in block "+j+" ("+mseq.length+") and the original view ("+sequences.length+")");
228               swidth = mseq[0].getLength(); // JBPNote: could ensure padded here.
229               for (int s = 0; s < mseq.length; s++)
230               {
231                 if (alignment[s] == null)
232                 {
233                   alignment[s] = mseq[s];
234                 }
235                 else
236                 {
237                   alignment[s].setSequence(alignment[s].getSequence() +
238                                            mseq[s].getSequence());
239                   if (mseq[s].getStart() <= mseq[s].getEnd())
240                   {
241                     alignment[s].setEnd(mseq[s].getEnd());
242                   }
243                   if (order!=null) {
244                     order.updateSequence(mseq[s], alignment[s]);
245                   }
246                 }
247               }
248             }
249             else
250             {
251               // recover original alignment block or place gaps
252               if (true)
253               {
254                 // recover input data
255                 for (int s = 0; s < sequences.length; s++)
256                 {
257                   SequenceI oseq = sequences[s].getSeq(gapCharacter).getSubSequence(start,
258                       contigs[contig + 1]);
259                   if (swidth < oseq.getLength())
260                   {
261                     swidth = oseq.getLength();
262                   }
263                   if (alignment[s] == null)
264                   {
265                     alignment[s] = oseq;
266                   }
267                   else
268                   {
269                     alignment[s].setSequence(alignment[s].getSequence() +
270                                              oseq.getSequence());
271                     if (oseq.getEnd() >= oseq.getStart())
272                     {
273                       alignment[s].setEnd(oseq.getEnd());
274                     }
275                   }
276                 }
277
278               }
279               j++;
280             }
281             nwidth += swidth;
282           }
283           // advance to begining of visible region
284           start = contigs[contig + 1] + contigs[contig + 2];
285           // add hidden segment to right of next region
286           for (int s = 0; s < sequences.length; s++)
287           {
288             SequenceI hseq = sequences[s].getSeq(gapCharacter).getSubSequence(contigs[contig +
289                 1], start);
290             if (alignment[s] == null)
291             {
292               alignment[s] = hseq;
293             }
294             else
295             {
296               alignment[s].setSequence(alignment[s].getSequence() +
297                                        hseq.getSequence());
298               if (hseq.getEnd() >= hseq.getStart())
299               {
300                 alignment[s].setEnd(hseq.getEnd());
301               }
302             }
303           }
304           // mark hidden segment as hidden in the new alignment
305           columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
306           nwidth += contigs[contig + 2];
307         }
308         // Do final segment - if it exists
309         if (j < nvismsa.length)
310         {
311           int swidth = 0;
312           if (nvismsa[j] != null)
313           {
314             SequenceI mseq[] = nvismsa[j];
315             AlignmentOrder order = (orders!=null) ? orders[j] : null;
316             swidth = mseq[0].getLength();
317             for (int s = 0; s < mseq.length; s++)
318             {
319               if (alignment[s] == null)
320               {
321                 alignment[s] = mseq[s];
322               }
323               else
324               {
325                 alignment[s].setSequence(alignment[s].getSequence() +
326                                          mseq[s].getSequence());
327                 if (mseq[s].getEnd() >= mseq[s].getStart())
328                 {
329                   alignment[s].setEnd(mseq[s].getEnd());
330                 }
331                 if (order!=null) {
332                   order.updateSequence(mseq[s], alignment[s]);
333                 }
334               }
335             }
336           }
337           else
338           {
339             if (start < owidth)
340             {
341               // recover input data or place gaps
342               if (true)
343               {
344                 // recover input data
345                 for (int s = 0; s < sequences.length; s++)
346                 {
347                   SequenceI oseq = sequences[s].getSeq(gapCharacter).getSubSequence(start,
348                       owidth + 1);
349                   if (swidth < oseq.getLength())
350                   {
351                     swidth = oseq.getLength();
352                   }
353                   if (alignment[s] == null)
354                   {
355                     alignment[s] = oseq;
356                   }
357                   else
358                   {
359                     alignment[s].setSequence(alignment[s].getSequence() +
360                                              oseq.getSequence());
361                     if (oseq.getEnd() >= oseq.getStart())
362                     {
363                       alignment[s].setEnd(oseq.getEnd());
364                     }
365                   }
366                 }
367                 nwidth += swidth;
368               }
369               else
370               {
371                 // place gaps.
372                 throw new Error("Padding not yet implemented.");
373               }
374             }
375           }
376         }
377       }
378       return new Object[] { alignment, columnselection};
379     } else {
380       if (nvismsa.length!=1)
381         throw new Error("Mismatch between visible blocks to update and number of contigs in view (contigs=0,blocks="+nvismsa.length);
382       if (nvismsa[0]!=null)
383         return new Object[] { nvismsa[0], new ColumnSelection()};
384       else
385         return getAlignmentAndColumnSelection(gapCharacter);
386     }
387   }
388
389 }