JAL-2018 export graduated feature colours correctly
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 9 May 2016 13:41:43 +0000 (14:41 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 9 May 2016 13:41:43 +0000 (14:41 +0100)
examples/exampleFeatures.txt
src/jalview/appletgui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/Jalview2XML.java
src/jalview/io/FeaturesFile.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
test/jalview/io/FeaturesFileTest.java

index dfadb50..2dc4b6d 100755 (executable)
@@ -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
index 03d4ce6..a93cdcb 100644 (file)
@@ -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);
index 40635c0..f250583 100644 (file)
@@ -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<String> fr_colours = fr.getAllFeatureColours();
+        Iterator<String> 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());
index 2799a7e..24b6e78 100644 (file)
@@ -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<String> settingsAdded = new Vector<String>();
         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<String> en = ap.getSeqPanel().seqCanvas
+                .getFeatureRenderer()
                 .getFeatureGroups().iterator();
-        Vector groupsAdded = new Vector();
+        Vector<String> groupsAdded = new Vector<String>();
         while (en.hasNext())
         {
-          String grp = en.next().toString();
+          String grp = en.next();
           if (groupsAdded.contains(grp))
           {
             continue;
index 2dd5f26..372d905 100755 (executable)
@@ -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("<html>") == -1)
+              if (sequenceFeature.links != null
+                      && sequenceFeature.getDescription().indexOf("<html>") == -1)
               {
                 out.append("<html>");
               }
 
-              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("<a href=\"" + href + "\">" + label + "</a>");
+                    out.append(" <a href=\"" + href + "\">" + label
+                            + "</a>");
                   }
                 }
 
-                if (features[j].getDescription().indexOf("</html>") == -1)
+                if (sequenceFeature.getDescription().indexOf("</html>") == -1)
                 {
                   out.append("</html>");
                 }
@@ -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)
index 848f565..ec2c591 100644 (file)
@@ -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<String> 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;
   }
index 385e049..81d5b05 100644 (file)
@@ -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<String, Object> 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"
+            + "<html>Pfam domain<a href=\"http://pfam.sanger.ac.uk/family/PF00111\">Pfam_3_4</a></html>\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<String, Object> 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"
+            + "<html>Pfam domain<a href=\"http://pfam.sanger.ac.uk/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n"
+            + "ENDGROUP\tuniprot\n";
+    assertEquals(expected, exported);
+  }
 }