JAL-2480 SequenceFeaturesI encapsulates features api
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 18 Apr 2017 08:42:45 +0000 (09:42 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 18 Apr 2017 08:42:45 +0000 (09:42 +0100)
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/features/FeatureStore.java
src/jalview/datamodel/features/SequenceFeatures.java
src/jalview/datamodel/features/SequenceFeaturesI.java [new file with mode: 0644]
src/jalview/gui/FeatureSettings.java
test/jalview/datamodel/features/FeatureStoreTest.java
test/jalview/datamodel/features/SequenceFeaturesTest.java

index e1c8566..b93cae0 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.datamodel;
 import jalview.analysis.AlignSeq;
 import jalview.api.DBRefEntryI;
 import jalview.datamodel.features.SequenceFeatures;
+import jalview.datamodel.features.SequenceFeaturesI;
 import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
@@ -426,6 +427,12 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
+  public SequenceFeaturesI getFeatures()
+  {
+    return sequenceFeatureStore;
+  }
+
+  @Override
   public boolean addPDBId(PDBEntry entry)
   {
     if (pdbIds == null)
index 7ecb4ed..605f682 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import jalview.datamodel.features.SequenceFeaturesI;
+
 import java.util.List;
 import java.util.Vector;
 
@@ -267,6 +269,13 @@ public interface SequenceI extends ASequenceI
   public SequenceFeature[] getSequenceFeatures();
 
   /**
+   * Answers the object holding features for the sequence
+   * 
+   * @return
+   */
+  SequenceFeaturesI getFeatures();
+
+  /**
    * Replaces the array of sequence features associated with this sequence with
    * a new array reference. If this sequence has a dataset sequence, then this
    * method will update the dataset sequence's feature array
index 721ac18..d6a94e2 100644 (file)
@@ -121,6 +121,12 @@ public class FeatureStore
    */
   Set<String> nonPositionalFeatureGroups;
 
+  /*
+   * the total length of all positional features; contact features count 1 to
+   * the total and 1 to size(), consistent with an average 'feature length' of 1
+   */
+  int totalExtent;
+
   /**
    * Constructor
    */
@@ -176,6 +182,18 @@ public class FeatureStore
       }
     }
 
+    /*
+     * record the total extent of positional features, to make
+     * getAverageFeatureLength possible; we count the length of a 
+     * contact feature as 1
+     */
+    if (added && !feature.isNonPositional())
+    {
+      int featureLength = feature.isContactFeature() ? 1 : 1
+              + feature.getEnd() - feature.getBegin();
+      totalExtent += featureLength;
+    }
+
     return added;
   }
 
@@ -622,6 +640,7 @@ public class FeatureStore
     if (removed)
     {
       rebuildFeatureGroups(sf.getFeatureGroup(), removedNonPositional);
+      // TODO and recalculate totalExtent (feature may have changed length!)
     }
 
     return removed;
@@ -756,4 +775,46 @@ public class FeatureStore
 
     return matched;
   }
+
+  /**
+   * Answers the number of positional (or non-positional) features stored
+   * 
+   * @param positional
+   * @return
+   */
+  public int size(boolean positional)
+  {
+    if (!positional)
+    {
+      return nonPositionalFeatures == null ? 0 : nonPositionalFeatures
+              .size();
+    }
+
+    int size = nonNestedFeatures.size();
+
+    if (contactFeatureStarts != null)
+    {
+      // note a contact feature (start/end) counts as one
+      size += contactFeatureStarts.size();
+    }
+
+    if (nestedFeatures != null)
+    {
+      size += nestedFeatures.size();
+    }
+
+    return size;
+  }
+
+  /**
+   * Answers the average length of positional features (or zero if there are
+   * none). Contact features contribute a value of 1 to the average.
+   * 
+   * @return
+   */
+  public float getAverageFeatureLength()
+  {
+    int d = size(true);
+    return d == 0 ? 0f : (float) totalExtent / d;
+  }
 }
index 6165d0a..4489b1d 100644 (file)
@@ -4,6 +4,7 @@ import jalview.datamodel.SequenceFeature;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -19,7 +20,7 @@ import java.util.Set;
  * @author gmcarstairs
  *
  */
