normalised logo rendering (JAL-958)
[jalview.git] / src / jalview / analysis / StructureFrequency.java
index 4d83019..aa1e277 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
- * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
+ * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
  * 
  * This file is part of Jalview.
  * 
@@ -15,6 +15,7 @@
  * 
  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  */
+
 package jalview.analysis;
 
 import java.util.*;
@@ -46,143 +47,15 @@ public class StructureFrequency
 
   public static final String PAIRPROFILE = "B";
 
-  public static final Hashtable[] calculate(Vector sequences, int start,
-          int end)
-  {
-    return calculate(sequences, start, end, false);
-  }
-
-  public static final Hashtable[] calculate(Vector sequences, int start,
-          int end, boolean profile)
-  {
-    SequenceI[] seqs = new SequenceI[sequences.size()];
-    int width = 0;
-    for (int i = 0; i < sequences.size(); i++)
-    {
-      seqs[i] = (SequenceI) sequences.elementAt(i);
-      if (seqs[i].getLength() > width)
-      {
-        width = seqs[i].getLength();
-      }
-    }
-
-    Hashtable[] reply = new Hashtable[width];
-
-    if (end >= width)
-    {
-      end = width;
-    }
-
-    calculate(seqs, start, end, reply, profile);
-
-    return reply;
-  }
-
-  public static final void calculate(SequenceI[] sequences, int start,
-          int end, Hashtable[] result)
-  {
-    calculate(sequences, start, end, result, false);
-  }
-
-  public static final void calculate(SequenceI[] sequences, int start,
-          int end, Hashtable[] result, boolean profile)
-  {
-    Hashtable residueHash;
-    int maxCount, nongap, i, j, v, jSize = sequences.length;
-    String maxResidue;
-    char c;
-    float percentage;
-
-    int[] values = new int[255];
-
-    char[] seq;
-
-    for (i = start; i < end; i++)
-    {
-      residueHash = new Hashtable();
-      maxCount = 0;
-      maxResidue = "";
-      nongap = 0;
-      values = new int[255];
-
-      for (j = 0; j < jSize; j++)
-      {
-        if (sequences[j] == null)
-        {
-          System.err
-                  .println("WARNING: Consensus skipping null sequence - possible race condition.");
-          continue;
-        }
-        seq = sequences[j].getSequence();
-        if (seq.length > i)
-        {
-          c = seq[i];
-
-          if (c == '.' || c == ' ')
-          {
-            c = '-';
-          }
-
-          if (c == '-')
-          {
-            values['-']++;
-            continue;
-          }
-          else if ('a' <= c && c <= 'z')
-          {
-            c -= 32; // ('a' - 'A');
-          }
-
-          nongap++;
-          values[c]++;
-
-        }
-        else
-        {
-          values['-']++;
-        }
-      }
-
-      for (v = 'A'; v < 'Z'; v++)
-      {
-        if (values[v] < 2 || values[v] < maxCount)
-        {
-          continue;
-        }
-
-        if (values[v] > maxCount)
-        {
-          maxResidue = String.valueOf((char) v);
-        }
-        else if (values[v] == maxCount)
-        {
-          maxResidue += String.valueOf((char) v);
-        }
-        maxCount = values[v];
-      }
-
-      if (maxResidue.length() == 0)
-      {
-        maxResidue = "-";
-      }
-      if (profile)
-      {
-        residueHash.put(PROFILE, new int[][]
-        { values, new int[]
-        { jSize, nongap } });
-      }
-      residueHash.put(MAXCOUNT, new Integer(maxCount));
-      residueHash.put(MAXRESIDUE, maxResidue);
-
-      percentage = ((float) maxCount * 100) / (float) jSize;
-      residueHash.put(PID_GAPS, new Float(percentage));
-
-      percentage = ((float) maxCount * 100) / (float) nongap;
-      residueHash.put(PID_NOGAPS, new Float(percentage));
-      result[i] = residueHash;
-    }
-  }
-
+  /**
+   * Returns the 3' position of a base pair
+   * 
+   * @param pairs
+   *          Secondary structure annotation
+   * @param indice
+   *          5' position of a base pair
+   * @return 3' position of a base pair
+   */
   public static int findPair(SequenceFeature[] pairs, int indice)
   {
     for (int i = 0; i < pairs.length; i++)
@@ -210,7 +83,6 @@ public class StructureFrequency
           int end, Hashtable[] result, boolean profile,
           AlignmentAnnotation rnaStruc)
   {
-    // System.out.println("StructureFrequency.calculateNEW4");
     Hashtable residueHash;
     String maxResidue;
     char[] seq, struc = rnaStruc.getRNAStruc().toCharArray();
@@ -228,8 +100,14 @@ public class StructureFrequency
       values = new int[255];
       pairs = new int[255][255];
       bpEnd = -1;
-
-      s = struc[i];
+      if (i < struc.length)
+      {
+        s = struc[i];
+      }
+      else
+      {
+        s = '-';
+      }
       if (s == '.' || s == ' ')
       {
         s = '-';
@@ -273,13 +151,11 @@ public class StructureFrequency
             cEnd = seq[bpEnd];
             if (checkBpType(c, cEnd))
             {
-              values['H']++; // H means it's a helix (structured)
+              values['(']++; // H means it's a helix (structured)
             }
-            // System.out.println("pair: "+c+","+cEnd);
             pairs[c][cEnd]++;
-            // System.out.println("pairs: "+c+","+cEnd+" - "+pairs[c][cEnd]);
 
-            maxResidue = "H";
+            maxResidue = "(";
           }
         }
         // nonGap++;
