From ecb334f98fca8ed9f27b6a7d027dea3bd4213023 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Mon, 9 May 2016 14:41:43 +0100 Subject: [PATCH] JAL-2018 export graduated feature colours correctly --- examples/exampleFeatures.txt | 2 +- src/jalview/appletgui/FeatureRenderer.java | 6 -- src/jalview/gui/FeatureSettings.java | 25 ++++--- src/jalview/gui/Jalview2XML.java | 52 ++++----------- src/jalview/io/FeaturesFile.java | 48 +++++++------- .../seqfeatures/FeatureRendererModel.java | 30 ++------- test/jalview/io/FeaturesFileTest.java | 70 ++++++++++++++++++++ 7 files changed, 127 insertions(+), 106 deletions(-) diff --git a/examples/exampleFeatures.txt b/examples/exampleFeatures.txt index dfadb50..2dc4b6d 100755 --- a/examples/exampleFeatures.txt +++ b/examples/exampleFeatures.txt @@ -1,5 +1,5 @@ ST-TURN-IIL blue|255,0,255|absolute|20.0|95.0|below|66.0 -GAMMA-TURN-CLASSIC red|0,255,255|20.0|95.0|below|66.0 +GAMMA-TURN-CLASSIC red|0,255,255|20.0|95.0|below|66.0 BETA-TURN-IR 9a6a94 BETA-TURN-IL d6a6ca BETA-BULGE 1dc451 diff --git a/src/jalview/appletgui/FeatureRenderer.java b/src/jalview/appletgui/FeatureRenderer.java index 03d4ce6..a93cdcb 100644 --- a/src/jalview/appletgui/FeatureRenderer.java +++ b/src/jalview/appletgui/FeatureRenderer.java @@ -351,12 +351,6 @@ public class FeatureRenderer extends start.setText(features[0].getBegin() + ""); end.setText(features[0].getEnd() + ""); description.setText(features[0].getDescription()); - Color col = getColour(name.getText()); - if (col == null) - { - col = new jalview.schemes.UserColourScheme() - .createColourFromName(name.getText()); - } Object fcol = getFeatureStyle(name.getText()); // simply display the feature color in a box colourPanel.updateColor(fcol); diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 40635c0..f250583 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -28,7 +28,9 @@ import jalview.gui.Help.HelpId; import jalview.io.JalviewFileChooser; import jalview.schemes.AnnotationColourGradient; import jalview.schemes.GraduatedColor; +import jalview.util.Format; import jalview.util.MessageManager; +import jalview.util.QuickSort; import jalview.viewmodel.AlignmentViewport; import jalview.ws.dbsources.das.api.jalviewSourceI; @@ -830,7 +832,7 @@ public class FeatureSettings extends JPanel implements void save() { JalviewFileChooser chooser = new JalviewFileChooser( - jalview.bin.Cache.getProperty("LAST_DIRECTORY"), + Cache.getProperty("LAST_DIRECTORY"), new String[] { "fc" }, new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours"); @@ -851,34 +853,35 @@ public class FeatureSettings extends JPanel implements PrintWriter out = new PrintWriter(new OutputStreamWriter( new FileOutputStream(choice), "UTF-8")); - Set fr_colours = fr.getAllFeatureColours(); - Iterator e = fr_colours.iterator(); + Set fr_colours = fr.getAllFeatureColours(); + Iterator e = fr_colours.iterator(); float[] sortOrder = new float[fr_colours.size()]; String[] sortTypes = new String[fr_colours.size()]; int i = 0; while (e.hasNext()) { - sortTypes[i] = e.next().toString(); + sortTypes[i] = e.next(); sortOrder[i] = fr.getOrder(sortTypes[i]); i++; } - jalview.util.QuickSort.sort(sortOrder, sortTypes); + QuickSort.sort(sortOrder, sortTypes); sortOrder = null; Object fcol; GraduatedColor gcol; - for (i = 0; i < sortTypes.length; i++) + for (String featureType : sortTypes) { jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour(); - col.setName(sortTypes[i]); - col.setRGB(jalview.util.Format.getHexString(fr.getColour(col - .getName()))); - fcol = fr.getFeatureStyle(sortTypes[i]); + col.setName(featureType); + fcol = fr.getFeatureStyle(featureType); + Color colour = fcol instanceof Color ? (Color) fcol + : ((GraduatedColor) fcol).getMaxColor(); + col.setRGB(Format.getHexString(colour)); if (fcol instanceof GraduatedColor) { gcol = (GraduatedColor) fcol; col.setMin(gcol.getMin()); col.setMax(gcol.getMax()); - col.setMinRGB(jalview.util.Format.getHexString(gcol + col.setMinRGB(Format.getHexString(gcol .getMinColor())); col.setAutoScale(gcol.isAutoScale()); col.setThreshold(gcol.getThresh()); diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 2799a7e..24b6e78 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -90,6 +90,7 @@ import jalview.ws.params.ArgumentI; import jalview.ws.params.AutoCalcSetting; import jalview.ws.params.WsParamSetI; +import java.awt.Color; import java.awt.Rectangle; import java.io.BufferedReader; import java.io.DataInputStream; @@ -1194,17 +1195,17 @@ public class Jalview2XML .getFeatureRenderer().getRenderOrder() .toArray(new String[0]); - Vector settingsAdded = new Vector(); + Vector settingsAdded = new Vector(); Object gstyle = null; GraduatedColor gcol = null; if (renderOrder != null) { - for (int ro = 0; ro < renderOrder.length; ro++) + for (String featureType : renderOrder) { gstyle = ap.getSeqPanel().seqCanvas.getFeatureRenderer() - .getFeatureStyle(renderOrder[ro]); + .getFeatureStyle(featureType); Setting setting = new Setting(); - setting.setType(renderOrder[ro]); + setting.setType(featureType); if (gstyle instanceof GraduatedColor) { gcol = (GraduatedColor) gstyle; @@ -1219,57 +1220,30 @@ public class Jalview2XML } else { - setting.setColour(ap.getSeqPanel().seqCanvas - .getFeatureRenderer().getColour(renderOrder[ro]) - .getRGB()); + setting.setColour(((Color) gstyle).getRGB()); } setting.setDisplay(av.getFeaturesDisplayed().isVisible( - renderOrder[ro])); + featureType)); float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer() - .getOrder(renderOrder[ro]); + .getOrder(featureType); if (rorder > -1) { setting.setOrder(rorder); } fs.addSetting(setting); - settingsAdded.addElement(renderOrder[ro]); + settingsAdded.addElement(featureType); } } - // Make sure we save none displayed feature settings - Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer() - .getFeatureColours().keySet().iterator(); - while (en.hasNext()) - { - String key = en.next().toString(); - if (settingsAdded.contains(key)) - { - continue; - } - - Setting setting = new Setting(); - setting.setType(key); - setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer() - .getColour(key).getRGB()); - - setting.setDisplay(false); - float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer() - .getOrder(key); - if (rorder > -1) - { - setting.setOrder(rorder); - } - fs.addSetting(setting); - settingsAdded.addElement(key); - } // is groups actually supposed to be a map here ? - en = ap.getSeqPanel().seqCanvas.getFeatureRenderer() + Iterator en = ap.getSeqPanel().seqCanvas + .getFeatureRenderer() .getFeatureGroups().iterator(); - Vector groupsAdded = new Vector(); + Vector groupsAdded = new Vector(); while (en.hasNext()) { - String grp = en.next().toString(); + String grp = en.next(); if (groupsAdded.contains(grp)) { continue; diff --git a/src/jalview/io/FeaturesFile.java b/src/jalview/io/FeaturesFile.java index 2dd5f26..372d905 100755 --- a/src/jalview/io/FeaturesFile.java +++ b/src/jalview/io/FeaturesFile.java @@ -842,12 +842,12 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI features = sequences[i].getSequenceFeatures(); if (features != null) { - for (int j = 0; j < features.length; j++) + for (SequenceFeature sequenceFeature : features) { - isnonpos = features[j].begin == 0 && features[j].end == 0; + isnonpos = sequenceFeature.begin == 0 && sequenceFeature.end == 0; if ((!nonpos && isnonpos) || (!isnonpos && visOnly && !visible - .containsKey(features[j].type))) + .containsKey(sequenceFeature.type))) { // skip if feature is nonpos and we ignore them or if we only // output visible and it isn't non-pos and it's not visible @@ -855,47 +855,48 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI } if (group != null - && (features[j].featureGroup == null || !features[j].featureGroup + && (sequenceFeature.featureGroup == null || !sequenceFeature.featureGroup .equals(group))) { continue; } - if (group == null && features[j].featureGroup != null) + if (group == null && sequenceFeature.featureGroup != null) { continue; } // we have features to output featuresGen = true; - if (features[j].description == null - || features[j].description.equals("")) + if (sequenceFeature.description == null + || sequenceFeature.description.equals("")) { - out.append(features[j].type).append(TAB); + out.append(sequenceFeature.type).append(TAB); } else { - if (features[j].links != null - && features[j].getDescription().indexOf("") == -1) + if (sequenceFeature.links != null + && sequenceFeature.getDescription().indexOf("") == -1) { out.append(""); } - out.append(features[j].description + " "); - if (features[j].links != null) + out.append(sequenceFeature.description); + if (sequenceFeature.links != null) { - for (int l = 0; l < features[j].links.size(); l++) + for (int l = 0; l < sequenceFeature.links.size(); l++) { - String label = features[j].links.elementAt(l).toString(); + String label = sequenceFeature.links.elementAt(l); String href = label.substring(label.indexOf("|") + 1); label = label.substring(0, label.indexOf("|")); - if (features[j].description.indexOf(href) == -1) + if (sequenceFeature.description.indexOf(href) == -1) { - out.append("" + label + ""); + out.append(" " + label + + ""); } } - if (features[j].getDescription().indexOf("") == -1) + if (sequenceFeature.getDescription().indexOf("") == -1) { out.append(""); } @@ -905,15 +906,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI } out.append(sequences[i].getName()); out.append("\t-1\t"); - out.append(features[j].begin); + out.append(sequenceFeature.begin); out.append(TAB); - out.append(features[j].end); + out.append(sequenceFeature.end); out.append(TAB); - out.append(features[j].type); - if (!Float.isNaN(features[j].score)) + out.append(sequenceFeature.type); + if (!Float.isNaN(sequenceFeature.score)) { out.append(TAB); - out.append(features[j].score); + out.append(sequenceFeature.score); } out.append(newline); } @@ -1024,7 +1025,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI boolean includeNonPositionalFeatures) { StringBuilder out = new StringBuilder(256); - out.append(String.format("%s %d\n", GFF_VERSION, gffVersion)); + int version = gffVersion == 0 ? 2 : gffVersion; + out.append(String.format("%s %d\n", GFF_VERSION, version)); String source; boolean isnonpos; for (SequenceI seq : sequences) diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 848f565..ec2c591 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -561,31 +561,6 @@ public abstract class FeatureRendererModel implements } /** - * return a nominal colour for this feature - * - * @param featureType - * @return standard color, or maximum colour for graduated colourscheme - */ - public Color getColour(String featureType) - { - Object fc = getFeatureStyle(featureType); - - if (fc instanceof Color) - { - return (Color) fc; - } - else - { - if (fc instanceof GraduatedColor) - { - return ((GraduatedColor) fc).getMaxColor(); - } - } - throw new Error("Implementation Error: Unrecognised render object " - + fc.getClass() + " for features of type " + featureType); - } - - /** * calculate the render colour for a specific feature using current feature * settings. * @@ -838,6 +813,9 @@ public abstract class FeatureRendererModel implements return renderOrder != null; } + /** + * Returns feature types in ordering of rendering, where last means on top + */ public List getRenderOrder() { if (renderOrder == null) @@ -947,7 +925,7 @@ public abstract class FeatureRendererModel implements while (en.hasNext()) { String col = en.next(); - fcols.put(col, getColour(col)); + fcols.put(col, featureColours.get(col)); } return fcols; } diff --git a/test/jalview/io/FeaturesFileTest.java b/test/jalview/io/FeaturesFileTest.java index 385e049..81d5b05 100644 --- a/test/jalview/io/FeaturesFileTest.java +++ b/test/jalview/io/FeaturesFileTest.java @@ -26,6 +26,7 @@ import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; +import jalview.api.FeatureRenderer; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceDummy; @@ -412,4 +413,73 @@ public class FeaturesFileTest parseResult); checkDatasetfromSimpleGff3(dataset); } + + @Test(groups = { "Functional" }) + public void testPrintJalviewFormat() throws Exception + { + File f = new File("examples/uniref50.fa"); + AlignmentI al = readAlignmentFile(f); + AlignFrame af = new AlignFrame(al, 500, 500); + Map colours = af.getFeatureRenderer() + .getFeatureColours(); + String features = "METAL\tcc9900\n" + + "GAMMA-TURN\tred|0,255,255|20.0|95.0|below|66.0\n" + + "Pfam\tred\n" + + "STARTGROUP\tuniprot\n" + + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\n" + + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\n" + + "Pfam domainPfam_3_4\tFER_CAPAA\t-1\t20\t20\tPfam\n" + + "ENDGROUP\tuniprot\n"; + FeaturesFile featuresFile = new FeaturesFile(features, + FormatAdapter.PASTE); + featuresFile.parse(al.getDataset(), colours, false); + + /* + * first with no features displayed + */ + FeatureRenderer fr = af.alignPanel.getFeatureRenderer(); + Map visible = fr + .getDisplayedFeatureCols(); + String exported = featuresFile.printJalviewFormat( + al.getSequencesArray(), visible); + String expected = "No Features Visible"; + assertEquals(expected, exported); + + /* + * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam + */ + fr.setVisible("METAL"); + fr.setVisible("GAMMA-TURN"); + visible = fr.getDisplayedFeatureCols(); + exported = featuresFile.printJalviewFormat(al.getSequencesArray(), + visible); + expected = "METAL\tcc9900\n" + + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n" + + "\nSTARTGROUP\tuniprot\n" + + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n" + + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n" + + "ENDGROUP\tuniprot\n"; + assertEquals(expected, exported); + + /* + * now set Pfam visible + */ + fr.setVisible("Pfam"); + visible = fr.getDisplayedFeatureCols(); + exported = featuresFile.printJalviewFormat(al.getSequencesArray(), + visible); + /* + * note the order of feature types is uncontrolled - derives from + * FeaturesDisplayed.featuresDisplayed which is a HashSet + */ + expected = "METAL\tcc9900\n" + + "Pfam\tff0000\n" + + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n" + + "\nSTARTGROUP\tuniprot\n" + + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n" + + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n" + + "Pfam domainPfam_3_4\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n" + + "ENDGROUP\tuniprot\n"; + assertEquals(expected, exported); + } } -- 1.7.10.2