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