experimental: sort by feature UI in feature settings and variable height rendering...
authorjprocter <Jim Procter>
Fri, 19 Dec 2008 15:39:12 +0000 (15:39 +0000)
committerjprocter <Jim Procter>
Fri, 19 Dec 2008 15:39:12 +0000 (15:39 +0000)
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java

index 9eacb6c..b6806e7 100755 (executable)
@@ -43,7 +43,9 @@ public class FeatureRenderer
   AlignViewport av;
 
   Color resBoxColour;
-
+  /**
+   * global transparency for feature
+   */
   float transparency = 1.0f;
 
   FontMetrics fm;
@@ -248,6 +250,11 @@ public class FeatureRenderer
 
   int sfSize, sfindex, spos, epos;
 
+  /**
+   * show scores as heights
+   */
+  protected boolean varyHeight=false;
+
   synchronized public void drawSequence(Graphics g, SequenceI seq,
           int start, int end, int y1)
   {
@@ -366,6 +373,13 @@ public class FeatureRenderer
 
         }
         else
+       if (av.showSeqFeaturesHeight && sequenceFeatures[sfindex].score!=Float.NaN)
+        {
+         renderScoreFeature(g, seq, seq
+                 .findIndex(sequenceFeatures[sfindex].begin) - 1, seq
+                 .findIndex(sequenceFeatures[sfindex].end) - 1,
+                 getColour(sequenceFeatures[sfindex].type), start, end, y1, normaliseScore(sequenceFeatures[sfindex]));
+        } else
         {
           renderFeature(g, seq, seq
                   .findIndex(sequenceFeatures[sfindex].begin) - 1, seq
@@ -384,6 +398,28 @@ public class FeatureRenderer
               1.0f));
     }
   }
+  Hashtable minmax = new Hashtable();
+  /**
+   * normalise a score against the max/min bounds for the feature type.
+   * @param sequenceFeature
+   * @return byte[] { signed, normalised signed (-127 to 127) or unsigned (0-255) value.
+   */
+  private final byte[] normaliseScore(SequenceFeature sequenceFeature)
+  {
+    float[] mm = (float[]) minmax.get(sequenceFeature.type);
+    final byte[] r=new byte[] { 0, (byte) 255};
+    if (mm!=null)
+    {
+      if (r[0]!=0 || mm[0]<0.0)
+      {
+        r[0]=1;
+        r[1]=(byte) ((int) 128.0+127.0*(sequenceFeature.score/mm[1]));
+      } else {
+        r[1]=(byte) ((int) 255.0*(sequenceFeature.score/mm[1]));
+      }
+    }
+    return r;
+  }
 
   char s;
 
@@ -432,6 +468,67 @@ public class FeatureRenderer
       }
     }
   }
+  void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend,
+          Color featureColour, int start, int end, int y1, byte[] bs)
+  {
+
+    if (((fstart <= end) && (fend >= start)))
+    {
+      if (fstart < start)
+      { // fix for if the feature we have starts before the sequence start,
+        fstart = start; // but the feature end is still valid!!
+      }
+
+      if (fend >= end)
+      {
+        fend = end;
+      }
+      int pady = (y1 + av.charHeight) - av.charHeight / 5;
+      int ystrt = 0,yend=av.charHeight;
+      if (bs[0]!=0)
+      {
+        // signed - zero is always middle of residue line.
+        if (bs[1]<128)
+        {
+          yend = av.charHeight*(128-bs[1])/512;
+          ystrt = av.charHeight-yend/2;
+        } else {
+          ystrt = av.charHeight/2;
+          yend = av.charHeight*(bs[1]-128)/512;
+        }
+      } else {
+        yend = av.charHeight*bs[1]/255;
+        ystrt = av.charHeight-yend;
+
+      }
+      for (i = fstart; i <= fend; i++)
+      {
+        s = seq.getCharAt(i);
+
+        if (jalview.util.Comparison.isGap(s))
+        {
+          continue;
+        }
+
+        g.setColor(featureColour);
+        int x=(i-start)*av.charWidth;
+        g.drawRect(x, y1, av.charWidth, av.charHeight);
+        g.fillRect(x, y1+ystrt, av.charWidth,
+                yend);
+
+        if (offscreenRender || !av.validCharWidth)
+        {
+          continue;
+        }
+
+        g.setColor(Color.black);
+        charOffset = (av.charWidth - fm.charWidth(s)) / 2;
+        g.drawString(String.valueOf(s), charOffset
+                + (av.charWidth * (i - start)), pady);
+
+      }
+    }
+  }
 
   boolean newFeatureAdded = false;
 
@@ -503,6 +600,10 @@ public class FeatureRenderer
         }
       }
     }
