Merge branch 'alpha/JAL-3362_Jalview_212_alpha' into alpha/merge_212_JalviewJS_2112
[jalview.git] / src / jalview / renderer / AnnotationRenderer.java
index 68dbe4f..70991c6 100644 (file)
@@ -25,17 +25,18 @@ import jalview.analysis.CodingUtils;
 import jalview.analysis.Rna;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
-import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.ProfilesI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.ZappoColourScheme;
 import jalview.util.Platform;
+import jalview.workers.InformationThread;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
@@ -68,10 +69,16 @@ public class AnnotationRenderer
 
   private FontMetrics fm;
 
-  private final boolean USE_FILL_ROUND_RECT = Platform.isAMac();
+  private final boolean USE_FILL_ROUND_RECT = Platform.isAMacAndNotJS();
 
-  boolean av_renderHistogram = true, av_renderProfile = true,
-          av_normaliseProfile = false;
+  // todo remove these flags, read from group/viewport where needed
+  boolean av_renderHistogram = true;
+
+  boolean av_renderProfile = true;
+
+  boolean av_normaliseProfile = false;
+
+  boolean av_infoHeight = false;
 
   ResidueShaderI profcolour = null;
 
@@ -81,12 +88,14 @@ public class AnnotationRenderer
 
   private ProfilesI hconsensus;
 
-  private Hashtable[] complementConsensus;
+  private Hashtable<String, Object>[] complementConsensus;
 
-  private Hashtable[] hStrucConsensus;
+  private Hashtable<String, Object>[] hStrucConsensus;
 
   private boolean av_ignoreGapsConsensus;
 
+  private boolean av_ignoreBelowBackground;
+
   /**
    * attributes set from AwtRenderPanelI
    */
@@ -345,8 +354,12 @@ public class AnnotationRenderer
     complementConsensus = av.getComplementConsensusHash();
     hStrucConsensus = av.getRnaStructureConsensusHash();
     av_ignoreGapsConsensus = av.isIgnoreGapsConsensus();
+    av_ignoreBelowBackground = av.isIgnoreBelowBackground();
+    av_infoHeight = av.isInfoLetterHeight();
   }
 
