JAL-2808 feature filters held on FeatureRenderer, getColor(feature)
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 2 Nov 2017 14:47:10 +0000 (14:47 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 2 Nov 2017 14:47:10 +0000 (14:47 +0000)
extracted

src/jalview/api/FeatureRenderer.java
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
src/jalview/viewmodel/seqfeatures/FeatureRendererSettings.java

index 9d2d7f4..40c7d4d 100644 (file)
@@ -22,6 +22,7 @@ package jalview.api;
 
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.util.matcher.KeyedMatcherSetI;
 
 import java.awt.Color;
 import java.awt.Graphics;
 
 import java.awt.Color;
 import java.awt.Graphics;
@@ -215,4 +216,53 @@ public interface FeatureRenderer
    */
   float getTransparency();
 
    */
   float getTransparency();
 
+  /**
+   * Answers the filters applied to the given feature type, or null if none is
+   * set
+   * 
+   * @param featureType
+   * @return
+   */
+  KeyedMatcherSetI getFeatureFilter(String featureType);
+
+  /**
+   * Answers a shallow copy of the feature filters map
+   * 
+   * @return
+   */
+  public Map<String, KeyedMatcherSetI> getFeatureFilters();
+
+  /**
+   * Sets the filters for the feature type, or removes them if a null or empty
+   * filter is passed
+   * 
+   * @param featureType
+   * @param filter
+   */
+  void setFeatureFilter(String featureType, KeyedMatcherSetI filter);
+
+  /**
+   * Replaces all feature filters with the given map
+   * 
+   * @param filters
+   */
+  void setFeatureFilters(Map<String, KeyedMatcherSetI> filters);
+
+  /**
+   * Returns the colour for a particular feature instance. This includes
+   * calculation of 'colour by label', or of a graduated score colour, if
+   * applicable.
+   * <p>
+   * Returns null if
+   * <ul>
+   * <li>feature type is not visible, or</li>
+   * <li>feature group is not visible, or</li>
+   * <li>feature values lie outside any colour threshold, or</li>
+   * <li>feature is excluded by filter conditions</li>
+   * </ul>
+   * 
+   * @param feature
+   * @return
+   */
+  Color getColour(SequenceFeature feature);
 }
 }
index 1f47da3..6687e6a 100644 (file)
@@ -304,14 +304,16 @@ public class FeatureRenderer extends FeatureRendererModel
       List<SequenceFeature> overlaps = seq.getFeatures().findFeatures(
               visiblePositions.getBegin(), visiblePositions.getEnd(), type);
 
       List<SequenceFeature> overlaps = seq.getFeatures().findFeatures(
               visiblePositions.getBegin(), visiblePositions.getEnd(), type);
 
