X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fviewmodel%2Fseqfeatures%2FFeatureRendererModel.java;fp=src%2Fjalview%2Fviewmodel%2Fseqfeatures%2FFeatureRendererModel.java;h=284ee4f928147af00463e052592539400c14b58a;hb=691e7f3e04f4ddc3ae858257f063a0b01be265fc;hp=f6addb877dfb8aa59c72745f410b5bef7b17db0a;hpb=aef3d5fa8e246dd69593b67de48e4f9de1699022;p=jalview.git diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index f6addb8..284ee4f 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -35,10 +35,10 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; 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; @@ -116,11 +116,10 @@ public abstract class FeatureRendererModel implements synchronized (fd) { fd.clear(); - java.util.Iterator fdisp = _fr.getFeaturesDisplayed() - .getVisibleFeatures(); - while (fdisp.hasNext()) + for (String type : _fr.getFeaturesDisplayed() + .getVisibleFeatures()) { - fd.setVisible(fdisp.next()); + fd.setVisible(type); } } } @@ -266,48 +265,39 @@ public abstract class FeatureRendererModel implements @Override public List findFeaturesAtRes(SequenceI sequence, int res) { - ArrayList tmp = new ArrayList(); - SequenceFeature[] features = sequence.getSequenceFeatures(); - - if (features != null) + List result = new ArrayList(); + if (!av.areFeaturesDisplayed()) { - for (int i = 0; i < features.length; i++) - { - if (!av.areFeaturesDisplayed() - || !av.getFeaturesDisplayed().isVisible( - features[i].getType())) - { - continue; - } + return result; + } - if (features[i].featureGroup != null - && featureGroups != null - && featureGroups.containsKey(features[i].featureGroup) - && !featureGroups.get(features[i].featureGroup) - .booleanValue()) - { - continue; - } + Set visibleFeatures = getFeaturesDisplayed() + .getVisibleFeatures(); + String[] visibleTypes = visibleFeatures + .toArray(new String[visibleFeatures.size()]); - // check if start/end are at res, and if not a contact feature, that res - // lies between start and end - if ((features[i].getBegin() == res || features[i].getEnd() == res) - || (!features[i].isContactFeature() - && (features[i].getBegin() < res) && (features[i] - .getEnd() >= res))) - { - tmp.add(features[i]); - } + /* + * include features at the position provided their feature type is + * displayed, and feature group is null or marked for display + */ + List features = sequence.getFeatures().findFeatures( + res, res, visibleTypes); + + for (SequenceFeature sf : features) + { + if (!featureGroupNotShown(sf)) + { + result.add(sf); } } - return tmp; + return result; } /** * Searches alignment for all features and updates colours * * @param newMadeVisible - * if true newly added feature types will be rendered immediatly + * if true newly added feature types will be rendered immediately * TODO: check to see if this method should actually be proxied so * repaint events can be propagated by the renderer code */ @@ -329,8 +319,7 @@ public abstract class FeatureRendererModel implements } FeaturesDisplayedI featuresDisplayed = av.getFeaturesDisplayed(); - ArrayList allfeatures = new ArrayList(); - ArrayList oldfeatures = new ArrayList(); + Set oldfeatures = new HashSet(); if (renderOrder != null) { for (int i = 0; i < renderOrder.length; i++) @@ -341,107 +330,150 @@ public abstract class FeatureRendererModel implements } } } - if (minmax == null) - { - minmax = new Hashtable(); - } - - Set oldGroups = new HashSet(featureGroups.keySet()); + // <<<<<<< HEAD + // + // ======= + // if (minmax == null) + // { + // minmax = new Hashtable(); + // } + // + // Set oldGroups = new HashSet(featureGroups.keySet()); + // >>>>>>> refs/heads/develop AlignmentI alignment = av.getAlignment(); + List allfeatures = new ArrayList(); // or HashSet? + for (int i = 0; i < alignment.getHeight(); i++) { SequenceI asq = alignment.getSequenceAt(i); - SequenceFeature[] features = asq.getSequenceFeatures(); - - if (features == null) + for (String group : asq.getFeatures().getFeatureGroups(true)) { - continue; - } - - int index = 0; - while (index < features.length) - { - String fgrp = features[index].getFeatureGroup(); - oldGroups.remove(fgrp); - if (!featuresDisplayed.isRegistered(features[index].getType())) + // <<<<<<< HEAD + /* + * features in null group are always displayed; other groups + * keep their current visibility; new groups as 'newMadeVisible' + */ + boolean groupDisplayed = true; + if (group != null) + // ======= + // continue; + // } + // + // int index = 0; + // while (index < features.length) + // { + // String fgrp = features[index].getFeatureGroup(); + // oldGroups.remove(fgrp); + // if (!featuresDisplayed.isRegistered(features[index].getType())) + // >>>>>>> refs/heads/develop { - if (fgrp != null) + // <<<<<<< HEAD + if (featureGroups.containsKey(group)) + // ======= + // if (fgrp != null) + // >>>>>>> refs/heads/develop { - Boolean groupDisplayed = featureGroups.get(fgrp); - if (groupDisplayed == null) - { - groupDisplayed = Boolean.valueOf(newMadeVisible); - featureGroups.put(fgrp, groupDisplayed); - } - if (!groupDisplayed.booleanValue()) - { - index++; - continue; - } + groupDisplayed = featureGroups.get(group); } - if (!(features[index].begin == 0 && features[index].end == 0)) + else { - // If beginning and end are 0, the feature is for the whole sequence - // and we don't want to render the feature in the normal way - - if (newMadeVisible - && !oldfeatures.contains(features[index].getType())) - { - // this is a new feature type on the alignment. Mark it for - // display. - featuresDisplayed.setVisible(features[index].getType()); - setOrder(features[index].getType(), 0); - } + groupDisplayed = newMadeVisible; + featureGroups.put(group, groupDisplayed); } } - if (!allfeatures.contains(features[index].getType())) + if (groupDisplayed) { - allfeatures.add(features[index].getType()); - } - if (!Float.isNaN(features[index].score)) - { - int nonpos = features[index].getBegin() >= 1 ? 0 : 1; - float[][] mm = minmax.get(features[index].getType()); - if (mm == null) - { - mm = new float[][] { null, null }; - minmax.put(features[index].getType(), mm); - } - if (mm[nonpos] == null) - { - mm[nonpos] = new float[] { features[index].score, - features[index].score }; - - } - else + Set types = asq.getFeatures().getFeatureTypesForGroups( + true, group); + for (String type : types) { - if (mm[nonpos][0] > features[index].score) - { - mm[nonpos][0] = features[index].score; - } - if (mm[nonpos][1] < features[index].score) + if (!allfeatures.contains(type)) // or use HashSet and no test? { - mm[nonpos][1] = features[index].score; + allfeatures.add(type); } + updateMinMax(asq, type, true); // todo: for all features? } } - index++; } } /* - * oldGroups now consists of groups that no longer - * have any feature in them - remove these + //<<<<<<< HEAD + * mark any new feature types as visible */ - for (String grp : oldGroups) + Collections.sort(allfeatures, String.CASE_INSENSITIVE_ORDER); + if (newMadeVisible) { - featureGroups.remove(grp); + for (String type : allfeatures) + { + if (!oldfeatures.contains(type)) + { + featuresDisplayed.setVisible(type); + setOrder(type, 0); + } + } + // ======= + // * oldGroups now consists of groups that no longer + // * have any feature in them - remove these + // */ + // for (String grp : oldGroups) + // { + // featureGroups.remove(grp); + // >>>>>>> refs/heads/develop } updateRenderOrder(allfeatures); findingFeatures = false; } + /** + * Updates the global (alignment) min and max values for a feature type from + * the score for a sequence, if the score is not NaN. Values are stored + * separately for positional and non-positional features. + * + * @param seq + * @param featureType + * @param positional + */ + protected void updateMinMax(SequenceI seq, String featureType, + boolean positional) + { + float min = seq.getFeatures().getMinimumScore(featureType, positional); + if (Float.isNaN(min)) + { + return; + } + + float max = seq.getFeatures().getMaximumScore(featureType, positional); + + /* + * stored values are + * { {positionalMin, positionalMax}, {nonPositionalMin, nonPositionalMax} } + */ + if (minmax == null) + { + minmax = new Hashtable(); + } + synchronized (minmax) + { + float[][] mm = minmax.get(featureType); + int index = positional ? 0 : 1; + if (mm == null) + { + mm = new float[][] { null, null }; + minmax.put(featureType, mm); + } + if (mm[index] == null) + { + mm[index] = new float[] { min, max }; + } + else + { + mm[index][0] = Math.min(mm[index][0], min); + mm[index][1] = Math.max(mm[index][1], max); + } + } + } protected Boolean firing = Boolean.FALSE; /** @@ -578,6 +610,13 @@ public abstract class FeatureRendererModel implements return fc.getColor(feature); } + /** + * Answers true unless the feature has a graduated colour scheme and the + * feature value lies outside the current threshold for display + * + * @param sequenceFeature + * @return + */ protected boolean showFeature(SequenceFeature sequenceFeature) { FeatureColourI fc = getFeatureStyle(sequenceFeature.type); @@ -671,7 +710,8 @@ public abstract class FeatureRendererModel implements } /** - * Sets the priority order for features + * Sets the priority order for features, with the highest priority (displayed + * on top) at the start of the data array * * @param data * { String(Type), Colour(Type), Boolean(Displayed) } @@ -895,11 +935,10 @@ public abstract class FeatureRendererModel implements { return fcols; } - Iterator features = getViewport().getFeaturesDisplayed() + Set features = getViewport().getFeaturesDisplayed() .getVisibleFeatures(); - while (features.hasNext()) + for (String feature : features) { - String feature = features.next(); fcols.put(feature, getFeatureStyle(feature)); } return fcols; @@ -962,4 +1001,21 @@ public abstract class FeatureRendererModel implements return _gps; } + /** + * Answers true if the feature belongs to a feature group which is not + * currently displayed, else false + * + * @param sequenceFeature + * @return + */ + protected boolean featureGroupNotShown(final SequenceFeature sequenceFeature) + { + return featureGroups != null + && sequenceFeature.featureGroup != null + && sequenceFeature.featureGroup.length() != 0 + && featureGroups.containsKey(sequenceFeature.featureGroup) + && !featureGroups.get(sequenceFeature.featureGroup) + .booleanValue(); + } + }