Merge branch 'releases/Release_2_10_4_Branch' into develop
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 18 Apr 2018 11:41:08 +0000 (12:41 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 18 Apr 2018 11:41:08 +0000 (12:41 +0100)
Conflicts:
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
test/jalview/renderer/seqfeatures/FeatureRendererTest.java

1  2 
src/jalview/appletgui/OverviewCanvas.java
src/jalview/gui/OverviewCanvas.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
test/jalview/renderer/seqfeatures/FeatureRendererTest.java

@@@ -128,10 -128,10 +128,9 @@@ public class OverviewCanvas extends Com
      {
        mg.translate(0, od.getSequencesHeight());
        or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-               av.getCharWidth(), od.getGraphHeight(),
-               od.getColumns(av.getAlignment()));
+               od.getGraphHeight(), od.getColumns(av.getAlignment()));
        mg.translate(0, -od.getSequencesHeight());
      }
 -    System.gc();
  
      if (restart)
      {
@@@ -157,10 -157,10 +157,9 @@@ public class OverviewCanvas extends JCo
      {
        mg.translate(0, od.getSequencesHeight());
        or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-               av.getCharWidth(), od.getGraphHeight(),
-               od.getColumns(av.getAlignment()));
+               od.getGraphHeight(), od.getColumns(av.getAlignment()));
        mg.translate(0, -od.getSequencesHeight());
      }
 -    System.gc();
  
      or.removePropertyChangeListener(progressPanel);
      or = null;