+    if (minmax==null)
+    {
+      minmax = new Hashtable();
+    }
     for (int i = 0; i < av.alignment.getHeight(); i++)
     {
       SequenceFeature[] features = av.alignment.getSequenceAt(i)
@@ -552,6 +653,24 @@ public class FeatureRenderer
         {
           allfeatures.addElement(features[index].getType());
         }
+        if (features[index].score!=Float.NaN)
+        { 
+          float[] mm = (float[]) minmax.get(features[index].getType());
+          if (mm==null)
+          {
+            mm = new float[] { features[index].score,features[index].score};
+            minmax.put(features[index].getType(), mm);
+          } else {
+            if (mm[0]>features[index].score)
+            {
+              mm[0] = features[index].score;
+            }
+            if (mm[1]<features[index].score)
+            {
+              mm[1] = features[index].score;
+            }
+          }
+        }
         index++;
       }
     }
index 0b645f2..db93724 100755 (executable)
@@ -94,7 +94,8 @@ public class FeatureSettings extends JPanel
         selectedRow = table.rowAtPoint(evt.getPoint());
         if (javax.swing.SwingUtilities.isRightMouseButton(evt))
         {
-          popupSort((String)table.getValueAt(selectedRow, 0), evt.getX(), evt.getY());
+          popupSort((String) table.getValueAt(selectedRow, 0), fr.minmax,
+                  evt.getX(), evt.getY());
         }
       }
     });
@@ -146,7 +147,7 @@ public class FeatureSettings extends JPanel
         {
           fs.handlingUpdate = true;
           fs.resetTable(null); // new groups may be added with new seuqence
-                                // feature types only
+          // feature types only
           fs.handlingUpdate = false;
         }
       }
@@ -168,31 +169,59 @@ public class FeatureSettings extends JPanel
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
   }
 