+
+
   /**
    * Returns profile data; the first element is the profile type, the second is
    * the number of distinct values, the third the total count, and the remainder
@@ -362,17 +375,25 @@ public class AnnotationRenderer
     // properties/rendering attributes as a global 'alignment group' which holds
     // all vis settings for the alignment as a whole rather than a subset
     //
-    if (aa.autoCalculated && (aa.label.startsWith("Consensus")
-            || aa.label.startsWith("cDNA Consensus")))
+    if (InformationThread.HMM_CALC_ID.equals(aa.getCalcId()))
+    {
+      HiddenMarkovModel hmm = aa.sequenceRef.getHMM();
+      return AAFrequency.extractHMMProfile(hmm, column,
+              av_ignoreBelowBackground, av_infoHeight); // TODO check if this follows standard
+                                         // pipeline
+    }
+    if (aa.autoCalculated
+            && (aa.label.startsWith("Consensus") || aa.label
+                    .startsWith("cDNA Consensus")))
     {
       boolean forComplement = aa.label.startsWith("cDNA Consensus");
-      if (aa.groupRef != null && aa.groupRef.consensusData != null
+      if (aa.groupRef != null && aa.groupRef.getConsensusData() != null
               && aa.groupRef.isShowSequenceLogo())
       {
         // TODO? group consensus for cDNA complement
         return AAFrequency.extractProfile(
-                aa.groupRef.consensusData.get(column),
-                aa.groupRef.getIgnoreGapsConsensus());
+                aa.groupRef.getConsensusData().get(column),
+                                               aa.groupRef.getIgnoreGapsConsensus());
       }
       // TODO extend annotation row to enable dynamic and static profile data to
       // be stored
@@ -417,8 +438,6 @@ public class AnnotationRenderer
     return null;
   }
 
-  boolean rna = false;
-
   /**
    * Render the annotation rows associated with an alignment.
    * 
@@ -449,7 +468,7 @@ public class AnnotationRenderer
     updateFromAwtRenderPanel(annotPanel, av);
     fm = g.getFontMetrics();
     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
-    int temp = 0;
+    // int temp = 0;
     if (aa == null)
     {
       return false;
@@ -462,8 +481,8 @@ public class AnnotationRenderer
     boolean validRes = false;
     boolean validEnd = false;
     boolean labelAllCols = false;
-    boolean centreColLabels;
-    boolean centreColLabelsDef = av.isCentreColumnLabels();
+//    boolean centreColLabels;
+//    boolean centreColLabelsDef = av.isCentreColumnLabels();
     boolean scaleColLabel = false;
     final AlignmentAnnotation consensusAnnot = av
             .getAlignmentConsensusAnnotation();
@@ -471,8 +490,6 @@ public class AnnotationRenderer
             .getAlignmentStrucConsensusAnnotation();
     final AlignmentAnnotation complementConsensusAnnot = av
             .getComplementConsensusAnnotation();
-    boolean renderHistogram = true, renderProfile = true,
-            normaliseProfile = false, isRNA = rna;
 
     BitSet graphGroupDrawn = new BitSet();
     int charOffset = 0; // offset for a label
@@ -483,38 +500,57 @@ public class AnnotationRenderer
     for (int i = 0; i < aa.length; i++)
     {
       AlignmentAnnotation row = aa[i];
-      isRNA = row.isRNA();
+      boolean renderHistogram = true;
+      boolean renderProfile = false;
+      boolean normaliseProfile = false;
+      boolean isRNA = row.isRNA();
+
+      // check if this is a consensus annotation row and set the display
+      // settings appropriately
+      // TODO: generalise this to have render styles for consensus/profile
+      // data
+      if (row.groupRef != null && row == row.groupRef.getConsensus())
       {
-        // check if this is a consensus annotation row and set the display
-        // settings appropriately
-        // TODO: generalise this to have render styles for consensus/profile
-        // data
-        if (row.groupRef != null && row == row.groupRef.getConsensus())
-        {
-          renderHistogram = row.groupRef.isShowConsensusHistogram();
-          renderProfile = row.groupRef.isShowSequenceLogo();
-          normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
-        }
-        else if (row == consensusAnnot || row == structConsensusAnnot
-                || row == complementConsensusAnnot)
+        renderHistogram = row.groupRef.isShowConsensusHistogram();
+        renderProfile = row.groupRef.isShowSequenceLogo();
+        normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
+      }
+      else if (row == consensusAnnot || row == structConsensusAnnot
+              || row == complementConsensusAnnot)
+      {
+        renderHistogram = av_renderHistogram;
+        renderProfile = av_renderProfile;
+        normaliseProfile = av_normaliseProfile;
+      }
+      else if (InformationThread.HMM_CALC_ID.equals(row.getCalcId()))
+      {
+        if (row.groupRef != null)
         {
-          renderHistogram = av_renderHistogram;
-          renderProfile = av_renderProfile;
-          normaliseProfile = av_normaliseProfile;
+          renderHistogram = row.groupRef.isShowInformationHistogram();
+          renderProfile = row.groupRef.isShowHMMSequenceLogo();
+          normaliseProfile = row.groupRef.isNormaliseHMMSequenceLogo();
         }
         else
         {
-          renderHistogram = true;
-          // don't need to set render/normaliseProfile since they are not
-          // currently used in any other annotation track renderer
+          renderHistogram = av.isShowInformationHistogram();
+          renderProfile = av.isShowHMMSequenceLogo();
+          normaliseProfile = av.isNormaliseHMMSequenceLogo();
         }
       }
+      else if (row == consensusAnnot || row == structConsensusAnnot
+              || row == complementConsensusAnnot)
+      {
+        renderHistogram = av_renderHistogram;
+        renderProfile = av_renderProfile;
+        normaliseProfile = av_normaliseProfile;
+      }
+
       Annotation[] row_annotations = row.annotations;
       if (!row.visible)
       {
         continue;
       }
-      centreColLabels = row.centreColLabels || centreColLabelsDef;
+//      centreColLabels = row.centreColLabels || centreColLabelsDef;
       labelAllCols = row.showAllColLabels;
       scaleColLabel = row.scaleColLabel;
       lastSS = ' ';
@@ -782,7 +818,7 @@ public class AnnotationRenderer
               if (x > -1)
               {
 
-                int nb_annot = x - temp;
+                // int nb_annot = x - temp;
                 // System.out.println("\t type :"+lastSS+"\t x :"+x+"\t nbre
                 // annot :"+nb_annot);
                 switch (lastSS)
@@ -791,7 +827,7 @@ public class AnnotationRenderer
                 case ')': // and opposite direction
                   drawStemAnnot(g, row_annotations, lastSSX, x, y,
                           iconOffset, startRes, column, validRes, validEnd);
-                  temp = x;
+                  // temp = x;
                   break;
 
                 case 'H':
@@ -874,13 +910,13 @@ public class AnnotationRenderer
                   drawNotCanonicalAnnot(g, nonCanColor, row_annotations,
                           lastSSX, x, y, iconOffset, startRes, column,
                           validRes, validEnd);
-                  temp = x;
+                  // temp = x;
                   break;
                 default:
                   g.setColor(Color.gray);
                   g.fillRect(lastSSX, y + 6 + iconOffset,
                           (x * charWidth) - lastSSX, 2);
-                  temp = x;
+                  // temp = x;
                   break;
                 }
               }
@@ -1121,7 +1157,7 @@ public class AnnotationRenderer
 
   public static final Color STEM_COLOUR = Color.blue;
 
-  private Color sdNOTCANONICAL_COLOUR;
+  // private Color sdNOTCANONICAL_COLOUR;
 
   void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x,
           int y, int iconOffset, int startRes, int column, boolean validRes,
@@ -1397,7 +1433,8 @@ public class AnnotationRenderer
           boolean isStructureProfile = profl[0] == AlignmentAnnotation.STRUCTURE_PROFILE;
           boolean isCdnaProfile = profl[0] == AlignmentAnnotation.CDNA_PROFILE;
           float ht = normaliseProfile ? y - _aa.graphHeight : y1;
-          final double normaliseFactor = normaliseProfile ? _aa.graphHeight : (y2 - y1);
+          final double normaliseFactor = normaliseProfile ? _aa.graphHeight
+                  : (y2 - y1);
 
           /**
            * Render a single base for a sequence profile, a base pair for
@@ -1448,8 +1485,14 @@ public class AnnotationRenderer
               s = new String(dc);
             }
             // next profl[] position is profile % for the character(s)
-            
-            double newHeight = normaliseFactor * scale * profl[c++];
+
+            int percent = profl[c++];
+            if (percent == 0)
+            {
+              // failsafe in case a count rounds down to 0%
+              continue;
+            }
+            double newHeight = normaliseFactor * scale * percent;
 
             /*
              * Set character colour as per alignment colour scheme; use the
@@ -1475,9 +1518,9 @@ public class AnnotationRenderer
             // (int)(scl));
             // g.setColor(profcolour.findColour(dc[0]).darker());
 
-            double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length);            
+            double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length);
             double sy = newHeight / asc;
-            double newAsc = asc * sy; 
+            double newAsc = asc * sy;
             double newDec = dec * sy;
             // it is not necessary to recalculate lm for the new font.
             // note: lm.getBaselineOffsets()[lm.getBaselineIndex()]) must be 0
@@ -1485,7 +1528,7 @@ public class AnnotationRenderer
             // int hght = (int) (ht + (newAsc - newDec);
             // - lm.getBaselineOffsets()[lm.getBaselineIndex()]));
 
-            if (Jalview.isJS())
+            if (Platform.isJS())
             {
               /*
                * SwingJS does not implement font.deriveFont()
@@ -1503,10 +1546,14 @@ public class AnnotationRenderer
               ht2 += newHeight;
             }
             else
+            /**
+             * Java only
+             * 
+             * @j2sIgnore
+             */
             {
-              /*
-               * Java ('normal') method is to scale the font to fit
-               */
+              // Java ('normal') method is to scale the font to fit
+
               final int hght = (int) (ht + (newAsc - newDec));
               Font font = ofont
                       .deriveFont(AffineTransform.getScaleInstance(sx, sy));
@@ -1525,7 +1572,7 @@ public class AnnotationRenderer
       Graphics2D g2 = (Graphics2D) g;
       g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
               BasicStroke.JOIN_ROUND, 3f, new float[]
-      { 5f, 3f }, 0f));
+              { 5f, 3f }, 0f));
 
       y2 = (int) (y
               - ((_aa.threshold.value - min) / range) * _aa.graphHeight);