@@ -287,7 +163,6 @@ public class StructureFrequency
       // UPDATE this for new values
       if (profile)
       {
-        // System.out.println("profile");
         residueHash.put(PROFILE, new int[][]
         { values, new int[]
         { jSize, (jSize - values['-']) } });
@@ -295,7 +170,7 @@ public class StructureFrequency
         residueHash.put(PAIRPROFILE, pairs);
       }
 
-      count = values['H'];
+      count = values['('];
 
       residueHash.put(MAXCOUNT, new Integer(count));
       residueHash.put(MAXRESIDUE, maxResidue);
@@ -311,6 +186,27 @@ public class StructureFrequency
       }
       if (bpEnd > 0)
       {
+        values[')'] = values['('];
+        values['('] = 0;
+
+        residueHash = new Hashtable();
+        maxResidue = ")";
+
+        if (profile)
+        {
+          residueHash.put(PROFILE, new int[][]
+          { values, new int[]
+          { jSize, (jSize - values['-']) } });
+
+          residueHash.put(PAIRPROFILE, pairs);
+        }
+
+        residueHash.put(MAXCOUNT, new Integer(count));
+        residueHash.put(MAXRESIDUE, maxResidue);
+
+        percentage = ((float) count * 100) / (float) jSize;
+        residueHash.put(PID_GAPS, new Float(percentage));
+
         result[bpEnd] = residueHash;
       }
     }
@@ -404,19 +300,6 @@ public class StructureFrequency
           boolean ignoreGapsInConsensusCalculation,
           boolean includeAllConsSymbols)
   {
-    completeConsensus(consensus, hconsensus, iStart, width,
-            ignoreGapsInConsensusCalculation, includeAllConsSymbols, null); // new
-    // char[]
-    // { 'A', 'C', 'G', 'T', 'U' });
-  }
-
-  public static void completeConsensus(AlignmentAnnotation consensus,
-          Hashtable[] hconsensus, int iStart, int width,
-          boolean ignoreGapsInConsensusCalculation,
-          boolean includeAllConsSymbols, char[] alphabet)
-  {
-    System.out.println("StructureFrequency.completeConsensus "
-            + includeAllConsSymbols);
     float tval, value;
     if (consensus == null || consensus.annotations == null
             || consensus.annotations.length < width)
@@ -457,52 +340,53 @@ public class StructureFrequency
       }
       int[][] profile = (int[][]) hconsensus[i]
               .get(StructureFrequency.PROFILE);
-      if (profile != null && includeAllConsSymbols) // Just responsible for the
+      int[][] pairs = (int[][]) hconsensus[i]
+              .get(StructureFrequency.PAIRPROFILE);
+
+      if (pairs != null && includeAllConsSymbols) // Just responsible for the
       // tooltip
+      // TODO Update tooltips for Structure row
       {
-        // System.out.println("StructureFrequency.includeAllConsSymbols");
         mouseOver = "";
-        if (alphabet != null)
+
+        /* TODO It's not sure what is the purpose of the alphabet and wheter it is useful for structure?
+         * 
+         * if (alphabet != null) { for (int c = 0; c < alphabet.length; c++) {
+         * tval = ((float) profile[0][alphabet[c]]) 100f / (float)
+         * profile[1][ignoreGapsInConsensusCalculation ? 1 : 0]; mouseOver +=
+         * ((c == 0) ? "" : "; ") + alphabet[c] + " " + ((int) tval) + "%"; } }
+         * else {
+         */
+        Object[] ca = new Object[625];
+        float[] vl = new float[625];
+        int x = 0;
+        for (int c = 65; c < 90; c++)
         {
-          for (int c = 0; c < alphabet.length; c++)
+          for (int d = 65; d < 90; d++)
           {
-            tval = ((float) profile[0][alphabet[c]])
-                    * 100f
-                    / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
-                            : 0];
-            mouseOver += ((c == 0) ? "" : "; ") + alphabet[c] + " "
-                    + ((int) tval) + "%";
+            ca[x] = new int[]
+            { c, d };
+            vl[x] = (float) pairs[c][d];
+            x++;
           }
         }
