Merge branch 'bug/JAL-3120restoreFeatureColour' into merge/JAL-3120
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 4 Mar 2019 10:54:27 +0000 (10:54 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 4 Mar 2019 10:54:27 +0000 (10:54 +0000)
Conflicts:
src/jalview/gui/Jalview2XML.java
test/jalview/io/Jalview2xmlTests.java

1  2 
src/jalview/gui/FeatureTypeSettings.java
src/jalview/project/Jalview2XML.java
src/jalview/schemes/FeatureColour.java
src/jalview/workers/ConsensusThread.java
test/jalview/gui/AlignFrameTest.java
test/jalview/io/FeaturesFileTest.java
test/jalview/project/Jalview2xmlTests.java
test/jalview/renderer/seqfeatures/FeatureRendererTest.java
test/jalview/schemes/FeatureColourTest.java

@@@ -5064,20 -4691,18 +5064,21 @@@ public class Jalview2XM
            {
              noValueColour = maxColour;
            }
 -          float min = setting.hasMin() ? setting.getMin() : 0f;
 -          float max = setting.hasMin() ? setting.getMax() : 1f;
 +          float min = safeFloat(safeFloat(setting.getMin()));
 +          float max = setting.getMax() == null ? 1f
 +                  : setting.getMax().floatValue();
-           FeatureColourI gc = new FeatureColour(minColour, maxColour,
+           FeatureColourI gc = new FeatureColour(maxColour, minColour,
 -                  maxColour, noValueColour, min, max);
 -          if (setting.getAttributeNameCount() > 0)
++                  maxColour,
 +                  noValueColour, min, max);
 +          if (setting.getAttributeName().size() > 0)
            {
 -            gc.setAttributeName(setting.getAttributeName());
 +            gc.setAttributeName(setting.getAttributeName().toArray(
 +                    new String[setting.getAttributeName().size()]));
            }
 -          if (setting.hasThreshold())
 +          if (setting.getThreshold() != null)
            {
 -            gc.setThreshold(setting.getThreshold());
 -            int threshstate = setting.getThreshstate();
 +            gc.setThreshold(setting.getThreshold().floatValue());
 +            int threshstate = safeInt(setting.getThreshstate());
              // -1 = None, 0 = Below, 1 = Above threshold
              if (threshstate == 0)
              {
          noValueColour = maxcol;
        }
    
-       colour = new FeatureColour(mincol, maxcol, noValueColour,
+       colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
 -              colourModel.getMin(), colourModel.getMax());
 -      String[] attributes = colourModel.getAttributeName();
 +              safeFloat(colourModel.getMin()),
 +              safeFloat(colourModel.getMax()));
 +      final List<String> attributeName = colourModel.getAttributeName();
 +      String[] attributes = attributeName
 +              .toArray(new String[attributeName.size()]);
        if (attributes != null && attributes.length > 0)
        {
          colour.setAttributeName(attributes);
@@@ -118,7 -118,7 +118,10 @@@ public class ConsensusThread extends Al
    protected void eraseConsensus(int aWidth)
    {
      AlignmentAnnotation consensus = getConsensusAnnotation();
--    consensus.annotations = new Annotation[aWidth];
++    if (consensus != null)
++    {
++      consensus.annotations = new Annotation[aWidth];
++    }
      AlignmentAnnotation gap = getGapAnnotation();
      if (gap != null)
      {
Simple merge
@@@ -736,167 -704,7 +736,167 @@@ public class FeaturesFileTes
      featureFilters.put("pfam", filter2);
      visible.put("foobar", new FeatureColour(Color.blue));
      ff.outputFeatureFilters(sb, visible, featureFilters);
 -    String expected = "\nSTARTFILTERS\nfoobar\tLabel Present\npfam\t(CSQ:PolyPhen Present) AND (Score LE -2.4)\nENDFILTERS\n\n";
 +    String expected = "\nSTARTFILTERS\nfoobar\tLabel Present\npfam\t(CSQ:PolyPhen Present) AND (Score LE -2.4)\nENDFILTERS\n";
      assertEquals(expected, sb.toString());
    }
 +
 +  /**
 +   * Output as GFF should not include features which are not visible due to
 +   * colour threshold or feature filter settings
 +   * 
 +   * @throws Exception
 +   */
 +  @Test(groups = { "Functional" })
 +  public void testPrintGffFormat_withFilters() throws Exception
 +  {
 +    File f = new File("examples/uniref50.fa");
 +    AlignmentI al = readAlignmentFile(f);
 +    AlignFrame af = new AlignFrame(al, 500, 500);
 +    SequenceFeature sf1 = new SequenceFeature("METAL", "Cath", 39, 39, 1.2f,
 +            null);
 +    sf1.setValue("clin_sig", "Likely Pathogenic");
 +    sf1.setValue("AF", "24");
 +    al.getSequenceAt(0).addSequenceFeature(sf1);
 +    SequenceFeature sf2 = new SequenceFeature("METAL", "Cath", 41, 41, 0.6f,
 +            null);
 +    sf2.setValue("clin_sig", "Benign");
 +    sf2.setValue("AF", "46");
 +    al.getSequenceAt(0).addSequenceFeature(sf2);
 +  
 +    FeaturesFile featuresFile = new FeaturesFile();
 +    FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
 +    final String gffHeader = "##gff-version 2\n";
 +
 +    fr.setVisible("METAL");
 +    fr.setColour("METAL", new FeatureColour(Color.PINK));
 +    String exported = featuresFile.printGffFormat(al.getSequencesArray(),
 +            fr, false);
 +    String expected = gffHeader
 +            + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
 +            + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
 +    assertEquals(expected, exported);
 +
 +    /*
 +     * now threshold to Score > 1.1 - should exclude sf2
 +     */
-     FeatureColourI fc = new FeatureColour(Color.white, Color.BLACK,
++    FeatureColourI fc = new FeatureColour(null, Color.white, Color.BLACK,
 +            Color.white, 0f, 2f);
 +    fc.setAboveThreshold(true);
 +    fc.setThreshold(1.1f);
 +    fr.setColour("METAL", fc);
 +    exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
 +            false);
 +    expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n";
 +    assertEquals(expected, exported);
 +
 +    /*
 +     * remove threshold and check sf2 is exported
 +     */
 +    fc.setAboveThreshold(false);
 +    exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
 +            false);
 +    expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
 +            + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
 +    assertEquals(expected, exported);
 +
 +    /*
 +     * filter on (clin_sig contains Benign) - should include sf2 and exclude sf1
 +     */
 +    FeatureMatcherSetI filter = new FeatureMatcherSet();
 +    filter.and(FeatureMatcher.byAttribute(Condition.Contains, "benign",
 +            "clin_sig"));
 +    fr.setFeatureFilter("METAL", filter);
 +    exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
 +            false);
 +    expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
 +    assertEquals(expected, exported);
 +  }
 +
 +  /**
 +   * Output as Jalview should not include features which are not visible due to
 +   * colour threshold or feature filter settings
 +   * 
 +   * @throws Exception
 +   */
 +  @Test(groups = { "Functional" })
 +  public void testPrintJalviewFormat_withFilters() throws Exception
 +  {
 +    File f = new File("examples/uniref50.fa");
 +    AlignmentI al = readAlignmentFile(f);
 +    AlignFrame af = new AlignFrame(al, 500, 500);
 +    SequenceFeature sf1 = new SequenceFeature("METAL", "Cath", 39, 39, 1.2f,
 +            "grp1");
 +    sf1.setValue("clin_sig", "Likely Pathogenic");
 +    sf1.setValue("AF", "24");
 +    al.getSequenceAt(0).addSequenceFeature(sf1);
 +    SequenceFeature sf2 = new SequenceFeature("METAL", "Cath", 41, 41, 0.6f,
 +            "grp2");
 +    sf2.setValue("clin_sig", "Benign");
 +    sf2.setValue("AF", "46");
 +    al.getSequenceAt(0).addSequenceFeature(sf2);
 +  
 +    FeaturesFile featuresFile = new FeaturesFile();
 +    FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
 +    fr.findAllFeatures(true);
 +  
 +    fr.setVisible("METAL");
 +    fr.setColour("METAL", new FeatureColour(Color.PINK));
 +    String exported = featuresFile.printJalviewFormat(
 +            al.getSequencesArray(),
 +            fr, false);
 +    String expected = "METAL\tffafaf\n\nSTARTGROUP\tgrp1\n"
 +            + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n"
 +            + "ENDGROUP\tgrp1\n\nSTARTGROUP\tgrp2\n"
 +            + "Cath\tFER_CAPAA\t-1\t41\t41\tMETAL\t0.6\n"
 +            + "ENDGROUP\tgrp2\n";
 +    assertEquals(expected, exported);
 +  
 +    /*
 +     * now threshold to Score > 1.1 - should exclude sf2
 +     * (and there should be no empty STARTGROUP/ENDGROUP output)
 +     */
-     FeatureColourI fc = new FeatureColour(Color.white, Color.BLACK,
++    FeatureColourI fc = new FeatureColour(null, Color.white, Color.BLACK,
 +            Color.white, 0f, 2f);
 +    fc.setAboveThreshold(true);
 +    fc.setThreshold(1.1f);
 +    fr.setColour("METAL", fc);
 +    exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
 +            false);
 +    expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|above|1.1\n\n"
 +            + "STARTGROUP\tgrp1\n"
 +            + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n"
 +            + "ENDGROUP\tgrp1\n";
 +    assertEquals(expected, exported);
 +  
 +    /*
 +     * remove threshold and check sf2 is exported
 +     */
 +    fc.setAboveThreshold(false);
 +    exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
 +            false);
 +    expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|none\n\n"
 +            + "STARTGROUP\tgrp1\n"
 +            + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n"
 +            + "ENDGROUP\tgrp1\n\nSTARTGROUP\tgrp2\n"
 +            + "Cath\tFER_CAPAA\t-1\t41\t41\tMETAL\t0.6\n"
 +            + "ENDGROUP\tgrp2\n";
 +    assertEquals(expected, exported);
 +  
 +    /*
 +     * filter on (clin_sig contains Benign) - should include sf2 and exclude sf1
 +     */
 +    FeatureMatcherSetI filter = new FeatureMatcherSet();
 +    filter.and(FeatureMatcher.byAttribute(Condition.Contains, "benign",
 +            "clin_sig"));
 +    fr.setFeatureFilter("METAL", filter);
 +    exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
 +            false);
 +    expected = "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
 +    expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|none\n\n"
 +            + "STARTFILTERS\nMETAL\tclin_sig Contains benign\nENDFILTERS\n\n"
 +            + "STARTGROUP\tgrp2\n"
 +            + "Cath\tFER_CAPAA\t-1\t41\t41\tMETAL\t0.6\n"
 +            + "ENDGROUP\tgrp2\n";
 +    assertEquals(expected, exported);
 +  }
  }
