From: gmungoc Date: Mon, 4 Mar 2019 10:54:27 +0000 (+0000) Subject: Merge branch 'bug/JAL-3120restoreFeatureColour' into merge/JAL-3120 X-Git-Tag: Release_2_11_0~17^2~80 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=3c8a25936a2d805e7e3d7ab82f83b13135406d18 Merge branch 'bug/JAL-3120restoreFeatureColour' into merge/JAL-3120 Conflicts: src/jalview/gui/Jalview2XML.java test/jalview/io/Jalview2xmlTests.java --- 3c8a25936a2d805e7e3d7ab82f83b13135406d18 diff --cc src/jalview/project/Jalview2XML.java index f772cf5,28077e6..53e9a83 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.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) { @@@ -6562,12 -5954,9 +6563,12 @@@ 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 attributeName = colourModel.getAttributeName(); + String[] attributes = attributeName + .toArray(new String[attributeName.size()]); if (attributes != null && attributes.length > 0) { colour.setAttributeName(attributes); diff --cc src/jalview/workers/ConsensusThread.java index 335529c,335529c..78c6da2 --- a/src/jalview/workers/ConsensusThread.java +++ b/src/jalview/workers/ConsensusThread.java @@@ -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) { diff --cc test/jalview/io/FeaturesFileTest.java index 3632cc7,32ca841..77c18db --- a/test/jalview/io/FeaturesFileTest.java +++ b/test/jalview/io/FeaturesFileTest.java @@@ -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); + } } diff --cc test/jalview/renderer/seqfeatures/FeatureRendererTest.java index a0fb498,ba8b581..723f3b8 --- a/test/jalview/renderer/seqfeatures/FeatureRendererTest.java +++ b/test/jalview/renderer/seqfeatures/FeatureRendererTest.java @@@ -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 + } } diff --cc test/jalview/schemes/FeatureColourTest.java index 6ccce85,1a6a5f3..8f7ac7c --- a/test/jalview/schemes/FeatureColourTest.java +++ b/test/jalview/schemes/FeatureColourTest.java @@@ -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 + } }