c9ae0446605b4fa6ed1ac598379c789d6c76aed2
[jalview.git] / src / jalview / analysis / AlignSeq.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 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.analysis;
20
21 import java.util.*;
22
23 import java.awt.*;
24
25 import jalview.datamodel.*;
26 import jalview.schemes.*;
27 import jalview.util.*;
28
29 /**
30  * 
31  * 
32  * @author $author$
33  * @version $Revision$
34  */
35 public class AlignSeq
36 {
37   public static final String PEP = "pep";
38
39   public static final String DNA = "dna";
40
41   static String[] dna =
42   { "A", "C", "G", "T", "-" };
43
44   // "C", "T", "A", "G", "-"};
45   static String[] pep =
46   { "A", "R", "N", "D", "C", "Q", "E", "G", "H", "I", "L", "K", "M", "F",
47       "P", "S", "T", "W", "Y", "V", "B", "Z", "X", "-" };
48
49   int[][] score;
50
51   int[][] E;
52
53   int[][] F;
54
55   int[][] traceback;
56
57   int[] seq1;
58
59   int[] seq2;
60
61   SequenceI s1;
62
63   SequenceI s2;
64
65   public String s1str;
66
67   public String s2str;
68
69   int maxi;
70
71   int maxj;
72
73   int[] aseq1;
74
75   int[] aseq2;
76
77   public String astr1 = "";
78
79   public String astr2 = "";
80
81   /** DOCUMENT ME!! */
82   public int seq1start;
83
84   /** DOCUMENT ME!! */
85   public int seq1end;
86
87   /** DOCUMENT ME!! */
88   public int seq2start;
89
90   /** DOCUMENT ME!! */
91   public int seq2end;
92
93   int count;
94
95   /** DOCUMENT ME!! */
96   public int maxscore;
97
98   float pid;
99
100   int prev = 0;
101
102   int gapOpen = 120;
103
104   int gapExtend = 20;
105
106   int[][] lookup = ResidueProperties.getBLOSUM62();
107
108   String[] intToStr = pep;
109
110   int defInt = 23;
111
112   StringBuffer output = new StringBuffer();
113
114   String type;
115
116   private  int[] charToInt;
117
118   /**
119    * Creates a new AlignSeq object.
120    * 
121    * @param s1
122    *                DOCUMENT ME!
123    * @param s2
124    *                DOCUMENT ME!
125    * @param type
126    *                DOCUMENT ME!
127    */
128   public AlignSeq(SequenceI s1, SequenceI s2, String type)
129   {
130     SeqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(),
131             type);
132   }
133
134   /**
135    * Creates a new AlignSeq object.
136    * 
137    * @param s1
138    *                DOCUMENT ME!
139    * @param s2
140    *                DOCUMENT ME!
141    * @param type
142    *                DOCUMENT ME!
143    */
144   public AlignSeq(SequenceI s1, String string1, SequenceI s2,
145           String string2, String type)
146   {
147     SeqInit(s1, string1, s2, string2, type);
148   }
149
150   /**
151    * DOCUMENT ME!
152    * 
153    * @return DOCUMENT ME!
154    */
155   public int getMaxScore()
156   {
157     return maxscore;
158   }
159
160   /**
161    * DOCUMENT ME!
162    * 
163    * @return DOCUMENT ME!
164    */
165   public int getSeq2Start()
166   {
167     return seq2start;
168   }
169
170   /**
171    * DOCUMENT ME!
172    * 
173    * @return DOCUMENT ME!
174    */
175   public int getSeq2End()
176   {
177     return seq2end;
178   }
179
180   /**
181    * DOCUMENT ME!
182    * 
183    * @return DOCUMENT ME!
184    */
185   public int getSeq1Start()
186   {
187     return seq1start;
188   }
189
190   /**
191    * DOCUMENT ME!
192    * 
193    * @return DOCUMENT ME!
194    */
195   public int getSeq1End()
196   {
197     return seq1end;
198   }
199
200   /**
201    * DOCUMENT ME!
202    * 
203    * @return DOCUMENT ME!
204    */
205   public String getOutput()
206   {
207     return output.toString();
208   }
209
210   /**
211    * DOCUMENT ME!
212    * 
213    * @return DOCUMENT ME!
214    */
215   public String getAStr1()
216   {
217     return astr1;
218   }
219
220   /**
221    * DOCUMENT ME!
222    * 
223    * @return DOCUMENT ME!
224    */
225   public String getAStr2()
226   {
227     return astr2;
228   }
229
230   /**
231    * DOCUMENT ME!
232    * 
233    * @return DOCUMENT ME!
234    */
235   public int[] getASeq1()
236   {
237     return aseq1;
238   }
239
240   /**
241    * DOCUMENT ME!
242    * 
243    * @return DOCUMENT ME!
244    */
245   public int[] getASeq2()
246   {
247     return aseq2;
248   }
249
250   /**
251    * DOCUMENT ME!
252    * 
253    * @return DOCUMENT ME!
254    */
255   public SequenceI getS1()
256   {
257     return s1;
258   }
259
260   /**
261    * DOCUMENT ME!
262    * 
263    * @return DOCUMENT ME!
264    */
265   public SequenceI getS2()
266   {
267     return s2;
268   }
269
270   /**
271    * DOCUMENT ME!
272    * 
273    * @param s1
274    *                DOCUMENT ME!
275    * @param string1 -
276    *                string to align for sequence1
277    * @param s2
278    *                sequence 2
279    * @param string2 -
280    *                string to align for sequence2
281    * @param type
282    *                DNA or PEPTIDE
283    */
284   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
285           String string2, String type)
286   {
287     this.s1 = s1;
288     this.s2 = s2;
289     setDefaultParams(type);
290     SeqInit(string1, string2);
291   }
292
293   public void SeqInit(SequenceI s1, String string1, SequenceI s2,
294           String string2, ScoreMatrix scoreMatrix)
295   {
296     this.s1 = s1;
297     this.s2 = s2;
298     setType(scoreMatrix.isDNA() ? AlignSeq.DNA : AlignSeq.PEP);
299     lookup = scoreMatrix.getMatrix();
300   }
301
302   /**
303    * construct score matrix for string1 and string2 (after removing any existing
304    * gaps
305    * 
306    * @param string1
307    * @param string2
308    */
309   private void SeqInit(String string1, String string2)
310   {
311     s1str = extractGaps(jalview.util.Comparison.GapChars, string1);
312     s2str = extractGaps(jalview.util.Comparison.GapChars, string2);
313
314     if (s1str.length() == 0 || s2str.length() == 0)
315     {
316       output.append("ALL GAPS: "
317               + (s1str.length() == 0 ? s1.getName() : " ")
318               + (s2str.length() == 0 ? s2.getName() : ""));
319       return;
320     }
321
322     // System.out.println("lookuip " + rt.freeMemory() + " "+ rt.totalMemory());
323     seq1 = new int[s1str.length()];
324
325     // System.out.println("seq1 " + rt.freeMemory() +" " + rt.totalMemory());
326     seq2 = new int[s2str.length()];
327
328     // System.out.println("seq2 " + rt.freeMemory() + " " + rt.totalMemory());
329     score = new int[s1str.length()][s2str.length()];
330
331     // System.out.println("score " + rt.freeMemory() + " " + rt.totalMemory());
332     E = new int[s1str.length()][s2str.length()];
333
334     // System.out.println("E " + rt.freeMemory() + " " + rt.totalMemory());
335     F = new int[s1str.length()][s2str.length()];
336     traceback = new int[s1str.length()][s2str.length()];
337
338     // System.out.println("F " + rt.freeMemory() + " " + rt.totalMemory());
339     seq1 = stringToInt(s1str, type);
340
341     // System.out.println("seq1 " + rt.freeMemory() + " " + rt.totalMemory());
342     seq2 = stringToInt(s2str, type);
343
344     // System.out.println("Seq2 " + rt.freeMemory() + " " + rt.totalMemory());
345     // long tstart = System.currentTimeMillis();
346     // calcScoreMatrix();
347     // long tend = System.currentTimeMillis();
348     // System.out.println("Time take to calculate score matrix = " +
349     // (tend-tstart) + " ms");
350     // printScoreMatrix(score);
351     // System.out.println();
352     // printScoreMatrix(traceback);
353     // System.out.println();
354     // printScoreMatrix(E);
355     // System.out.println();
356     // /printScoreMatrix(F);
357     // System.out.println();
358     // tstart = System.currentTimeMillis();
359     // traceAlignment();
360     // tend = System.currentTimeMillis();
361     // System.out.println("Time take to traceback alignment = " + (tend-tstart)
362     // + " ms");
363   }
364
365   private void setDefaultParams(String type)
366   {
367     setType(type);
368
369     if (type.equals(AlignSeq.PEP))
370     {
371       lookup = ResidueProperties.getDefaultPeptideMatrix();
372     }
373     else if (type.equals(AlignSeq.DNA))
374     {
375       lookup = ResidueProperties.getDefaultDnaMatrix();
376     }
377   }
378
379   private void setType(String type2)
380   {
381     this.type = type2;
382     if (type.equals(AlignSeq.PEP))
383     {
384       intToStr = pep;
385       charToInt = ResidueProperties.aaIndex;
386       defInt = 23;
387     }
388     else if (type.equals(AlignSeq.DNA))
389     {
390       intToStr = dna;
391       charToInt = ResidueProperties.nucleotideIndex;
392       defInt = 4;
393     }
394     else
395     {
396       output.append("Wrong type = dna or pep only");
397       throw new Error("Unknown Type " + type2
398               + " - dna or pep are the only allowed values.");
399     }
400   }
401
402   /**
403    * DOCUMENT ME!
404    */
405   public void traceAlignment()
406   {
407     // Find the maximum score along the rhs or bottom row
408     int max = -9999;
409
410     for (int i = 0; i < seq1.length; i++)
411     {
412       if (score[i][seq2.length - 1] > max)
413       {
414         max = score[i][seq2.length - 1];
415         maxi = i;
416         maxj = seq2.length - 1;
417       }
418     }
419
420     for (int j = 0; j < seq2.length; j++)
421     {
422       if (score[seq1.length - 1][j] > max)
423       {
424         max = score[seq1.length - 1][j];
425         maxi = seq1.length - 1;
426         maxj = j;
427       }
428     }
429
430     // System.out.println(maxi + " " + maxj + " " + score[maxi][maxj]);
431     int i = maxi;
432     int j = maxj;
433     int trace;
434     maxscore = score[i][j] / 10;
435
436     seq1end = maxi + 1;
437     seq2end = maxj + 1;
438
439     aseq1 = new int[seq1.length + seq2.length];
440     aseq2 = new int[seq1.length + seq2.length];
441
442     count = (seq1.length + seq2.length) - 1;
443
444     while ((i > 0) && (j > 0))
445     {
446       if ((aseq1[count] != defInt) && (i >= 0))
447       {
448         aseq1[count] = seq1[i];
449         astr1 = s1str.charAt(i) + astr1;
450       }
451
452       if ((aseq2[count] != defInt) && (j > 0))
453       {
454         aseq2[count] = seq2[j];
455         astr2 = s2str.charAt(j) + astr2;
456       }
457
458       trace = findTrace(i, j);
459
460       if (trace == 0)
461       {
462         i--;
463         j--;
464       }
465       else if (trace == 1)
466       {
467         j--;
468         aseq1[count] = defInt;
469         astr1 = "-" + astr1.substring(1);
470       }
471       else if (trace == -1)
472       {
473         i--;
474         aseq2[count] = defInt;
475         astr2 = "-" + astr2.substring(1);
476       }
477
478       count--;
479     }
480
481     seq1start = i + 1;
482     seq2start = j + 1;
483
484     if (aseq1[count] != defInt)
485     {
486       aseq1[count] = seq1[i];
487       astr1 = s1str.charAt(i) + astr1;
488     }
489
490     if (aseq2[count] != defInt)
491     {
492       aseq2[count] = seq2[j];
493       astr2 = s2str.charAt(j) + astr2;
494     }
495   }
496
497   /**
498    * DOCUMENT ME!
499    */
500   public void printAlignment(java.io.PrintStream os)
501   {
502     // TODO: Use original sequence characters rather than re-translated
503     // characters in output
504     // Find the biggest id length for formatting purposes
505     int maxid = s1.getName().length();
506     if (s2.getName().length() > maxid)
507     {
508       maxid = s2.getName().length();
509     }
510
511     int len = 72 - maxid - 1;
512     int nochunks = ((aseq1.length - count) / len) + 1;
513     pid = 0;
514
515     output.append("Score = " + score[maxi][maxj] + "\n");
516     output.append("Length of alignment = " + (aseq1.length - count) + "\n");
517     output.append("Sequence ");
518     output.append(new Format("%" + maxid + "s").form(s1.getName()));
519     output.append(" :  " + s1.getStart() + " - " + s1.getEnd()
520             + " (Sequence length = " + s1str.length() + ")\n");
521     output.append("Sequence ");
522     output.append(new Format("%" + maxid + "s").form(s2.getName()));
523     output.append(" :  " + s2.getStart() + " - " + s2.getEnd()
524             + " (Sequence length = " + s2str.length() + ")\n\n");
525
526     for (int j = 0; j < nochunks; j++)
527     {
528       // Print the first aligned sequence
529       output.append(new Format("%" + (maxid) + "s").form(s1.getName())
530               + " ");
531
532       for (int i = 0; i < len; i++)
533       {
534         if ((i + (j * len)) < astr1.length())
535         {
536           output.append(astr1.charAt(i + (j * len)));
537         }
538       }
539
540       output.append("\n");
541       output.append(new Format("%" + (maxid) + "s").form(" ") + " ");
542
543       // Print out the matching chars
544       for (int i = 0; i < len; i++)
545       {
546         if ((i + (j * len)) < astr1.length())
547         {
548           if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
549                   && !jalview.util.Comparison.isGap(astr1.charAt(i
550                           + (j * len))))
551           {
552             pid++;
553             output.append("|");
554           }
555           else if (type.equals("pep"))
556           {
557             if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
558                     astr2.charAt(i + (j * len))) > 0)
559             {
560               output.append(".");
561             }
562             else
563             {
564               output.append(" ");
565             }
566           }
567           else
568           {
569             output.append(" ");
570           }
571         }
572       }
573
574       // Now print the second aligned sequence
575       output = output.append("\n");
576       output = output.append(new Format("%" + (maxid) + "s").form(s2
577               .getName())
578               + " ");
579
580       for (int i = 0; i < len; i++)
581       {
582         if ((i + (j * len)) < astr2.length())
583         {
584           output.append(astr2.charAt(i + (j * len)));
585         }
586       }
587
588       output = output.append("\n\n");
589     }
590
591     pid = pid / (float) (aseq1.length - count) * 100;
592     output = output.append(new Format("Percentage ID = %2.2f\n\n")
593             .form(pid));
594
595     try
596     {
597       os.print(output.toString());
598     } catch (Exception ex)
599     {
600     }
601   }
602
603   /**
604    * DOCUMENT ME!
605    * 
606    * @param mat
607    *                DOCUMENT ME!
608    */
609   public void printScoreMatrix(int[][] mat)
610   {
611     int n = seq1.length;
612     int m = seq2.length;
613
614     for (int i = 0; i < n; i++)
615     {
616       // Print the top sequence
617       if (i == 0)
618       {
619         Format.print(System.out, "%8s", s2str.substring(0, 1));
620
621         for (int jj = 1; jj < m; jj++)
622         {
623           Format.print(System.out, "%5s", s2str.substring(jj, jj + 1));
624         }
625
626         System.out.println();
627       }
628
629       for (int j = 0; j < m; j++)
630       {
631         if (j == 0)
632         {
633           Format.print(System.out, "%3s", s1str.substring(i, i + 1));
634         }
635
636         Format.print(System.out, "%3d ", mat[i][j] / 10);
637       }
638
639       System.out.println();
640     }
641   }
642
643   /**
644    * DOCUMENT ME!
645    * 
646    * @param i
647    *                DOCUMENT ME!
648    * @param j
649    *                DOCUMENT ME!
650    * 
651    * @return DOCUMENT ME!
652    */
653   public int findTrace(int i, int j)
654   {
655     int t = 0;
656     int max = score[i - 1][j - 1] + (lookup[seq1[i]][seq2[j]] * 10);
657
658     if (F[i][j] > max)
659     {
660       max = F[i][j];
661       t = -1;
662     }
663     else if (F[i][j] == max)
664     {
665       if (prev == -1)
666       {
667         max = F[i][j];
668         t = -1;
669       }
670     }
671
672     if (E[i][j] >= max)
673     {
674       max = E[i][j];
675       t = 1;
676     }
677     else if (E[i][j] == max)
678     {
679       if (prev == 1)
680       {
681         max = E[i][j];
682         t = 1;
683       }
684     }
685
686     prev = t;
687
688     return t;
689   }
690
691   /**
692    * DOCUMENT ME!
693    */
694   public void calcScoreMatrix()
695   {
696     int n = seq1.length;
697     int m = seq2.length;
698
699     // top left hand element
700     score[0][0] = lookup[seq1[0]][seq2[0]] * 10;
701     E[0][0] = -gapExtend;
702     F[0][0] = 0;
703
704     // Calculate the top row first
705     for (int j = 1; j < m; j++)
706     {
707       // What should these values be? 0 maybe
708       E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
709       F[0][j] = -gapExtend;
710
711       score[0][j] = max(lookup[seq1[0]][seq2[j]] * 10, -gapOpen, -gapExtend);
712
713       traceback[0][j] = 1;
714     }
715
716     // Now do the left hand column
717     for (int i = 1; i < n; i++)
718     {
719       E[i][0] = -gapOpen;
720       F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
721       
722       score[i][0] = max(lookup[seq1[i]][seq2[0]] * 10, E[i][0], F[i][0]);
723       traceback[i][0] = -1;
724     }
725
726     // Now do all the other rows
727     for (int i = 1; i < n; i++)
728     {
729       for (int j = 1; j < m; j++)
730       {
731         E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
732         F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
733
734         score[i][j] = max(score[i - 1][j - 1]
735                 + (lookup[seq1[i]][seq2[j]] * 10), E[i][j], F[i][j]);
736         traceback[i][j] = findTrace(i, j);
737       }
738     }
739   }
740
741   /**
742    * DOCUMENT ME!
743    * 
744    * @param gapChar
745    *                DOCUMENT ME!
746    * @param seq
747    *                DOCUMENT ME!
748    * 
749    * @return DOCUMENT ME!
750    */
751   public static String extractGaps(String gapChar, String seq)
752   {
753     StringTokenizer str = new StringTokenizer(seq, gapChar);
754     StringBuffer newString = new StringBuffer();
755
756     while (str.hasMoreTokens())
757     {
758       newString.append(str.nextToken());
759     }
760
761     return newString.toString();
762   }
763
764   /**
765    * DOCUMENT ME!
766    * 
767    * @param i1
768    *                DOCUMENT ME!
769    * @param i2
770    *                DOCUMENT ME!
771    * @param i3
772    *                DOCUMENT ME!
773    * 
774    * @return DOCUMENT ME!
775    */
776   public int max(int i1, int i2, int i3)
777   {
778     int max = i1;
779
780     if (i2 > i1)
781     {
782       max = i2;
783     }
784
785     if (i3 > max)
786     {
787       max = i3;
788     }
789
790     return max;
791   }
792
793   /**
794    * DOCUMENT ME!
795    * 
796    * @param i1
797    *                DOCUMENT ME!
798    * @param i2
799    *                DOCUMENT ME!
800    * 
801    * @return DOCUMENT ME!
802    */
803   public int max(int i1, int i2)
804   {
805     int max = i1;
806
807     if (i2 > i1)
808     {
809       max = i2;
810     }
811
812     return max;
813   }
814
815   /**
816    * DOCUMENT ME!
817    * 
818    * @param s
819    *                DOCUMENT ME!
820    * @param type
821    *                DOCUMENT ME!
822    * 
823    * @return DOCUMENT ME!
824    */
825   public int[] stringToInt(String s, String type)
826   {
827     int[] seq1 = new int[s.length()];
828
829     for (int i = 0; i < s.length(); i++)
830     {
831       // String ss = s.substring(i, i + 1).toUpperCase();
832       char c = s.charAt(i);
833       if ('a' <= c && c <= 'z')
834       {
835         // TO UPPERCASE !!!
836         c -= ('a' - 'A');
837       }
838
839       try
840       {
841         seq1[i] = charToInt[c]; // set accordingly from setType
842         if (seq1[i]<0 || seq1[i] > defInt) // set from setType: 23 for peptides, or 4 for NA.
843         {
844           seq1[i] = defInt;
845         }
846       
847       } catch (Exception e)
848       {
849         seq1[i] = defInt;
850       }
851     }
852
853     return seq1;
854   }
855
856   /**
857    * DOCUMENT ME!
858    * 
859    * @param g
860    *                DOCUMENT ME!
861    * @param mat
862    *                DOCUMENT ME!
863    * @param n
864    *                DOCUMENT ME!
865    * @param m
866    *                DOCUMENT ME!
867    * @param psize
868    *                DOCUMENT ME!
869    */
870   public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
871           int psize)
872   {
873     int max = -1000;
874     int min = 1000;
875
876     for (int i = 0; i < n; i++)
877     {
878       for (int j = 0; j < m; j++)
879       {
880         if (mat[i][j] >= max)
881         {
882           max = mat[i][j];
883         }
884
885         if (mat[i][j] <= min)
886         {
887           min = mat[i][j];
888         }
889       }
890     }
891
892     System.out.println(max + " " + min);
893
894     for (int i = 0; i < n; i++)
895     {
896       for (int j = 0; j < m; j++)
897       {
898         int x = psize * i;
899         int y = psize * j;
900
901         // System.out.println(mat[i][j]);
902         float score = (float) (mat[i][j] - min) / (float) (max - min);
903         g.setColor(new Color(score, 0, 0));
904         g.fillRect(x, y, psize, psize);
905
906         // System.out.println(x + " " + y + " " + score);
907       }
908     }
909   }
910 }