@@@ -535,71 -537,4 +537,71 @@@ public class FeatureRendererTes
      csqData.put("Feature", "ENST01234");
      assertEquals(fr.getColour(sf2), expected);
    }
 +
 +  @Test(groups = "Functional")
 +  public void testIsVisible()
 +  {
 +    String seqData = ">s1\nMLQGIFPRS\n";
 +    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
 +            DataSourceType.PASTE);
 +    AlignViewportI av = af.getViewport();
 +    FeatureRenderer fr = new FeatureRenderer(av);
 +    SequenceI seq = av.getAlignment().getSequenceAt(0);
 +    SequenceFeature sf = new SequenceFeature("METAL", "Desc", 10, 10, 1f,
 +            "Group");
 +    sf.setValue("AC", "11");
 +    sf.setValue("CLIN_SIG", "Likely Pathogenic");
 +    seq.addSequenceFeature(sf);
 +
 +    assertFalse(fr.isVisible(null));
 +
 +    /*
 +     * initial state FeatureRenderer hasn't 'found' feature
 +     * and so its feature type has not yet been set visible
 +     */
 +    assertFalse(fr.getDisplayedFeatureCols().containsKey("METAL"));
 +    assertFalse(fr.isVisible(sf));
 +
 +    fr.findAllFeatures(true);
 +    assertTrue(fr.isVisible(sf));
 +
 +    /*
 +     * feature group not visible
 +     */
 +    fr.setGroupVisibility("Group", false);
 +    assertFalse(fr.isVisible(sf));
 +    fr.setGroupVisibility("Group", true);
 +    assertTrue(fr.isVisible(sf));
 +
 +    /*
 +     * feature score outwith colour threshold (score > 2)
 +     */