-  protected void popupSort(final String type, int x, int y)
+  protected void popupSort(final String type, final Hashtable minmax,
+          int x, int y)
   {
-    JPopupMenu men = new JPopupMenu();
-    men.setName("Sort by "+type);
-    JMenuItem scr = new JMenuItem("Score");
+    JPopupMenu men = new JPopupMenu("Settings for " + type);
+    JMenuItem scr = new JMenuItem("Sort by Score");
     men.add(scr);
-    final FeatureSettings me=this;
-    scr.addActionListener(new ActionListener() {
+    final FeatureSettings me = this;
+    scr.addActionListener(new ActionListener()
+    {
 
       public void actionPerformed(ActionEvent e)
       {
-        me.sortByScore(new String[] {type});
+        me.sortByScore(new String[]
+        { type });
       }
-      
+
     });
-    JMenuItem dens = new JMenuItem("Density");
-    dens.addActionListener(new ActionListener() {
+    JMenuItem dens = new JMenuItem("Sort by Density");
+    dens.addActionListener(new ActionListener()
+    {
 
       public void actionPerformed(ActionEvent e)
       {
-        me.sortByDens(new String[] { type });
+        me.sortByDens(new String[]
+        { type });
       }
-      
+
     });
     men.add(dens);
+    if (minmax != null)
+    {
+      final Object typeMinMax = minmax.get(type);
+      final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height");
+      chb.setSelected(minmax.get(type) != null);
+      chb.addActionListener(new ActionListener()
+      {
+
+        public void actionPerformed(ActionEvent e)
+        {
+          chb.setState(chb.getState());
+          if (chb.getState())
+          {
+            minmax.put(type, null);
+          }
+          else
+          {
+            minmax.put(type, typeMinMax);
+          }
+        }
+
+      });
+      men.add(chb);
+    }
     men.show(table, x, y);
   }
 
@@ -409,8 +438,8 @@ public class FeatureSettings extends JPanel
     {
       if (!handlingUpdate)
         fr.findAllFeatures(groupChanged != null); // prod to update
-                                                  // colourschemes. but don't
-                                                  // affect display
+      // colourschemes. but don't
+      // affect display
       // First add the checks in the previous render order,
       // in case the window has been closed and reopened
       for (int ro = fr.renderOrder.length - 1; ro > -1; ro--)
@@ -617,8 +646,8 @@ public class FeatureSettings extends JPanel
       if (awidth[0] > 0)
       {
         width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
-                                          // weight - but have to make per
-                                          // sequence, too (awidth[2])
+        // weight - but have to make per
+        // sequence, too (awidth[2])
         // if (width[i]==1) // hack to distinguish single width sequences.
         num++;
       }
@@ -714,7 +743,9 @@ public class FeatureSettings extends JPanel
   JButton cancelDAS = new JButton();
 
   JButton optimizeOrder = new JButton();
+
   JButton sortByScore = new JButton();
+
   JButton sortByDens = new JButton();
 
   JPanel transbuttons = new JPanel(new BorderLayout());
@@ -760,7 +791,8 @@ public class FeatureSettings extends JPanel
       {
         sortByDens(null);
       }
-    });    cancel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
+    });
+    cancel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
     cancel.setText("Cancel");
     cancel.addActionListener(new ActionListener()
     {
@@ -861,48 +893,51 @@ public class FeatureSettings extends JPanel
   {
     sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
   }
-  protected void sortBy(String[] typ, String methodText, final String method) {
-    if (typ==null)
+
+  protected void sortBy(String[] typ, String methodText, final String method)
+  {
+    if (typ == null)
     {
       typ = getDisplayedFeatureTypes();
     }
-    String gps[]=null;
+    String gps[] = null;
     gps = getDisplayedFeatureGroups();
-    if (typ!=null)
+    if (typ != null)
     {
-      for (int i=0;i<typ.length; i++)
+      for (int i = 0; i < typ.length; i++)
       {
-        System.err.println("Sorting on Types:"+typ[i]);
+        System.err.println("Sorting on Types:" + typ[i]);
       }
     }
-    if (gps!=null)
+    if (gps != null)
     {
-      
-      for (int i=0;i<gps.length; i++)
+
+      for (int i = 0; i < gps.length; i++)
       {
-        System.err.println("Sorting on groups:"+gps[i]);
+        System.err.println("Sorting on groups:" + gps[i]);
       }
     }
     AlignmentPanel alignPanel = af.alignPanel;
     AlignmentI al = alignPanel.av.getAlignment();
 
-    int start,stop;
+    int start, stop;
     SequenceGroup sg = alignPanel.av.getSelectionGroup();
-    if (sg!=null)
+    if (sg != null)
     {
       start = sg.getStartRes();
       stop = sg.getEndRes();
-    } else {
+    }
+    else
+    {
       start = 0;
       stop = al.getWidth();
     }
     SequenceI[] oldOrder = al.getSequencesArray();
-    AlignmentSorter.sortByFeature(typ, gps, start, stop,
-            al, method);
-    af.addHistoryItem(new OrderCommand(methodText, oldOrder,
-            alignPanel.av.getAlignment()));
+    AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
+    af.addHistoryItem(new OrderCommand(methodText, oldOrder, alignPanel.av
+            .getAlignment()));
     alignPanel.paintAlignment(true);
-    
+
   }
 
   protected void sortByScore(String[] typ)
@@ -912,15 +947,16 @@ public class FeatureSettings extends JPanel
 
   private String[] getDisplayedFeatureTypes()
   {
-    String[] typ=null;
-    if (fr!=null)
+    String[] typ = null;
+    if (fr != null)
     {
-      synchronized (fr.renderOrder) {
+      synchronized (fr.renderOrder)
+      {
         typ = new String[fr.renderOrder.length];
         System.arraycopy(fr.renderOrder, 0, typ, 0, typ.length);
-        for (int i=0;i<typ.length;i++)
+        for (int i = 0; i < typ.length; i++)
         {
-          if (af.viewport.featuresDisplayed.get(typ[i])==null)
+          if (af.viewport.featuresDisplayed.get(typ[i]) == null)
           {
             typ[i] = null;
           }
@@ -932,27 +968,27 @@ public class FeatureSettings extends JPanel
 
   private String[] getDisplayedFeatureGroups()
   {
-    String[] gps=null;
-    if (fr!=null)
+    String[] gps = null;
+    if (fr != null)
     {
-      
-      if (fr.featureGroups!=null)
+
+      if (fr.featureGroups != null)
       {
         Enumeration en = fr.featureGroups.keys();
         gps = new String[fr.featureColours.size()];
-        int g=0;
-        boolean valid=false;
+        int g = 0;
+        boolean valid = false;
         while (en.hasMoreElements())
         {
           String gp = (String) en.nextElement();
-          Boolean on = (Boolean )fr.featureGroups.get(gp);
-          if (on!=null && on.booleanValue())
+          Boolean on = (Boolean) fr.featureGroups.get(gp);
+          if (on != null && on.booleanValue())
           {
             valid = true;
             gps[g++] = gp;
           }
         }
-        while (g<gps.length)
+        while (g < gps.length)
         {
           gps[g++] = null;
         }
@@ -1019,23 +1055,31 @@ public class FeatureSettings extends JPanel
   {
     dassourceBrowser.initDasSources();
   }
+
   /**
-   * examine the current list of das sources and return any matching the given nicknames in sources 
-   * @param sources Vector of Strings to resolve to DAS source nicknames.
+   * examine the current list of das sources and return any matching the given
+   * nicknames in sources
+   * 
+   * @param sources
+   *                Vector of Strings to resolve to DAS source nicknames.
    * @return sources that are present in source list.
    */
   public Vector resolveSourceNicknames(Vector sources)
   {
     return dassourceBrowser.resolveSourceNicknames(sources);
   }
+
   /**
-   * get currently selected das sources. ensure you have called initDasSources before calling this.
+   * get currently selected das sources. ensure you have called initDasSources
+   * before calling this.
+   * 
    * @return vector of selected das source nicknames
    */
   public Vector getSelectedSources()
   {
     return dassourceBrowser.getSelectedSources();
   }
+
   /**
    * properly initialise DAS fetcher and then initiate a new thread to fetch
    * features from the named sources (rather than any turned on by default)