-      filterFeaturesForDisplay(overlaps, fc);
+      // filterFeaturesForDisplay(overlaps, fc);
 
       for (SequenceFeature sf : overlaps)
       {
 
       for (SequenceFeature sf : overlaps)
       {
-        Color featureColour = fc.getColor(sf);
+        Color featureColour = getColor(sf, fc);
         if (featureColour == null)
         {
         if (featureColour == null)
         {
-          // score feature outwith threshold for colouring
+          /*
+           * feature excluded by visibility settings, filters, or colour threshold
+           */
           continue;
         }
 
           continue;
         }
 
index 2f30e94..6461748 100644 (file)
@@ -30,6 +30,7 @@ import jalview.datamodel.features.SequenceFeatures;
 import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.schemes.FeatureColour;
 import jalview.util.ColorUtils;
 import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.schemes.FeatureColour;
 import jalview.util.ColorUtils;
+import jalview.util.matcher.KeyedMatcherSetI;
 
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
 
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
@@ -49,14 +50,25 @@ public abstract class FeatureRendererModel
         implements jalview.api.FeatureRenderer
 {
 
         implements jalview.api.FeatureRenderer
 {
 
-  /**
+  /*
    * global transparency for feature
    */
   protected float transparency = 1.0f;
 
    * global transparency for feature
    */
   protected float transparency = 1.0f;
 
-  protected Map<String, FeatureColourI> featureColours = new ConcurrentHashMap<String, FeatureColourI>();
+  /*
+   * colour scheme for each feature type
+   */
+  protected Map<String, FeatureColourI> featureColours = new ConcurrentHashMap<>();
+
+  /*
+   * visibility flag for each feature group
+   */
+  protected Map<String, Boolean> featureGroups = new ConcurrentHashMap<>();
 
 
-  protected Map<String, Boolean> featureGroups = new ConcurrentHashMap<String, Boolean>();
+  /*
+   * filters for each feature type
+   */
+  protected Map<String, KeyedMatcherSetI> featureFilters = new HashMap<>();
 
   protected String[] renderOrder;
 
 
   protected String[] renderOrder;
 
@@ -100,6 +112,7 @@ public abstract class FeatureRendererModel
     this.renderOrder = frs.renderOrder;
     this.featureGroups = frs.featureGroups;
     this.featureColours = frs.featureColours;
     this.renderOrder = frs.renderOrder;
     this.featureGroups = frs.featureGroups;
     this.featureColours = frs.featureColours;
+    this.featureFilters = frs.featureFilters;
     this.transparency = frs.transparency;
     this.featureOrder = frs.featureOrder;
     if (av != null && av != fr.getViewport())
     this.transparency = frs.transparency;
     this.featureOrder = frs.featureOrder;
     if (av != null && av != fr.getViewport())
@@ -557,20 +570,11 @@ public abstract class FeatureRendererModel
     return fc;
   }
 
     return fc;
   }
 
-  /**
-   * Returns the configured colour for a particular feature instance. This
-   * includes calculation of 'colour by label', or of a graduated score colour,
-   * if applicable. It does not take into account feature visibility or colour
-   * transparency. Returns null for a score feature whose score value lies
-   * outside any colour threshold.
-   * 
-   * @param feature
-   * @return
-   */
+  @Override
   public Color getColour(SequenceFeature feature)
   {
     FeatureColourI fc = getFeatureStyle(feature.getType());
   public Color getColour(SequenceFeature feature)
   {
     FeatureColourI fc = getFeatureStyle(feature.getType());
-    return fc.getColor(feature);
+    return getColor(feature, fc);
   }
 
   /**
   }
 
   /**
@@ -995,11 +999,11 @@ public abstract class FeatureRendererModel
   }
 
   /**
   }
 
   /**
-   * Removes from the list of features any that have a feature group that is not
-   * displayed, or duplicate the location of a feature of the same type (unless
-   * a graduated colour scheme or colour by label is applied). Should be used
-   * only for features of the same feature colour (which normally implies the
-   * same feature type).
+   * Removes from the list of features any that duplicate the location of a
+   * feature of the same type (unless feature is filtered out, or a graduated
+   * colour scheme or colour by label is applied). Should be used only for
+   * features of the same feature colour (which normally implies the same
+   * feature type).
    * 
    * @param features
    * @param fc
    * 
    * @param features
    * @param fc
@@ -1019,11 +1023,6 @@ public abstract class FeatureRendererModel
     while (it.hasNext())
     {
       SequenceFeature sf = it.next();
     while (it.hasNext())
     {
       SequenceFeature sf = it.next();
-      if (featureGroupNotShown(sf))
-      {
-        it.remove();
-        continue;
-      }
 
       /*
        * a feature is redundant for rendering purposes if it has the
 
       /*
        * a feature is redundant for rendering purposes if it has the
@@ -1045,4 +1044,88 @@ public abstract class FeatureRendererModel
     }
   }
 
     }
   }
 
+  @Override
+  public Map<String, KeyedMatcherSetI> getFeatureFilters()
+  {
+    return new HashMap<>(featureFilters);
+  }
+
+  @Override
+  public void setFeatureFilters(Map<String, KeyedMatcherSetI> filters)
+  {
+    featureFilters = filters;
+  }
+
+  @Override
+  public KeyedMatcherSetI getFeatureFilter(String featureType)
+  {
+    return featureFilters.get(featureType);
+  }
+
+  @Override
+  public void setFeatureFilter(String featureType, KeyedMatcherSetI filter)
+  {
+    if (filter == null || filter.isEmpty())
+    {
+      featureFilters.remove(featureType);
+    }
+    else
+    {
+      featureFilters.put(featureType, filter);
+    }
+  }
+
+  /**
+   * Answers the colour for the feature, or null if the feature is excluded by
+   * feature type or group visibility, by filters, or by colour threshold
+   * settings
+   * 
+   * @param sf
+   * @param fc
+   * @return
+   */
+  public Color getColor(SequenceFeature sf, FeatureColourI fc)
+  {
+    /*
+     * is the feature type displayed?
+     */
+    if (!showFeatureOfType(sf.getType()))
+    {
+      return null;
+    }
+
+    /*
+     * is the feature group displayed?
+     */
+    if (featureGroupNotShown(sf))
+    {
+      return null;
+    }
+
+    /*
+     * does the feature pass filters?
+     */
+    if (!featureMatchesFilters(sf))
+    {
+      return null;
+    }
+  
+    return fc.getColor(sf);
+  }
+
+  /**
+   * Answers true if there no are filters defined for the feature type, or this
+   * feature matches the filters. Answers false if the feature fails to match
+   * filters.
+   * 
+   * @param sf
+   * @return
+   */
+  protected boolean featureMatchesFilters(SequenceFeature sf)
+  {
+    KeyedMatcherSetI filter = featureFilters.get(sf.getType());
+    return filter == null ? true : filter.matches(key -> sf
+            .getValueAsString(key));
+  }
+
 }
 }
index dc2ae11..6afaa54 100644 (file)
@@ -22,8 +22,10 @@ package jalview.viewmodel.seqfeatures;
 
 import jalview.api.FeatureColourI;
 import jalview.schemes.FeatureColour;
 
 import jalview.api.FeatureColourI;
 import jalview.schemes.FeatureColour;
+import jalview.util.matcher.KeyedMatcherSetI;
 
 import java.util.Arrays;
 
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -42,6 +44,11 @@ public class FeatureRendererSettings implements Cloneable
    */
   Map<String, FeatureColourI> featureColours;
 
    */
   Map<String, FeatureColourI> featureColours;
 
+  /*
+   * map of {featureType, filters}
+   */
+  Map<String, KeyedMatcherSetI> featureFilters;
+
   float transparency;
 
   Map<String, Float> featureOrder;
   float transparency;
 
   Map<String, Float> featureOrder;
@@ -72,7 +79,9 @@ public class FeatureRendererSettings implements Cloneable
     renderOrder = null;
     featureGroups = new ConcurrentHashMap<String, Boolean>();
     featureColours = new ConcurrentHashMap<String, FeatureColourI>();
     renderOrder = null;
     featureGroups = new ConcurrentHashMap<String, Boolean>();
     featureColours = new ConcurrentHashMap<String, FeatureColourI>();
+    featureFilters = new HashMap<>();
     featureOrder = new ConcurrentHashMap<String, Float>();
     featureOrder = new ConcurrentHashMap<String, Float>();
+
     if (fr.renderOrder != null)
     {
       this.renderOrder = new String[fr.renderOrder.length];
     if (fr.renderOrder != null)
     {
       this.renderOrder = new String[fr.renderOrder.length];
@@ -100,6 +109,12 @@ public class FeatureRendererSettings implements Cloneable
         featureColours.put(next, new FeatureColour((FeatureColour) val));
       }
     }
         featureColours.put(next, new FeatureColour((FeatureColour) val));
       }
     }
+
+    if (fr.featureFilters != null)
+    {
+      this.featureFilters.putAll(fr.featureFilters);
+    }
+
     this.transparency = fr.transparency;
     if (fr.featureOrder != null)
     {
     this.transparency = fr.transparency;
     if (fr.featureOrder != null)
     {