JAL-2808 capture feature attributes datatype (Character/Number/Mixed) for more intell...
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 22 Nov 2017 09:34:58 +0000 (09:34 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 22 Nov 2017 09:34:58 +0000 (09:34 +0000)
src/jalview/datamodel/features/FeatureAttributes.java
test/jalview/datamodel/features/FeatureAttributesTest.java

index 7221d62..e359b62 100644 (file)
@@ -14,6 +14,11 @@ import java.util.TreeMap;
  */
 public class FeatureAttributes
 {
+  public enum Datatype
+  {
+    Character, Number, Mixed
+  }
+
   private static FeatureAttributes instance = new FeatureAttributes();
 
   /*
@@ -79,6 +84,8 @@ public class FeatureAttributes
      */
     boolean hasValue = false;
 
+    Datatype type;
+
     /**
      * Note one instance of this attribute, recording unique, non-null names,
      * and the min/max of any numerical values
@@ -95,12 +102,17 @@ public class FeatureAttributes
         try
         {
           float f = Float.valueOf(value);
-          min = Float.min(min, f);
-          max = Float.max(max, f);
+          min = hasValue ? Float.min(min, f) : f;
+          max = hasValue ? Float.max(max, f) : f;
           hasValue = true;
+          type = (type == null || type == Datatype.Number) ? Datatype.Number
+                  : Datatype.Mixed;
         } catch (NumberFormatException e)
         {
-          // ok, wasn't a number, ignore for min-max purposes
+          // not a number, ignore for min-max purposes
+          type = (type == null || type == Datatype.Character)
+                  ? Datatype.Character
+                  : Datatype.Mixed;
         }
       }
     }
@@ -118,6 +130,11 @@ public class FeatureAttributes
       return null;
     }
 
+    public Datatype getType()
+    {
+      return type;
+    }
+
     /**
      * Adds the given description to the list of known descriptions (without
      * duplication)
@@ -318,4 +335,26 @@ public class FeatureAttributes
     }
     attData.addDescription(description);
   }
+
+  /**
+   * Answers the datatype of the feature, which is one of Character, Number or
+   * Mixed (or null if not known), as discovered from values recorded.
+   * 
+   * @param featureType
+   * @param attName
+   * @return
+   */
+  public Datatype getDatatype(String featureType, String... attName)
+  {
+    Map<String[], AttributeData> atts = attributes.get(featureType);
+    if (atts != null)
+    {
+      AttributeData attData = atts.get(attName);
+      if (attData != null)
+      {
+        return attData.getType();
+      }
+    }
+    return null;
+  }
 }
index e464326..4b7a435 100644 (file)
@@ -1,18 +1,35 @@
 package jalview.datamodel.features;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
-import java.util.Comparator;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.features.FeatureAttributes.Datatype;
 
-import junit.extensions.PA;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
 
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 public class FeatureAttributesTest
 {
 
   /**
+   * clear down attributes map after tests
+   */
+  @AfterMethod
+  public void tearDown()
+  {
+    FeatureAttributes fa = FeatureAttributes.getInstance();
+    ((Map<?, ?>) PA.getValue(fa, "attributes")).clear();
+  }
+
+  /**
    * Test the method that keeps attribute names in non-case-sensitive order,
    * including handling of 'compound' names
    */
@@ -38,4 +55,66 @@ public class FeatureAttributesTest
     assertTrue(comp.compare(new String[] { "CSQ", "ac" }, new String[] {
         "csq", "AF" }) < 0);
   }
+
+  @Test
+  public void testGetMinMax()
+  {
+    SequenceFeature sf = new SequenceFeature("Pfam", "desc", 10, 20,
+            "group");
+    FeatureAttributes fa = FeatureAttributes.getInstance();
+    assertNull(fa.getMinMax("Pfam", "kd"));
+    sf.setValue("domain", "xyz");
+    assertNull(fa.getMinMax("Pfam", "kd"));
+    sf.setValue("kd", "some text");
+    assertNull(fa.getMinMax("Pfam", "kd"));
+    sf.setValue("kd", "1.3");
+    assertEquals(fa.getMinMax("Pfam", "kd"), new float[] { 1.3f, 1.3f });
+    sf.setValue("kd", "-2.6");
+    assertEquals(fa.getMinMax("Pfam", "kd"), new float[] { -2.6f, 1.3f });
+    Map<String, String> csq = new HashMap<>();
+    csq.put("AF", "-3");
+    sf.setValue("CSQ", csq);
+    assertEquals(fa.getMinMax("Pfam", "CSQ", "AF"),
+            new float[]
+            { -3f, -3f });
+    csq.put("AF", "4");
+    sf.setValue("CSQ", csq);
+    assertEquals(fa.getMinMax("Pfam", "CSQ", "AF"),
+            new float[]
+            { -3f, 4f });
+  }
+
+  /**
+   * Test the method that returns an attribute description, provided it is
+   * recorded and unique
+   */
+  @Test
+  public void testGetDescription()
+  {
+    FeatureAttributes fa = FeatureAttributes.getInstance();
+    // with no description returns null
+    assertNull(fa.getDescription("Pfam", "kd"));
+    // with a unique description, returns that value
+    fa.addDescription("Pfam", "desc1", "kd");
+    assertEquals(fa.getDescription("Pfam", "kd"), "desc1");
+    // with ambiguous description, returns null
+    fa.addDescription("Pfam", "desc2", "kd");
+    assertNull(fa.getDescription("Pfam", "kd"));
+  }
+
+  @Test
+  public void testDatatype()
+  {
+    FeatureAttributes fa = FeatureAttributes.getInstance();
+    assertNull(fa.getDatatype("Pfam", "kd"));
+    SequenceFeature sf = new SequenceFeature("Pfam", "desc", 10, 20,
+            "group");
+    sf.setValue("kd", "-1");
+    sf.setValue("domain", "Metal");
+    sf.setValue("phase", "1");
+    sf.setValue("phase", "reverse");
+    assertEquals(fa.getDatatype("Pfam", "kd"), Datatype.Number);
+    assertEquals(fa.getDatatype("Pfam", "domain"), Datatype.Character);
+    assertEquals(fa.getDatatype("Pfam", "phase"), Datatype.Mixed);
+  }
 }