Skip to content

Commit

Permalink
improve "hit testing" for clicks over features, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobinso committed Sep 29, 2023
1 parent b8e4abe commit ef76fb0
Show file tree
Hide file tree
Showing 9 changed files with 27 additions and 45 deletions.
31 changes: 15 additions & 16 deletions src/main/java/org/broad/igv/feature/FeatureUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ public static void sortFeatureList(List<? extends Feature> features) {
* Return a feature from the supplied list whose extent, expanded by "buffer", contains the given position.
*
* @param position 0-based genomic position to which to search for feature
* @param buffer search region. The first feature which contains the start position, (expanded by buffer, inclusive)
* will be accepted.
* @param bpPerPixel current resolution in base pairs per pixel.
* @param features
* @return
*/
public static <T extends Feature> T getFeatureAt(double position, int buffer, List<? extends T> features) {
public static <T extends Feature> T getFeatureAt(double position, double bpPerPixel, List<? extends T> features) {

int startIdx = 0;
int endIdx = features.size();
int buffer = (int) (2 * bpPerPixel);

while (startIdx != endIdx) {
int idx = (startIdx + endIdx) / 2;
Expand Down Expand Up @@ -367,34 +367,33 @@ public static int getIndexBeforeOld(double position, List<? extends Feature> fea


/**
* Return all features from the supplied list who's extent, expanded to "minWidth" if needed, contains the given position
* Return all features from the supplied list who's extent, expanded by "flanking", intersect the position
*
* @param position
* @param maxLength -- the distance back from position at which to start search (the maximum feature length)
* @param minWidth -- the minimum effective width of the feature
* @param flanking -- the minimum effective width of the feature
* @param features
* @return
*/
public static List<Feature> getAllFeaturesAt(double position,
double maxLength,
double minWidth,
double flanking,
List<? extends htsjdk.tribble.Feature> features) {

List<Feature> returnList = null;

double adjustedPosition = Math.max(0, position - maxLength);
int startIdx = Math.max(0, getIndexBefore(adjustedPosition, features));

int startIdx = Math.max(0, getIndexBefore(position - flanking, features));
double start = position - (flanking / 2);
double end = position + (flanking / 2);
for (int idx = startIdx; idx < features.size(); idx++) {
Feature feature = features.get(idx);
double start = feature.getStart() - (minWidth / 2);
if (start > position) {
break;
}
double end = feature.getEnd() + (minWidth / 2);
if (position >= start && position <= end) {
if(feature.getEnd() >= start && feature.getStart() <= end) {
if (returnList == null) returnList = new ArrayList();
returnList.add(feature);
}

if (feature.getStart() > end) {
break;
}
}

// Sort features by distance from position (features closest to position listed first)
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/org/broad/igv/sam/AlignmentTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -875,8 +875,7 @@ Alignment getAlignmentAt(double position, int y, ReferenceFrame frame) {
List<Alignment> features = row.alignments;

// No buffer for alignments, you must zoom in far enough for them to be visible
int buffer = 0;
return FeatureUtils.getFeatureAt(position, buffer, features);
return FeatureUtils.getFeatureAt(position, 0, features);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/sam/CoverageTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ private String getPrecomputedValueString(String chr, double position, ReferenceF
if (scores == null) {
return "";
} else {
LocusScore score = (LocusScore) FeatureUtils.getFeatureAt(position, 0, scores);
LocusScore score = FeatureUtils.getFeatureAt(position, 0, scores);
return score == null ? "" : "Mean count: " + score.getScore();
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/org/broad/igv/track/DataTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,7 @@ private LocusScore getLocusScoreAt(String chr, double position, ReferenceFrame f
return null;
} else {
// give a 2 pixel window, otherwise very narrow features will be missed.
double bpPerPixel = frame.getScale();
int buffer = (int) (2 * bpPerPixel); /* * */
return (LocusScore) FeatureUtils.getFeatureAt(position, buffer, scores);
return FeatureUtils.getFeatureAt(position, frame.getScale(), scores);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,10 @@ public String getValueString(String chr, double position, ReferenceFrame frame)
int zoom = Math.max(0, frame.getZoom());
List<LocusScore> scores = getSummaryScoresForRange(chr, (int) position - 10, (int) position + 10, zoom);

// give a 2 pixel window, otherwise very narrow features will be missed.
double bpPerPixel = frame.getScale();
int minWidth = (int) (2 * bpPerPixel); /* * */

if (scores == null) {
return "";
} else {
LocusScore score = (LocusScore) FeatureUtils.getFeatureAt(position, minWidth, scores);
LocusScore score = (LocusScore) FeatureUtils.getFeatureAt(position, frame.getScale(), scores);
return score == null ? "" : "Mean count: " + score.getScore();
}
}
Expand Down
10 changes: 3 additions & 7 deletions src/main/java/org/broad/igv/track/FeatureTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,7 @@ public String getValueStringAt(String chr, double position, int mouseX, int mous
if (scores == null) {
return "";
} else {
// give a +/- 2 pixel buffer, otherwise very narrow features will be missed.
double bpPerPixel = frame.getScale();
int minWidth = (int) (2 * bpPerPixel); /* * */
LocusScore score = (LocusScore) FeatureUtils.getFeatureAt(position, minWidth, scores);
LocusScore score = FeatureUtils.getFeatureAt(position, frame.getScale(), scores);
return score == null ? null : "Mean count: " + score.getScore();
}

Expand Down Expand Up @@ -558,9 +555,8 @@ public List<Feature> getFeaturesAtPositionInFeatureRow(double position, int feat
if (possFeatures != null) {
// give a minum 2 pixel or 1/2 bp window, otherwise very narrow features will be missed.
double bpPerPixel = frame.getScale();
double minWidth = Math.max(2, 3 * bpPerPixel);
int maxFeatureLength = packedFeatures.getMaxFeatureLength();
featureList = FeatureUtils.getAllFeaturesAt(position, maxFeatureLength, minWidth, possFeatures);
double minWidth = (int) (2* bpPerPixel);
featureList = FeatureUtils.getAllFeaturesAt(position, minWidth, possFeatures);
}
return featureList;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/broad/igv/track/GisticTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -360,13 +360,13 @@ public String getValueStringAt(String chr, double position, int mouseX, int igno
LocusScore amp = null;
List<GisticScore> ampScores = ampScoreMap.get(chr);
if (ampScores != null) {
amp = (LocusScore) FeatureUtils.getFeatureAt(position, 0, ampScores);
amp = FeatureUtils.getFeatureAt(position, 0, ampScores);
}

LocusScore del = null;
List<GisticScore> delScores = delScoreMap.get(chr);
if (delScores != null) {
del = (LocusScore) FeatureUtils.getFeatureAt(position, 0, delScores);
del = FeatureUtils.getFeatureAt(position, 0, delScores);
}

if ((amp == null) && (del == null)) {
Expand Down
6 changes: 1 addition & 5 deletions src/main/java/org/broad/igv/track/TribbleFeatureSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -578,14 +578,10 @@ public String getValueString(String chr, double position, ReferenceFrame frame)
int zoom = Math.max(0, frame.getZoom());
List<LocusScore> scores = getSummaryScoresForRange(chr, (int) position - 10, (int) position + 10, zoom);

// give a 2 pixel window, otherwise very narrow features will be missed.
double bpPerPixel = frame.getScale();
int minWidth = (int) (2 * bpPerPixel); /* * */

if (scores == null) {
return "";
} else {
LocusScore score = (LocusScore) FeatureUtils.getFeatureAt(position, minWidth, scores);
LocusScore score = FeatureUtils.getFeatureAt(position, frame.getScale(), scores);
return score == null ? "" : "Mean count: " + score.getScore();
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/test/java/org/broad/igv/feature/FeatureUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@ public void testGetFeatureClosestWithIndels(){
public void testGetAllFeaturesAt() {

int position = 56078756;
int maxLength = 100000;


List<Feature> result = FeatureUtils.getAllFeaturesAt(position, maxLength, 0, featureList);
double flanking = 0;
List<Feature> result = FeatureUtils.getAllFeaturesAt(position, flanking, featureList);
assertEquals(21, result.size());
for (Feature f : result) {
assertTrue(position >= f.getStart() && position <= f.getEnd());
Expand Down

0 comments on commit ef76fb0

Please sign in to comment.