@@@ -1029,20 -995,25 +1029,28 @@@ public abstract class FeatureRendererMo
    }
  
    /**
 -   * Removes from the list of features any that have a feature group that is not
 -   * displayed, or duplicate the location of a feature of the same type (unless
 -   * a graduated colour scheme or colour by label is applied). Should be used
 -   * only for features of the same feature colour (which normally implies the
 -   * same feature type).
 +   * Removes from the list of features any that duplicate the location of a
 +   * feature of the same type. Should be used only for features of the same,
 +   * simple, feature colour (which normally implies the same feature type). Does
-    * not check visibility settings for feature type or feature group.
++   * not check visibility settings for feature type or feature group. No
++   * filtering is done if transparency, or any feature filters, are in force.
     * 
     * @param features
 -   * @param fc
     */
 -  public void filterFeaturesForDisplay(List<SequenceFeature> features,
 -          FeatureColourI fc)
 +  public void filterFeaturesForDisplay(List<SequenceFeature> features)
    {
--    if (features.isEmpty())
++    /*
++     * don't remove 'redundant' features if 
++     * - transparency is applied (feature count affects depth of feature colour)
++     * - filters are applied (not all features may be displayable)
++     */
++    if (features.isEmpty() || transparency != 1f
++            || !featureFilters.isEmpty())
      {
        return;
      }
      SequenceFeatures.sortFeatures(features, true);
 -    boolean simpleColour = fc == null || fc.isSimpleColour();
      SequenceFeature lastFeature = null;
  
      Iterator<SequenceFeature> it = features.iterator();
@@@ -354,157 -314,56 +354,165 @@@ public class FeatureRendererTes
      assertEquals(features.size(), 3);
      assertTrue(features.contains(sf1) || features.contains(sf4));
      assertFalse(features.contains(sf1) && features.contains(sf4));
 -    assertTrue(features.contains(sf2));
 -    assertFalse(features.contains(sf3));
 +    assertTrue(features.contains(sf2) || features.contains(sf3));
 +    assertFalse(features.contains(sf2) && features.contains(sf3));
      assertTrue(features.contains(sf5));
+     /*
 -     * hide group 2, show group 3 - sf2 is removed, sf3 is retained
++     * no filtering if transparency is applied
+      */
 -    fr.setGroupVisibility("group2", false);
 -    fr.setGroupVisibility("group3", true);
++    fr.setTransparency(0.5f);
+     features = seq.getSequenceFeatures();
 -    fr.filterFeaturesForDisplay(features, null);
 -    assertEquals(features.size(), 3);
 -    assertTrue(features.contains(sf1) || features.contains(sf4));
 -    assertFalse(features.contains(sf1) && features.contains(sf4));
 -    assertFalse(features.contains(sf2));
 -    assertTrue(features.contains(sf3));
 -    assertTrue(features.contains(sf5));
++    fr.filterFeaturesForDisplay(features);
++    assertEquals(features.size(), 5);
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testGetColour()
 +  {
 +    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(">s1\nABCD\n",
 +            DataSourceType.PASTE);
 +    AlignViewportI av = af.getViewport();
 +    FeatureRenderer fr = new FeatureRenderer(av);
  
      /*
 -     * no filtering of co-located features with graduated colour scheme
 -     * filterFeaturesForDisplay does _not_ check colour threshold
 -     * sf2 is removed as its group is hidden
 +     * simple colour, feature type and group displayed
       */
 -    features = seq.getSequenceFeatures();
 -    fr.filterFeaturesForDisplay(features, new FeatureColour(Color.black,
 -            Color.white, 0f, 1f));
 -    assertEquals(features.size(), 4);
 -    assertFalse(features.contains(sf2));
 +    FeatureColourI fc = new FeatureColour(Color.red);
 +    fr.getFeatureColours().put("Cath", fc);
 +    SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
 +            "group1");
 +    assertEquals(fr.getColour(sf1), Color.red);
  
      /*
 -     * co-located features with colour by label
 -     * should not get filtered
 +     * hide feature type, then unhide
 +     * - feature type visibility should not affect the result
       */
 -    features = seq.getSequenceFeatures();
 -    FeatureColour fc = new FeatureColour(Color.black);
 -    fc.setColourByLabel(true);
 -    fr.filterFeaturesForDisplay(features, fc);
 -    assertEquals(features.size(), 4);
 -    assertTrue(features.contains(sf1));
 -    assertTrue(features.contains(sf3));
 -    assertTrue(features.contains(sf4));
 -    assertTrue(features.contains(sf5));
 +    FeatureSettingsBean[] data = new FeatureSettingsBean[1];
 +    data[0] = new FeatureSettingsBean("Cath", fc, null, false);
 +    fr.setFeaturePriority(data);
 +    assertEquals(fr.getColour(sf1), Color.red);
 +    data[0] = new FeatureSettingsBean("Cath", fc, null, true);
 +    fr.setFeaturePriority(data);
 +    assertEquals(fr.getColour(sf1), Color.red);
  
      /*
 -     * no filtering if transparency is applied
 +     * hide feature group, then unhide
       */
 -    fr.setTransparency(0.5f);
 -    features = seq.getSequenceFeatures();
 -    fr.setGroupVisibility("group2", true);
 -    fr.filterFeaturesForDisplay(features, new FeatureColour(Color.RED));
 -    assertEquals(features.size(), 5);
 +    fr.setGroupVisibility("group1", false);
 +    assertNull(fr.getColour(sf1));
 +    fr.setGroupVisibility("group1", true);
 +    assertEquals(fr.getColour(sf1), Color.red);
 +
 +    /*
 +     * graduated colour by score, no threshold, no score
 +     * 
 +     */
 +    FeatureColourI gc = new FeatureColour(Color.yellow, Color.red,
 +            Color.green, 1f, 11f);
 +    fr.getFeatureColours().put("Cath", gc);
 +    assertEquals(fr.getColour(sf1), Color.green);
 +
 +    /*
 +     * graduated colour by score, no threshold, with score value
 +     */
 +    SequenceFeature sf2 = new SequenceFeature("Cath", "", 6, 8, 6f,
 +            "group1");
 +    // score 6 is half way from yellow(255, 255, 0) to red(255, 0, 0)
 +    Color expected = new Color(255, 128, 0);
 +    assertEquals(fr.getColour(sf2), expected);
 +
 +    /*
 +     * above threshold, score is above threshold - no change
 +     */
 +    gc.setAboveThreshold(true);
 +    gc.setThreshold(5f);
 +    assertEquals(fr.getColour(sf2), expected);
 +
 +    /*
 +     * threshold is min-max; now score 6 is 1/6 of the way from 5 to 11
 +     * or from yellow(255, 255, 0) to red(255, 0, 0)
 +     */
 +    gc = new FeatureColour(Color.yellow, Color.red, Color.green, 5f, 11f);
 +    fr.getFeatureColours().put("Cath", gc);
 +    gc.setAutoScaled(false); // this does little other than save a checkbox setting!
 +    assertEquals(fr.getColour(sf2), new Color(255, 213, 0));
 +
 +    /*
 +     * feature score is below threshold - no colour
 +     */
 +    gc.setAboveThreshold(true);
 +    gc.setThreshold(7f);
 +    assertNull(fr.getColour(sf2));
 +
 +    /*
 +     * feature score is above threshold - no colour
 +     */
 +    gc.setBelowThreshold(true);
 +    gc.setThreshold(3f);
 +    assertNull(fr.getColour(sf2));
 +
 +    /*
 +     * colour by feature attribute value
 +     * first with no value held
 +     */
 +    gc = new FeatureColour(Color.yellow, Color.red, Color.green, 1f, 11f);
 +    fr.getFeatureColours().put("Cath", gc);
 +    gc.setAttributeName("AF");
 +    assertEquals(fr.getColour(sf2), Color.green);
 +
 +    // with non-numeric attribute value
 +    sf2.setValue("AF", "Five");
 +    assertEquals(fr.getColour(sf2), Color.green);
 +
 +    // with numeric attribute value
 +    sf2.setValue("AF", "6");
 +    assertEquals(fr.getColour(sf2), expected);
 +
 +    // with numeric value outwith threshold
 +    gc.setAboveThreshold(true);
 +    gc.setThreshold(10f);
 +    assertNull(fr.getColour(sf2));
 +
 +    // with filter on AF < 4
 +    gc.setAboveThreshold(false);
 +    assertEquals(fr.getColour(sf2), expected);
 +    FeatureMatcherSetI filter = new FeatureMatcherSet();
 +    filter.and(FeatureMatcher.byAttribute(Condition.LT, "4.0", "AF"));
 +    fr.setFeatureFilter("Cath", filter);
 +    assertNull(fr.getColour(sf2));
 +
 +    // with filter on 'Consequence contains missense'
 +    filter = new FeatureMatcherSet();
 +    filter.and(FeatureMatcher.byAttribute(Condition.Contains, "missense",
 +            "Consequence"));
 +    fr.setFeatureFilter("Cath", filter);
 +    // if feature has no Consequence attribute, no colour
 +    assertNull(fr.getColour(sf2));
 +    // if attribute does not match filter, no colour
 +    sf2.setValue("Consequence", "Synonymous");
 +    assertNull(fr.getColour(sf2));
 +    // attribute matches filter
 +    sf2.setValue("Consequence", "Missense variant");
 +    assertEquals(fr.getColour(sf2), expected);
 +
 +    // with filter on CSQ:Feature contains "ENST01234"
 +    filter = new FeatureMatcherSet();
 +    filter.and(FeatureMatcher.byAttribute(Condition.Matches, "ENST01234",
 +            "CSQ", "Feature"));
 +    fr.setFeatureFilter("Cath", filter);
 +    // if feature has no CSQ data, no colour
 +    assertNull(fr.getColour(sf2));
 +    // if CSQ data does not include Feature, no colour
 +    Map<String, String> csqData = new HashMap<>();
 +    csqData.put("BIOTYPE", "Transcript");
 +    sf2.setValue("CSQ", csqData);
 +    assertNull(fr.getColour(sf2));
 +    // if attribute does not match filter, no colour
 +    csqData.put("Feature", "ENST9876");
 +    assertNull(fr.getColour(sf2));
 +    // attribute matches filter
 +    csqData.put("Feature", "ENST01234");
 +    assertEquals(fr.getColour(sf2), expected);
    }
  }