-     FeatureColourI fc = new FeatureColour(Color.white, Color.black,
++    FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
 +            Color.white, 0, 10);
 +    fc.setAboveThreshold(true);
 +    fc.setThreshold(2f);
 +    fr.setColour("METAL", fc);
 +    assertFalse(fr.isVisible(sf)); // score 1 is not above threshold 2
 +    fc.setBelowThreshold(true);
 +    assertTrue(fr.isVisible(sf)); // score 1 is below threshold 2
 +
 +    /*
 +     * colour with threshold on attribute AC (value is 11)
 +     */
 +    fc.setAttributeName("AC");
 +    assertFalse(fr.isVisible(sf)); // value 11 is not below threshold 2
 +    fc.setAboveThreshold(true);
 +    assertTrue(fr.isVisible(sf)); // value 11 is above threshold 2
 +
 +    fc.setAttributeName("AF"); // attribute AF is absent in sf
 +    assertTrue(fr.isVisible(sf)); // feature is not excluded by threshold
 +
 +    FeatureMatcherSetI filter = new FeatureMatcherSet();
 +    filter.and(FeatureMatcher.byAttribute(Condition.Contains, "pathogenic",
 +            "CLIN_SIG"));
 +    fr.setFeatureFilter("METAL", filter);
 +    assertTrue(fr.isVisible(sf)); // feature matches filter
 +    filter.and(FeatureMatcher.byScore(Condition.LE, "0.4"));
 +    assertFalse(fr.isVisible(sf)); // feature doesn't match filter
 +  }
  }
