import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeatures;
import jalview.renderer.seqfeatures.FeatureRenderer;
import jalview.schemes.FeatureColour;
import jalview.util.ColorUtils;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
return result;
}
+ /**
+ * 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 is applied)
+ *
+ * @param features
+ * @param fc
+ */
+ public void filterFeaturesForDisplay(List<SequenceFeature> features,
+ FeatureColourI fc)
+ {
+ if (features.isEmpty())
+ {
+ return;
+ }
+ SequenceFeatures.sortFeatures(features, true);
+ boolean graduated = fc != null && fc.isGraduatedColour();
+ SequenceFeature lastFeature = null;
+
+ Iterator<SequenceFeature> it = features.iterator();
+ while (it.hasNext())
+ {
+ SequenceFeature sf = it.next();
+ if (featureGroupNotShown(sf))
+ {
+ it.remove();
+ continue;
+ }
+
+ /*
+ * a feature is redundant for rendering purposes if it has the
+ * same extent as another (so would just redraw the same colour);
+ * (checking type and isContactFeature as a fail-safe here, although
+ * currently they are guaranteed to match in this context)
+ */
+ if (!graduated)
+ {
+ if (lastFeature != null && sf.getBegin() == lastFeature.getBegin()
+ && sf.getEnd() == lastFeature.getEnd()
+ && sf.isContactFeature() == lastFeature.isContactFeature()
+ && sf.getType().equals(lastFeature.getType()))
+ {
+ it.remove();
+ }
+ }
+ lastFeature = sf;
+ }
+ }
+
}
import jalview.schemes.FeatureColour;
import java.awt.Color;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
assertEquals(features.size(), 1);
assertTrue(features.contains(sf8));
}
+
+ @Test(groups = "Functional")
+ public void testFilterFeaturesForDisplay()
+ {
+ String seqData = ">s1\nabcdef\n";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
+ DataSourceType.PASTE);
+ AlignViewportI av = af.getViewport();
+ FeatureRenderer fr = new FeatureRenderer(av);
+
+ List<SequenceFeature> features = new ArrayList<>();
+ fr.filterFeaturesForDisplay(features, null); // empty list, does nothing
+
+ SequenceI seq = av.getAlignment().getSequenceAt(0);
+ SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, "group1");
+ seq.addSequenceFeature(sf1);
+ SequenceFeature sf2 = new SequenceFeature("Cath", "", 5, 11, "group2");
+ seq.addSequenceFeature(sf2);
+ SequenceFeature sf3 = new SequenceFeature("Cath", "", 5, 11, "group3");
+ seq.addSequenceFeature(sf3);
+ SequenceFeature sf4 = new SequenceFeature("Cath", "", 6, 8, "group4");
+ seq.addSequenceFeature(sf4);
+ SequenceFeature sf5 = new SequenceFeature("Cath", "", 6, 9, "group4");
+ seq.addSequenceFeature(sf5);
+
+ fr.findAllFeatures(true);
+
+ features = seq.getSequenceFeatures();
+ assertEquals(features.size(), 5);
+ assertTrue(features.contains(sf1));
+ assertTrue(features.contains(sf2));
+ assertTrue(features.contains(sf3));
+ assertTrue(features.contains(sf4));
+ assertTrue(features.contains(sf5));
+
+ /*
+ * filter out duplicate (co-located) features
+ * note: which gets removed is not guaranteed
+ */
+ fr.filterFeaturesForDisplay(features, new FeatureColour(Color.blue));
+ assertEquals(features.size(), 3);
+ assertTrue(features.contains(sf1) || features.contains(sf4));
+ assertFalse(features.contains(sf1) && features.contains(sf4));
+ assertTrue(features.contains(sf2) || features.contains(sf3));
+ assertFalse(features.contains(sf2) && features.contains(sf3));
+ assertTrue(features.contains(sf5));
+
+ /*
+ * hide group 3 - sf3 is removed, sf2 is retained
+ */
+ fr.setGroupVisibility("group3", false);
+ features = seq.getSequenceFeatures();
+ fr.filterFeaturesForDisplay(features, new FeatureColour(Color.blue));
+ assertEquals(features.size(), 3);
+ assertTrue(features.contains(sf1) || features.contains(sf4));
+ assertFalse(features.contains(sf1) && features.contains(sf4));
+ assertTrue(features.contains(sf2));
+ assertFalse(features.contains(sf3));
+ assertTrue(features.contains(sf5));
+
+ /*
+ * hide group 2, show group 3 - sf2 is removed, sf3 is retained
+ */
+ fr.setGroupVisibility("group2", false);
+ fr.setGroupVisibility("group3", true);
+ features = seq.getSequenceFeatures();
+ fr.filterFeaturesForDisplay(features, null);
+ assertEquals(features.size(), 3);
+ assertTrue(features.contains(sf1) || features.contains(sf4));
+ assertFalse(features.contains(sf1) && features.contains(sf4));
+ assertFalse(features.contains(sf2));
+ assertTrue(features.contains(sf3));
+ assertTrue(features.contains(sf5));
+
+ /*
+ * no filtering of co-located features with graduated colour scheme
+ * sf2 is removed as its group is hidden
+ */
+ features = seq.getSequenceFeatures();
+ fr.filterFeaturesForDisplay(features, new FeatureColour(Color.black,
+ Color.white, 0f, 1f));
+ assertEquals(features.size(), 4);
+ assertTrue(features.contains(sf1));
+ assertTrue(features.contains(sf3));
+ assertTrue(features.contains(sf4));
+ assertTrue(features.contains(sf5));
+
+ /*
+ * filtering of co-located features with colour by label
+ */
+ features = seq.getSequenceFeatures();
+ FeatureColour fc = new FeatureColour(Color.black);
+ fc.setColourByLabel(true);
+ fr.filterFeaturesForDisplay(features, fc);
+ assertEquals(features.size(), 3);
+ assertTrue(features.contains(sf1) || features.contains(sf4));
+ assertFalse(features.contains(sf1) && features.contains(sf4));
+ assertFalse(features.contains(sf2));
+ assertTrue(features.contains(sf3));
+ assertTrue(features.contains(sf5));
+ }
}