-public class SequenceFeatures
+public class SequenceFeatures implements SequenceFeaturesI
 {
 
   /*
@@ -36,14 +37,10 @@ public class SequenceFeatures
     featureStore = new HashMap<String, FeatureStore>();
   }
 
-  /**
-   * Adds one sequence feature to the store, and returns true, unless the
-   * feature is already contained in the store, in which case this method
-   * returns false. Containment is determined by SequenceFeature.equals()
-   * comparison.
-   * 
-   * @param sf
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#add(jalview.datamodel.SequenceFeature)
    */
+  @Override
   public boolean add(SequenceFeature sf)
   {
     String type = sf.getType();
@@ -55,16 +52,10 @@ public class SequenceFeatures
     return featureStore.get(type).addFeature(sf);
   }
 
-  /**
-   * Returns a (possibly empty) list of features, optionally restricted to
-   * specified types, which overlap the given (inclusive) sequence position
-   * range
-   * 
-   * @param from
-   * @param to
-   * @param type
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#findFeatures(int, int, java.lang.String)
    */
+  @Override
   public List<SequenceFeature> findFeatures(int from, int to,
           String... type)
   {
@@ -82,13 +73,10 @@ public class SequenceFeatures
     return result;
   }
 
-  /**
-   * Answers a list of all features stored, optionally restricted to specified
-   * types, in no particular guaranteed order
-   * 
-   * @param type
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getAllFeatures(java.lang.String)
    */
+  @Override
   public List<SequenceFeature> getAllFeatures(String... type)
   {
     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
@@ -100,13 +88,25 @@ public class SequenceFeatures
     return result;
   }
 
-  /**
-   * Answers a list of all positional features, optionally restricted to
-   * specified types, in no particular guaranteed order
-   * 
-   * @param type
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getFeatureCount(boolean, java.lang.String)
    */
+  @Override
+  public int getFeatureCount(boolean positional, String... type)
+  {
+    int result = 0;
+    for (FeatureStore fs : featureStore.values())
+    {
+      result += fs.size(positional);
+    }
+
+    return result;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getPositionalFeatures(java.lang.String)
+   */
+  @Override
   public List<SequenceFeature> getPositionalFeatures(String... type)
   {
     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
@@ -136,12 +136,10 @@ public class SequenceFeatures
             .keySet() : Arrays.asList(type);
   }
 
-  /**
-   * Answers a list of all contact features, optionally restricted to specified
-   * types, in no particular guaranteed order
-   * 
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getContactFeatures(java.lang.String)
    */
+  @Override
   public List<SequenceFeature> getContactFeatures(String... type)
   {
     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
@@ -157,14 +155,10 @@ public class SequenceFeatures
     return result;
   }
 
-  /**
-   * Answers a list of all non-positional features, optionally restricted to
-   * specified types, in no particular guaranteed order
-   * 
-   * @param type
-   *          if no type is specified, all are returned
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getNonPositionalFeatures(java.lang.String)
    */
+  @Override
   public List<SequenceFeature> getNonPositionalFeatures(String... type)
   {
     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
@@ -180,14 +174,10 @@ public class SequenceFeatures
     return result;
   }
 
-  /**
-   * Deletes the given feature from the store, returning true if it was found
-   * (and deleted), else false. This method makes no assumption that the feature
-   * is in the 'expected' place in the store, in case it has been modified since
-   * it was added.
-   * 
-   * @param sf
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#delete(jalview.datamodel.SequenceFeature)
    */
+  @Override
   public boolean delete(SequenceFeature sf)
   {
     for (FeatureStore featureSet : featureStore.values())
@@ -200,11 +190,10 @@ public class SequenceFeatures
     return false;
   }
 
-  /**
-   * Answers true if this store contains at least one feature, else false
-   * 
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#hasFeatures()
    */
+  @Override
   public boolean hasFeatures()
   {
     for (FeatureStore featureSet : featureStore.values())
@@ -217,17 +206,10 @@ public class SequenceFeatures
     return false;
   }
 
-  /**
-   * Returns a set of the distinct feature groups present in the collection. The
-   * set may include null. The boolean parameter determines whether the groups
-   * for positional or for non-positional features are returned. The optional
-   * type parameter may be used to restrict to groups for specified feature
-   * types.
-   * 
-   * @param positionalFeatures
-   * @param type
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getFeatureGroups(boolean, java.lang.String)
    */
+  @Override
   public Set<String> getFeatureGroups(boolean positionalFeatures,
           String... type)
   {
@@ -247,16 +229,10 @@ public class SequenceFeatures
     return groups;
   }
 
-  /**
-   * Answers the set of distinct feature types for which there is at least one
-   * feature with one of the given feature group(s). The parameter determines
-   * whether the groups for positional or for non-positional features are
-   * returned.
-   * 
-   * @param positionalFeatures
-   * @param groups
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getFeatureTypesForGroups(boolean, java.lang.String)
    */
+  @Override
   public Set<String> getFeatureTypesForGroups(boolean positionalFeatures,
           String... groups)
   {
@@ -281,4 +257,13 @@ public class SequenceFeatures
 
     return result;
   }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.features.SequenceFeaturesI#getFeatureTypes()
+   */
+  @Override
+  public Set<String> getFeatureTypes()
+  {
+    return Collections.unmodifiableSet(featureStore.keySet());
+  }
 }
diff --git a/src/jalview/datamodel/features/SequenceFeaturesI.java b/src/jalview/datamodel/features/SequenceFeaturesI.java
new file mode 100644 (file)
index 0000000..b6cc3ad
--- /dev/null
@@ -0,0 +1,125 @@
+package jalview.datamodel.features;
+
+import jalview.datamodel.SequenceFeature;
+
+import java.util.List;
+import java.util.Set;
+
+public interface SequenceFeaturesI
+{
+
+  /**
+   * Adds one sequence feature to the store, and returns true, unless the
+   * feature is already contained in the store, in which case this method
+   * returns false. Containment is determined by SequenceFeature.equals()
+   * comparison.
+   * 
+   * @param sf
+   */
+  public abstract boolean add(SequenceFeature sf);
+
+  /**
+   * Returns a (possibly empty) list of features, optionally restricted to
+   * specified types, which overlap the given (inclusive) sequence position
+   * range
+   * 
+   * @param from
+   * @param to
+   * @param type
+   * @return
+   */
+  public abstract List<SequenceFeature> findFeatures(int from, int to,
+          String... type);
+
+  /**
+   * Answers a list of all features stored, optionally restricted to specified
+   * types, in no particular guaranteed order
+   * 
+   * @param type
+   * @return
+   */
+  public abstract List<SequenceFeature> getAllFeatures(String... type);
+
+  public abstract int getFeatureCount(boolean positional, String... type);
+
+  /**
+   * Answers a list of all positional features, optionally restricted to
+   * specified types, in no particular guaranteed order
+   * 
+   * @param type
+   * @return
+   */
+  public abstract List<SequenceFeature> getPositionalFeatures(
+          String... type);
+
+  /**
+   * Answers a list of all contact features, optionally restricted to specified
+   * types, in no particular guaranteed order
+   * 
+   * @return
+   */
+  public abstract List<SequenceFeature> getContactFeatures(String... type);
+
+  /**
+   * Answers a list of all non-positional features, optionally restricted to
+   * specified types, in no particular guaranteed order
+   * 
+   * @param type
+   *          if no type is specified, all are returned
+   * @return
+   */
+  public abstract List<SequenceFeature> getNonPositionalFeatures(
+          String... type);
+
+  /**
+   * Deletes the given feature from the store, returning true if it was found
+   * (and deleted), else false. This method makes no assumption that the feature
+   * is in the 'expected' place in the store, in case it has been modified since
+   * it was added.
+   * 
+   * @param sf
+   */
+  public abstract boolean delete(SequenceFeature sf);
+
+  /**
+   * Answers true if this store contains at least one feature, else false
+   * 
+   * @return
+   */
+  public abstract boolean hasFeatures();
+
+  /**
+   * Returns a set of the distinct feature groups present in the collection. The
+   * set may include null. The boolean parameter determines whether the groups
+   * for positional or for non-positional features are returned. The optional
+   * type parameter may be used to restrict to groups for specified feature
+   * types.
+   * 
+   * @param positionalFeatures
+   * @param type
+   * @return
+   */
+  public abstract Set<String> getFeatureGroups(boolean positionalFeatures,
+          String... type);
+
+  /**
+   * Answers the set of distinct feature types for which there is at least one
+   * feature with one of the given feature group(s). The boolean parameter
+   * determines whether the groups for positional or for non-positional features
+   * are returned.
+   * 
+   * @param positionalFeatures
+   * @param groups
+   * @return
+   */
+  public abstract Set<String> getFeatureTypesForGroups(
+          boolean positionalFeatures, String... groups);
+
+  /**
+   * Answers an immutable set of the distinct feature types for which a feature
+   * is stored
+   * @return
+   */
+  public abstract Set<String> getFeatureTypes();
+
+}
\ No newline at end of file
index 26f9964..067d8ae 100644 (file)
@@ -23,6 +23,7 @@ package jalview.gui;
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.Help.HelpId;
@@ -60,6 +61,7 @@ import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
@@ -470,43 +472,19 @@ public class FeatureSettings extends JPanel implements
   @Override
   synchronized public void discoverAllFeatureData()
   {
-    Vector<String> allFeatures = new Vector<String>();
-    Vector<String> allGroups = new Vector<String>();
-    SequenceFeature[] tmpfeatures;
-    String group;
-    for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
-    {
-      tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
-              .getSequenceFeatures();
-      if (tmpfeatures == null)
-      {
-        continue;
-      }
+    Set<String> allGroups = new HashSet<String>();
+    AlignmentI alignment = af.getViewport().getAlignment();
 
-      int index = 0;
-      while (index < tmpfeatures.length)
+    for (int i = 0; i < alignment.getHeight(); i++)
+    {
+      SequenceI seq = alignment.getSequenceAt(i);
+      for (String group : seq.getFeatures().getFeatureGroups(true))
       {
-        if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
+        if (group != null && !allGroups.contains(group))
         {
-          index++;
-          continue;
-        }
-
-        if (tmpfeatures[index].getFeatureGroup() != null)
-        {
-          group = tmpfeatures[index].featureGroup;
-          if (!allGroups.contains(group))
-          {
-            allGroups.addElement(group);
-            checkGroupState(group);
-          }
+          allGroups.add(group);
+          checkGroupState(group);
         }
-
-        if (!allFeatures.contains(tmpfeatures[index].getType()))
-        {
-          allFeatures.addElement(tmpfeatures[index].getType());
-        }
-        index++;
       }
     }
 
@@ -572,7 +550,7 @@ public class FeatureSettings extends JPanel implements
 
   synchronized void resetTable(String[] groupChanged)
   {
-    if (resettingTable == true)
+    if (resettingTable)
     {
       return;
     }
@@ -591,13 +569,13 @@ public class FeatureSettings extends JPanel implements
     for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
     {
 
-      tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
-              .getSequenceFeatures();
+      SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
+      tmpfeatures = seq.getSequenceFeatures();
       if (tmpfeatures == null)
       {
         continue;
       }
-
+      Set<String> types = seq.getFeatures().getFeatureTypes();
       int index = 0;
       while (index < tmpfeatures.length)
       {
index 8aabc56..b04f810 100644 (file)
@@ -365,12 +365,16 @@ public class FeatureStoreTest
             Float.NaN, null);
 
     assertTrue(fs.addFeature(sf1));
+    assertEquals(fs.size(true), 1); // positional
+    assertEquals(fs.size(false), 0); // non-positional
 
     /*
      * re-adding the same or an identical feature should fail
      */
     assertFalse(fs.addFeature(sf1));
+    assertEquals(fs.size(true), 1);
     assertFalse(fs.addFeature(sf2));
+    assertEquals(fs.size(true), 1);
   }
 
   @Test(groups = "Functional")
@@ -378,6 +382,7 @@ public class FeatureStoreTest
   {
     FeatureStore fs = new FeatureStore();
     assertTrue(fs.isEmpty());
+    assertEquals(fs.size(true), 0);
 
     /*
      * non-nested feature
@@ -386,8 +391,10 @@ public class FeatureStoreTest
             Float.NaN, null);
     fs.addFeature(sf1);
     assertFalse(fs.isEmpty());
+    assertEquals(fs.size(true), 1);
     fs.delete(sf1);
     assertTrue(fs.isEmpty());
+    assertEquals(fs.size(true), 0);
 
     /*
      * non-positional feature
@@ -395,8 +402,11 @@ public class FeatureStoreTest
     sf1 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, null);
     fs.addFeature(sf1);
     assertFalse(fs.isEmpty());
+    assertEquals(fs.size(false), 1); // non-positional
+    assertEquals(fs.size(true), 0); // positional
     fs.delete(sf1);
     assertTrue(fs.isEmpty());
+    assertEquals(fs.size(false), 0);
 
     /*
      * contact feature
@@ -404,8 +414,10 @@ public class FeatureStoreTest
     sf1 = new SequenceFeature("Disulfide bond", "", 19, 49, Float.NaN, null);
     fs.addFeature(sf1);
     assertFalse(fs.isEmpty());
+    assertEquals(fs.size(true), 1);
     fs.delete(sf1);
     assertTrue(fs.isEmpty());
+    assertEquals(fs.size(true), 0);
 
     /*
      * sf2, sf3 added as nested features
@@ -418,14 +430,18 @@ public class FeatureStoreTest
     fs.addFeature(sf1);
     fs.addFeature(sf2);
     fs.addFeature(sf3);
+    assertEquals(fs.size(true), 3);
     assertTrue(fs.delete(sf1));
+    assertEquals(fs.size(true), 2);
     // FeatureStore should now only contain features in the NCList
     assertTrue(fs.nonNestedFeatures.isEmpty());
     assertEquals(fs.nestedFeatures.size(), 2);
     assertFalse(fs.isEmpty());
     assertTrue(fs.delete(sf2));
+    assertEquals(fs.size(true), 1);
     assertFalse(fs.isEmpty());
     assertTrue(fs.delete(sf3));
+    assertEquals(fs.size(true), 0);
     assertTrue(fs.isEmpty()); // all gone
   }
 
@@ -481,4 +497,29 @@ public class FeatureStoreTest
     groups = fs.getFeatureGroups(true);
     assertTrue(groups.isEmpty());
   }
+
+  @Test(groups = "Functional")
+  public void testGetAverageFeatureLength()
+  {
+    FeatureStore fs = new FeatureStore();
+    assertEquals(fs.getAverageFeatureLength(), 0f);
+
+    addFeature(fs, 10, 20); // 11
+    assertEquals(fs.getAverageFeatureLength(), 11f);
+    addFeature(fs, 17, 37); // 21
+    addFeature(fs, 14, 74); // 61
+    assertEquals(fs.getAverageFeatureLength(), 31f);
+
+    // non-positional features don't count
+    SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
+            "group1");
+    fs.addFeature(sf1);
+    assertEquals(fs.getAverageFeatureLength(), 31f);
+
+    // contact features count 1
+    SequenceFeature sf2 = new SequenceFeature("disulphide bond", "desc",
+            15, 35, 1f, "group1");
+    fs.addFeature(sf2);
+    assertEquals(fs.getAverageFeatureLength(), 94f / 4f);
+  }
 }
index 84a07b4..f9b9b6e 100644 (file)
@@ -16,7 +16,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetPositionalFeatures()
   {
-    SequenceFeatures store = new SequenceFeatures();
+    SequenceFeaturesI store = new SequenceFeatures();
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
     store.add(sf1);
@@ -96,7 +96,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetContactFeatures()
   {
-    SequenceFeatures store = new SequenceFeatures();
+    SequenceFeaturesI store = new SequenceFeatures();
     // non-contact
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
@@ -148,7 +148,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetNonPositionalFeatures()
   {
-    SequenceFeatures store = new SequenceFeatures();
+    SequenceFeaturesI store = new SequenceFeatures();
     // positional
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
@@ -211,7 +211,7 @@ public class SequenceFeaturesTest
    * @param to
    * @return
    */
-  SequenceFeature addFeature(SequenceFeatures sf, String type, int from,
+  SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from,
           int to)
   {
     SequenceFeature sf1 = new SequenceFeature(type, "", from, to,
@@ -224,7 +224,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testFindFeatures()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
     SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
     SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
@@ -288,7 +288,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testDelete()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
     assertTrue(sf.getPositionalFeatures().contains(sf1));
 
@@ -302,7 +302,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testHasFeatures()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertFalse(sf.hasFeatures());
 
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
@@ -319,7 +319,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertTrue(sf.getFeatureGroups(true).isEmpty());
     assertTrue(sf.getFeatureGroups(false).isEmpty());
 
@@ -412,7 +412,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetFeatureTypesForGroups()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
   
     /*