@@@ -712,44 -610,4 +659,45 @@@ public class FeatureColourTes
      Color expected = new Color(70, 120, 170);
      assertEquals(expected, fc.getColor(sf));
    }
 +
 +  @Test(groups = { "Functional" })
 +  public void testIsOutwithThreshold()
 +  {
 +    FeatureColourI fc = new FeatureColour(Color.red);
 +    SequenceFeature sf = new SequenceFeature("METAL", "desc", 10, 12, 1.2f, "grp");
 +    assertFalse(fc.isOutwithThreshold(null));
 +    assertFalse(fc.isOutwithThreshold(sf));
 +
-     fc = new FeatureColour(Color.white, Color.black, Color.green, 0f, 10f);
++    fc = new FeatureColour(null, Color.white, Color.black, Color.green, 0f,
++            10f);
 +    assertFalse(fc.isOutwithThreshold(sf)); // no threshold
 +
 +    fc.setAboveThreshold(true);
 +    fc.setThreshold(1f);
 +    assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is above 1
 +
 +    fc.setThreshold(2f);
 +    assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not above 2
 +
 +    fc.setBelowThreshold(true);
 +    assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is below 2
 +
 +    fc.setThreshold(1f);
 +    assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not below 1
 +
 +    /*
 +     * with attribute value threshold
 +     */
 +    fc.setAttributeName("AC");
 +    assertFalse(fc.isOutwithThreshold(sf)); // missing attribute AC is ignored
 +
 +    sf.setValue("AC", "-1");
 +    assertFalse(fc.isOutwithThreshold(sf)); // value -1 is below 1
 +
 +    sf.setValue("AC", "1");
 +    assertTrue(fc.isOutwithThreshold(sf)); // value 1 is not below 1
 +
 +    sf.setValue("AC", "junk");
 +    assertFalse(fc.isOutwithThreshold(sf)); // bad value is ignored
 +  }
  }