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