Jalview 2.6 source licence
[jalview.git] / src / jalview / datamodel / AlignmentView.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)\r
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  * \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 package jalview.datamodel;\r
19 \r
20 /**\r
21  * <p>\r
22  * Title:\r
23  * </p>\r
24  * \r
25  * <p>\r
26  * Description:\r
27  * </p>\r
28  * \r
29  * <p>\r
30  * Copyright: Copyright (c) 2004\r
31  * </p>\r
32  * \r
33  * <p>\r
34  * Company: Dundee University\r
35  * </p>\r
36  * \r
37  * @author not attributable\r
38  * @version 1.0\r
39  */\r
40 public class AlignmentView\r
41 {\r
42   /**\r
43    * Transient object compactly representing a 'view' of an alignment - with\r
44    * discontinuities marked.\r
45    */\r
46   private SeqCigar[] sequences = null;\r
47 \r
48   private int[] contigs = null;\r
49 \r
50   private int width = 0;\r
51 \r
52   private int firstCol = 0;\r
53 \r
54   public AlignmentView(CigarArray seqcigararray)\r
55   {\r
56     if (!seqcigararray.isSeqCigarArray())\r
57     {\r
58       throw new Error(\r
59               "Implementation Error - can only make an alignment view from a CigarArray of sequences.");\r
60     }\r
61     // contigs = seqcigararray.applyDeletions();\r
62     contigs = seqcigararray.getDeletedRegions();\r
63     sequences = seqcigararray.getSeqCigarArray();\r
64     width = seqcigararray.getWidth(); // visible width\r
65   }\r
66 \r
67   /**\r
68    * Create an alignmentView where the first column corresponds with the\r
69    * 'firstcol' column of some reference alignment\r
70    * \r
71    * @param sdata\r
72    * @param firstcol\r
73    */\r
74   public AlignmentView(CigarArray sdata, int firstcol)\r
75   {\r
76     this(sdata);\r
77     firstCol = firstcol;\r
78   }\r
79 \r
80   public void setSequences(SeqCigar[] sequences)\r
81   {\r
82     this.sequences = sequences;\r
83   }\r
84 \r
85   public void setContigs(int[] contigs)\r
86   {\r
87     this.contigs = contigs;\r
88   }\r
89 \r
90   public SeqCigar[] getSequences()\r
91   {\r
92     return sequences;\r
93   }\r
94 \r
95   /**\r
96    * @see CigarArray.getDeletedRegions\r
97    * @return int[] { vis_start, sym_start, length }\r
98    */\r
99   public int[] getContigs()\r
100   {\r
101     return contigs;\r
102   }\r
103 \r
104   /**\r
105    * get the full alignment and a columnselection object marking the hidden\r
106    * regions\r
107    * \r
108    * @param gapCharacter\r
109    *          char\r
110    * @return Object[] { SequenceI[], ColumnSelection}\r
111    */\r
112   public Object[] getAlignmentAndColumnSelection(char gapCharacter)\r
113   {\r
114     ColumnSelection colsel = new ColumnSelection();\r
115 \r
116     return new Object[]\r
117     {\r
118         SeqCigar.createAlignmentSequences(sequences, gapCharacter, colsel,\r
119                 contigs), colsel };\r
120   }\r
121 \r
122   /**\r
123    * getSequenceStrings\r
124    * \r
125    * @param c\r
126    *          char\r
127    * @return String[]\r
128    */\r
129   public String[] getSequenceStrings(char c)\r
130   {\r
131     String[] seqs = new String[sequences.length];\r
132     for (int n = 0; n < sequences.length; n++)\r
133     {\r
134       String fullseq = sequences[n].getSequenceString(c);\r
135       if (contigs != null)\r
136       {\r
137         seqs[n] = "";\r
138         int p = 0;\r
139         for (int h = 0; h < contigs.length; h += 3)\r
140         {\r
141           seqs[n] += fullseq.substring(p, contigs[h + 1]);\r
142           p = contigs[h + 1] + contigs[h + 2];\r
143         }\r
144         seqs[n] += fullseq.substring(p);\r
145       }\r
146       else\r
147       {\r
148         seqs[n] = fullseq;\r
149       }\r
150     }\r
151     return seqs;\r
152   }\r
153 \r
154   /**\r
155    * \r
156    * @return visible number of columns in alignment view\r
157    */\r
158   public int getWidth()\r
159   {\r
160     return width;\r
161   }\r
162 \r
163   protected void setWidth(int width)\r
164   {\r
165     this.width = width;\r
166   }\r
167 \r
168   /**\r
169    * get the contiguous subalignments in an alignment view.\r
170    * \r
171    * @param gapCharacter\r
172    *          char\r
173    * @return SequenceI[][]\r
174    */\r
175   public SequenceI[][] getVisibleContigs(char gapCharacter)\r
176   {\r
177     SequenceI[][] smsa;\r
178     int njobs = 1;\r
179     if (sequences == null || width <= 0)\r
180     {\r
181       return null;\r
182     }\r
183     if (contigs != null && contigs.length > 0)\r
184     {\r
185       int start = 0;\r
186       njobs = 0;\r
187       int fwidth = width;\r
188       for (int contig = 0; contig < contigs.length; contig += 3)\r
189       {\r
190         if ((contigs[contig + 1] - start) > 0)\r
191         {\r
192           njobs++;\r
193         }\r
194         fwidth += contigs[contig + 2]; // end up with full region width\r
195         // (including hidden regions)\r
196         start = contigs[contig + 1] + contigs[contig + 2];\r
197       }\r
198       if (start < fwidth)\r
199       {\r
200         njobs++;\r
201       }\r
202       smsa = new SequenceI[njobs][];\r
203       start = 0;\r
204       int j = 0;\r
205       for (int contig = 0; contig < contigs.length; contig += 3)\r
206       {\r
207         if (contigs[contig + 1] - start > 0)\r
208         {\r
209           SequenceI mseq[] = new SequenceI[sequences.length];\r
210           for (int s = 0; s < mseq.length; s++)\r
211           {\r
212             mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(\r
213                     start, contigs[contig + 1]);\r
214           }\r
215           smsa[j] = mseq;\r
216           j++;\r
217         }\r
218         start = contigs[contig + 1] + contigs[contig + 2];\r
219       }\r
220       if (start < fwidth)\r
221       {\r
222         SequenceI mseq[] = new SequenceI[sequences.length];\r
223         for (int s = 0; s < mseq.length; s++)\r
224         {\r
225           mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,\r
226                   fwidth + 1);\r
227         }\r
228         smsa[j] = mseq;\r
229         j++;\r
230       }\r
231     }\r
232     else\r
233     {\r
234       smsa = new SequenceI[1][];\r
235       smsa[0] = new SequenceI[sequences.length];\r
236       for (int s = 0; s < sequences.length; s++)\r
237       {\r
238         smsa[0][s] = sequences[s].getSeq(gapCharacter);\r
239       }\r
240     }\r
241     return smsa;\r
242   }\r
243 \r
244   /**\r
245    * return full msa and hidden regions with visible blocks replaced with new\r
246    * sub alignments\r
247    * \r
248    * @param nvismsa\r
249    *          SequenceI[][]\r
250    * @param orders\r
251    *          AlignmentOrder[] corresponding to each SequenceI[] block.\r
252    * @return Object[]\r
253    */\r
254   public Object[] getUpdatedView(SequenceI[][] nvismsa,\r
255           AlignmentOrder[] orders, char gapCharacter)\r
256   {\r
257     if (sequences == null || width <= 0)\r
258     {\r
259       throw new Error("empty view cannot be updated.");\r
260     }\r
261     if (nvismsa == null)\r
262     {\r
263       throw new Error(\r
264               "nvismsa==null. use getAlignmentAndColumnSelection() instead.");\r
265     }\r
266     if (contigs != null && contigs.length > 0)\r
267     {\r
268       SequenceI[] alignment = new SequenceI[sequences.length];\r
269       ColumnSelection columnselection = new ColumnSelection();\r
270       if (contigs != null && contigs.length > 0)\r
271       {\r
272         int start = 0;\r
273         int nwidth = 0;\r
274         int owidth = width;\r
275         int j = 0;\r
276         for (int contig = 0; contig < contigs.length; contig += 3)\r
277         {\r
278           owidth += contigs[contig + 2]; // recover final column width\r
279           if (contigs[contig + 1] - start > 0)\r
280           {\r
281             int swidth = 0; // subalignment width\r
282             if (nvismsa[j] != null)\r
283             {\r
284               SequenceI mseq[] = nvismsa[j];\r
285               AlignmentOrder order = (orders == null) ? null : orders[j];\r
286               j++;\r
287               if (mseq.length != sequences.length)\r
288               {\r
289                 throw new Error(\r
290                         "Mismatch between number of sequences in block "\r
291                                 + j + " (" + mseq.length\r
292                                 + ") and the original view ("\r
293                                 + sequences.length + ")");\r
294               }\r
295               swidth = mseq[0].getLength(); // JBPNote: could ensure padded\r
296               // here.\r
297               for (int s = 0; s < mseq.length; s++)\r
298               {\r
299                 if (alignment[s] == null)\r
300                 {\r
301                   alignment[s] = mseq[s];\r
302                 }\r
303                 else\r
304                 {\r
305                   alignment[s].setSequence(alignment[s]\r
306                           .getSequenceAsString()\r
307                           + mseq[s].getSequenceAsString());\r
308                   if (mseq[s].getStart() <= mseq[s].getEnd())\r
309                   {\r
310                     alignment[s].setEnd(mseq[s].getEnd());\r
311                   }\r
312                   if (order != null)\r
313                   {\r
314                     order.updateSequence(mseq[s], alignment[s]);\r
315                   }\r
316                 }\r
317               }\r
318             }\r
319             else\r
320             {\r
321               // recover original alignment block or place gaps\r
322               if (true)\r
323               {\r
324                 // recover input data\r
325                 for (int s = 0; s < sequences.length; s++)\r
326                 {\r
327                   SequenceI oseq = sequences[s].getSeq(gapCharacter)\r
328                           .getSubSequence(start, contigs[contig + 1]);\r
329                   if (swidth < oseq.getLength())\r
330                   {\r
331                     swidth = oseq.getLength();\r
332                   }\r
333                   if (alignment[s] == null)\r
334                   {\r
335                     alignment[s] = oseq;\r
336                   }\r
337                   else\r
338                   {\r
339                     alignment[s].setSequence(alignment[s]\r
340                             .getSequenceAsString()\r
341                             + oseq.getSequenceAsString());\r
342                     if (oseq.getEnd() >= oseq.getStart())\r
343                     {\r
344                       alignment[s].setEnd(oseq.getEnd());\r
345                     }\r
346                   }\r
347                 }\r
348 \r
349               }\r
350               j++;\r
351             }\r
352             nwidth += swidth;\r
353           }\r
354           // advance to begining of visible region\r
355           start = contigs[contig + 1] + contigs[contig + 2];\r
356           // add hidden segment to right of next region\r
357           for (int s = 0; s < sequences.length; s++)\r
358           {\r
359             SequenceI hseq = sequences[s].getSeq(gapCharacter)\r
360                     .getSubSequence(contigs[contig + 1], start);\r
361             if (alignment[s] == null)\r
362             {\r
363               alignment[s] = hseq;\r
364             }\r
365             else\r
366             {\r
367               alignment[s].setSequence(alignment[s].getSequenceAsString()\r
368                       + hseq.getSequenceAsString());\r
369               if (hseq.getEnd() >= hseq.getStart())\r
370               {\r
371                 alignment[s].setEnd(hseq.getEnd());\r
372               }\r
373             }\r
374           }\r
375           // mark hidden segment as hidden in the new alignment\r
376           columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2]\r
377                   - 1);\r
378           nwidth += contigs[contig + 2];\r
379         }\r
380         // Do final segment - if it exists\r
381         if (j < nvismsa.length)\r
382         {\r
383           int swidth = 0;\r
384           if (nvismsa[j] != null)\r
385           {\r
386             SequenceI mseq[] = nvismsa[j];\r
387             AlignmentOrder order = (orders != null) ? orders[j] : null;\r
388             swidth = mseq[0].getLength();\r
389             for (int s = 0; s < mseq.length; s++)\r
390             {\r
391               if (alignment[s] == null)\r
392               {\r
393                 alignment[s] = mseq[s];\r
394               }\r
395               else\r
396               {\r
397                 alignment[s].setSequence(alignment[s].getSequenceAsString()\r
398                         + mseq[s].getSequenceAsString());\r
399                 if (mseq[s].getEnd() >= mseq[s].getStart())\r
400                 {\r
401                   alignment[s].setEnd(mseq[s].getEnd());\r
402                 }\r
403                 if (order != null)\r
404                 {\r
405                   order.updateSequence(mseq[s], alignment[s]);\r
406                 }\r
407               }\r
408             }\r
409           }\r
410           else\r
411           {\r
412             if (start < owidth)\r
413             {\r
414               // recover input data or place gaps\r
415               if (true)\r
416               {\r
417                 // recover input data\r
418                 for (int s = 0; s < sequences.length; s++)\r
419                 {\r
420                   SequenceI oseq = sequences[s].getSeq(gapCharacter)\r
421                           .getSubSequence(start, owidth + 1);\r
422                   if (swidth < oseq.getLength())\r
423                   {\r
424                     swidth = oseq.getLength();\r
425                   }\r
426                   if (alignment[s] == null)\r
427                   {\r
428                     alignment[s] = oseq;\r
429                   }\r
430                   else\r
431                   {\r
432                     alignment[s].setSequence(alignment[s]\r
433                             .getSequenceAsString()\r
434                             + oseq.getSequenceAsString());\r
435                     if (oseq.getEnd() >= oseq.getStart())\r
436                     {\r
437                       alignment[s].setEnd(oseq.getEnd());\r
438                     }\r
439                   }\r
440                 }\r
441                 nwidth += swidth;\r
442               }\r
443               else\r
444               {\r
445                 // place gaps.\r
446                 throw new Error("Padding not yet implemented.");\r
447               }\r
448             }\r
449           }\r
450         }\r
451       }\r
452       return new Object[]\r
453       { alignment, columnselection };\r
454     }\r
455     else\r
456     {\r
457       if (nvismsa.length != 1)\r
458       {\r
459         throw new Error(\r
460                 "Mismatch between visible blocks to update and number of contigs in view (contigs=0,blocks="\r
461                         + nvismsa.length);\r
462       }\r
463       if (nvismsa[0] != null)\r
464       {\r
465         return new Object[]\r
466         { nvismsa[0], new ColumnSelection() };\r
467       }\r
468       else\r
469       {\r
470         return getAlignmentAndColumnSelection(gapCharacter);\r
471       }\r
472     }\r
473   }\r
474 \r
475   /**\r
476    * returns simple array of start end positions of visible range on alignment.\r
477    * vis_start and vis_end are inclusive - use\r
478    * SequenceI.getSubSequence(vis_start, vis_end+1) to recover visible sequence\r
479    * from underlying alignment.\r
480    * \r
481    * @return int[] { start_i, end_i } for 1<i<n visible regions.\r
482    */\r
483   public int[] getVisibleContigs()\r
484   {\r
485     if (contigs != null && contigs.length > 0)\r
486     {\r
487       int start = 0;\r
488       int nvis = 0;\r
489       int fwidth = width;\r
490       for (int contig = 0; contig < contigs.length; contig += 3)\r
491       {\r
492         if ((contigs[contig + 1] - start) > 0)\r
493         {\r
494           nvis++;\r
495         }\r
496         fwidth += contigs[contig + 2]; // end up with full region width\r
497         // (including hidden regions)\r
498         start = contigs[contig + 1] + contigs[contig + 2];\r
499       }\r
500       if (start < fwidth)\r
501       {\r
502         nvis++;\r
503       }\r
504       int viscontigs[] = new int[nvis * 2];\r
505       nvis = 0;\r
506       start = 0;\r
507       for (int contig = 0; contig < contigs.length; contig += 3)\r
508       {\r
509         if ((contigs[contig + 1] - start) > 0)\r
510         {\r
511           viscontigs[nvis] = start;\r
512           viscontigs[nvis + 1] = contigs[contig + 1] - 1; // end is inclusive\r
513           nvis += 2;\r
514         }\r
515         start = contigs[contig + 1] + contigs[contig + 2];\r
516       }\r
517       if (start < fwidth)\r
518       {\r
519         viscontigs[nvis] = start;\r
520         viscontigs[nvis + 1] = fwidth; // end is inclusive\r
521         nvis += 2;\r
522       }\r
523       return viscontigs;\r
524     }\r
525     else\r
526     {\r
527       return new int[]\r
528       { 0, width };\r
529     }\r
530   }\r
531 \r
532   /**\r
533    * \r
534    * @return position of first visible column of AlignmentView within its\r
535    *         parent's alignment reference frame\r
536    */\r
537   public int getAlignmentOrigin()\r
538   {\r
539     // TODO Auto-generated method stub\r
540     return firstCol;\r
541   }\r
542 }\r