-        else
+        jalview.util.QuickSort.sort(vl, ca);
+        int p = 0;
+
+        for (int c = 624; c > 0; c--)
         {
-          // System.out.println("StructureFrequency.NOTincludeAllConsSymbols");
-          Object[] ca = new Object[profile[0].length];
-          float[] vl = new float[profile[0].length];
-          for (int c = 0; c < ca.length; c++)
+          if (vl[c] > 0)
           {
-            ca[c] = new char[]
-            { (char) c };
-            vl[c] = (float) profile[0][c];
-          }
-          ;
-          jalview.util.QuickSort.sort(vl, ca);
-          for (int p = 0, c = ca.length - 1; profile[0][((char[]) ca[c])[0]] > 0; c--)
-          {
-            if (((char[]) ca[c])[0] != '-')
-            {
-              tval = ((float) profile[0][((char[]) ca[c])[0]])
-                      * 100f
-                      / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
-                              : 0];
-              mouseOver += ((p == 0) ? "" : "; ") + ((char[]) ca[c])[0]
-                      + " " + ((int) tval) + "%";
-              p++;
+            tval = ((float) vl[c] * 100f / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
+                    : 0]);
+            mouseOver += ((p == 0) ? "" : "; ") + (char) ((int[]) ca[c])[0]
+                    + (char) ((int[]) ca[c])[1] + " " + ((int) tval) + "%";
+            p++;
 
-            }
           }
-
         }
+
+        // }
       }
       else
       {
@@ -514,39 +398,49 @@ public class StructureFrequency
   }
 
   /**
-   * get the sorted profile for the given position of the consensus
+   * get the sorted base-pair profile for the given position of the consensus
    * 
    * @param hconsensus
-   * @return
+   * @return profile of the given column
    */
   public static int[] extractProfile(Hashtable hconsensus,
-          boolean ignoreGapsInConsensusCalculation, int column)
+          boolean ignoreGapsInConsensusCalculation)
   {
-    // TODO is there a more elegant way to acces the column number?
-    /*
-     * calculate the frequence of the 16 bp variations for this column 'somehow'
-     * transfer this via getProfile and let it correctly draw
-     */
-    int[] rtnval = new int[51]; // 2*(5*5)+1
+    int[] rtnval = new int[52]; // 2*(5*5)+2
     int[][] profile = (int[][]) hconsensus.get(StructureFrequency.PROFILE);
     int[][] pairs = (int[][]) hconsensus
             .get(StructureFrequency.PAIRPROFILE);
 
     if (profile == null)
       return null;
-    
-    rtnval[0] = 1;
-    for (int j = 65; j <= 90; j++)
+
+    // TODO fix the object length, also do it in completeConsensus
+    Object[] ca = new Object[625];
+    float[] vl = new float[625];
+    int x = 0;
+    for (int c = 65; c < 90; c++)
     {
-      for (int k = 65; k <= 90; k++)
+      for (int d = 65; d < 90; d++)
       {
-        if (pairs[j][k] > 0)
-        {
-          rtnval[rtnval[0]++] = j;
-          rtnval[rtnval[0]++] = k;
-          rtnval[rtnval[0]++] = (int) ((float) pairs[j][k] * 100f / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
-                  : 0]);
-        }
+        ca[x] = new int[]
+        { c, d };
+        vl[x] = (float) pairs[c][d];
+        x++;
+      }
+    }
+    jalview.util.QuickSort.sort(vl, ca);
+
+    rtnval[0] = 2;
+    rtnval[1] = 0;
+    for (int c = 624; c > 0; c--)
+    {
+      if (vl[c] > 0)
+      {
+        rtnval[rtnval[0]++] = ((int[]) ca[c])[0];
+        rtnval[rtnval[0]++] = ((int[]) ca[c])[1];
+        rtnval[rtnval[0]] = (int) ((float) vl[c] * 100f / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
+                : 0]);
+        rtnval[1]+=rtnval[rtnval[0]++];
       }
     }