Skip to content

Commit

Permalink
Allow specification of property / attribute for feature names. Fixes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobinso committed May 26, 2022
1 parent 6fa75bf commit b1b0824
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 77 deletions.
5 changes: 5 additions & 0 deletions src/main/java/org/broad/igv/feature/AbstractFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ public String getName() {
return name;
}

public String getDisplayName(String property) {
String nm = getAttribute(property);
return nm == null ? getName() : nm;
}

public boolean hasExons() {
return false;
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/broad/igv/feature/NamedFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@
public interface NamedFeature extends Feature {

String getName();

default String getDisplayName(String property) {
return getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.broad.igv.feature.*;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.feature.genome.Sequence;
import org.broad.igv.feature.genome.SequenceWrapper;
import org.broad.igv.feature.genome.fasta.FastaBlockCompressedSequence;
import org.broad.igv.feature.genome.fasta.FastaIndexedSequence;
import org.broad.igv.feature.gff.GFFFeatureSource;
Expand Down Expand Up @@ -70,7 +69,7 @@ private static FeatureTrack createGeneTrack(Genome genome, BufferedReader reader
if (props != null) {
geneFeatureTrack.setProperties(parser.getTrackProperties());
}
geneFeatureTrack.setUrl(annotationURL);
geneFeatureTrack.setFeatureInfoURL(annotationURL);
}
}
return geneFeatureTrack;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public BasicFeature decode(String nextLine) {
strand = Strand.NONE;
}
feature.setStrand(strand);

// Store the remaining features in description string */
Map<String, String> attributes = new LinkedHashMap<>();
if (tokens.length > 6) attributes.put("signalValue", tokens[6]);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/broad/igv/prefs/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ private Constants() {
// Generic track options
public static final String BYPASS_FILE_AUTO_DISCOVERY = "BYPASS_FILE_AUTO_DISCOVERY";
public static final String TRACK_ATTRIBUTE_NAME_KEY = "TRACK_ATTRIBUTE_NAME_KEY";

public static final String FEATURE_NAME_PROPERTY = "FEATURE_NAME_PROPERTY";
public static final String INITIAL_TRACK_HEIGHT = "15";
public static final String COLOR_SCALE_KEY = "COLOR_SCALE_";
public static final String TRACK_HEIGHT_KEY = "IGV.track.height";
Expand Down
40 changes: 19 additions & 21 deletions src/main/java/org/broad/igv/renderer/IGVFeatureRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public void render(List<IGVFeature> featureList,
boolean alternateExonColor = (track instanceof FeatureTrack && ((FeatureTrack) track).isAlternateExonColor());
Color trackPosColor = track.getColor();
Color trackNegColor = alternateExonColor ? track.getColor() : track.getAltColor();

String featureNameProperty = track.getLabelField();

for (IGVFeature feature : featureList) {

Expand Down Expand Up @@ -204,7 +204,7 @@ public void render(List<IGVFeature> featureList,
hasExons = bf.hasExons();
}

// Add directional arrows and exons, if there is room.
// Add directional arrows and exons, if there is room.
int pixelYCenter = trackRectangle.y + NORMAL_STRAND_Y_OFFSET / 2;

if (hasExons) {
Expand Down Expand Up @@ -234,7 +234,7 @@ public void render(List<IGVFeature> featureList,
Color peakColor = c == Color.cyan ? Color.red : Color.cyan;
g2D.setColor(peakColor);
int pw = Math.min(4, pixelWidth / 5);
g2D.fillRect(peakPixelPosition - pw/2, pixelYCenter - thinBlockHeight/2 - 1, pw, thinBlockHeight + 2);
g2D.fillRect(peakPixelPosition - pw / 2, pixelYCenter - thinBlockHeight / 2 - 1, pw, thinBlockHeight + 2);
g2D.setColor(c);
}
} catch (NumberFormatException e) {
Expand All @@ -246,7 +246,10 @@ public void render(List<IGVFeature> featureList,

// Draw name , if there is room
if (displayMode != Track.DisplayMode.SQUISHED && track.isShowFeatureNames()) {
String name = feature.getName();

String name = featureNameProperty != null ?
feature.getDisplayName(featureNameProperty) : feature.getName();

if (name != null) {
// Limit name display length
if (name.length() >= MAX_NAME_LENGTH) {
Expand All @@ -270,7 +273,7 @@ public void render(List<IGVFeature> featureList,
int verticalSpaceRequiredForText = textBaselineY - (int) trackRectangleY;

if (verticalSpaceRequiredForText <= trackRectangle.height) {
lastNamePixelEnd = drawFeatureName(feature, track.getDisplayMode(), nameStart, nameEnd,
lastNamePixelEnd = drawFeatureName(name, track.getDisplayMode(), nameStart, nameEnd,
lastNamePixelEnd, fontGraphics, textBaselineY);
}
}
Expand Down Expand Up @@ -544,7 +547,7 @@ protected void drawStrandArrows(Strand strand,

// Don't draw strand arrows for very small regions
// Limit drawing to visible region, we don't really know the viewport pEnd,
if ((endX - startX) < 6) {
if ((endX - startX) < 6) {
return;
}

Expand Down Expand Up @@ -579,19 +582,14 @@ protected void drawStrandArrows(Strand strand,

}

final private int drawFeatureName(IGVFeature feature,
final private int drawFeatureName(String name,
Track.DisplayMode mode,
int pixelStart,
int pixelEnd,
int lastFeatureEndedAtPixelX,
Graphics2D g2D,
int textBaselineY) {

String name = feature.getName();
if (name == null) {
return lastFeatureEndedAtPixelX;
}

FontMetrics fm = g2D.getFontMetrics();
int fontSize = fm.getFont().getSize();
int nameWidth = fm.stringWidth(name);
Expand Down Expand Up @@ -623,7 +621,7 @@ final private int drawFeatureName(IGVFeature feature,
* @param locationScale
* @param yOffset
* @param trackRectangle
* @param idx exon index
* @param idx exon index
*/
public void labelAminoAcids(int pStart, Graphics2D fontGraphics, double theOrigin,
RenderContext context, IGVFeature gene, double locationScale,
Expand All @@ -632,16 +630,16 @@ public void labelAminoAcids(int pStart, Graphics2D fontGraphics, double theOrigi
Genome genome = GenomeManager.getInstance().getCurrentGenome();
Exon exon = gene.getExons().get(idx);

Exon prevExon = idx == 0 ? null : gene.getExons().get(idx-1);
Exon nextExon = (idx+1) < gene.getExons().size() ?gene.getExons().get(idx+1) : null;
Exon prevExon = idx == 0 ? null : gene.getExons().get(idx - 1);
Exon nextExon = (idx + 1) < gene.getExons().size() ? gene.getExons().get(idx + 1) : null;

AminoAcidSequence aaSequence = exon.getAminoAcidSequence(genome, prevExon, nextExon);

if ((aaSequence != null) && aaSequence.hasNonNullSequence()) {
Rectangle aaRect = new Rectangle(pStart, yOffset - blockHeight / 2, 1, blockHeight);

int aaSeqStartPosition = aaSequence.getStart();
boolean odd = exon.getAminoAcidNumber(exon.getCdStart()) % 2 == 1;
boolean odd = exon.getAminoAcidNumber(exon.getCdStart()) % 2 == 1;

for (CodonAA acid : aaSequence.getSequence()) {
if (acid != null) {
Expand Down Expand Up @@ -704,20 +702,20 @@ public String getDisplayName() {
protected Color getFeatureColor(IGVFeature feature, Track track, Color defaultPosColor, Color defaultNegColor) {

// Set color used to draw the feature
Color color = null;
Color color = null;

// If an alt color is explicitly set use it for negative strand features;
if(feature.getStrand() == Strand.NEGATIVE) {
if (feature.getStrand() == Strand.NEGATIVE) {
color = track.getExplicitAltColor();
}

// If color is explicitly set use it
if(color == null) {
color = track.getExplicitColor();
if (color == null) {
color = track.getExplicitColor();
}

// No explicitly set color, try the feature itself
if(color == null && track.isItemRGB()) {
if (color == null && track.isItemRGB()) {
color = feature.getColor();
}

Expand Down
21 changes: 6 additions & 15 deletions src/main/java/org/broad/igv/track/AbstractTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public abstract class AbstractTrack implements Track {

private String attributeKey;
private String name;
private String url;
private String featureInfoURL;
private boolean itemRGB = true;

private boolean useScore;
Expand Down Expand Up @@ -150,12 +150,12 @@ public void setRendererClass(Class rc) {
// Ignore by default
}

public String getUrl() {
return url;
public String getFeatureInfoURL() {
return featureInfoURL;
}

public void setUrl(String url) {
this.url = url;
public void setFeatureInfoURL(String featureInfoURL) {
this.featureInfoURL = featureInfoURL;
}

public void setUseScore(boolean useScore) {
Expand Down Expand Up @@ -193,11 +193,6 @@ public void setSampleId(String sampleId) {
this.sampleId = sampleId;
}

@Override
public boolean isFilterable() {
return true; // True by default
}

public void renderName(Graphics2D g2D, Rectangle trackRectangle, Rectangle visibleRectangle) {

Rectangle rect = getDisplayableRect(trackRectangle, visibleRectangle);
Expand Down Expand Up @@ -503,10 +498,6 @@ public int getHeight() {
return (height < 0) ? getDefaultHeight() : height;
}

public boolean hasDataRange() {
return dataRange != null;
}

public DataRange getDataRange() {
if (dataRange == null) {
// Use the color scale if there is one
Expand Down Expand Up @@ -679,7 +670,7 @@ public void setProperties(TrackProperties properties) {
setWindowFunction(properties.getWindowingFunction());
}
if (properties.getUrl() != null) {
setUrl(properties.getUrl());
setFeatureInfoURL(properties.getUrl());
}

Map<String, String> attributes = properties.getAttributes();
Expand Down
21 changes: 17 additions & 4 deletions src/main/java/org/broad/igv/track/FeatureTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
import java.util.List;
import java.util.stream.Collectors;

import static org.broad.igv.feature.FeatureUtils.FEATURE_CENTER_COMPARATOR;

/**
* Track which displays features, typically showing regions of the genome
* in a qualitative way. Features are rendered using the specified FeatureRenderer.
Expand Down Expand Up @@ -119,6 +117,7 @@ public class FeatureTrack extends AbstractTrack implements IGVEventObserver {
private String trackLine = null;

private boolean groupByStrand = false;
private String labelField;

public FeatureTrack() {

Expand Down Expand Up @@ -445,7 +444,7 @@ public String getValueStringAt(String chr, double position, int mouseX, int mous
private String getFeatureURL(IGVFeature igvFeature) {
String url = igvFeature.getURL();
if (url == null) {
String trackURL = getUrl();
String trackURL = getFeatureInfoURL();
if (trackURL != null && igvFeature.getName() != null) {
String encodedID = StringUtils.encodeURL(igvFeature.getName());
url = trackURL.replaceAll("\\$\\$", encodedID);
Expand All @@ -454,6 +453,14 @@ private String getFeatureURL(IGVFeature igvFeature) {
return url;
}

@Override
public String getLabelField() {
return labelField;
}

public void setLabelField(String labelField) {
this.labelField = labelField;
}

/**
* Get all features which overlap the specified locus
Expand Down Expand Up @@ -1036,7 +1043,9 @@ public boolean isGroupByStrand() {
@Override
public void marshalXML(Document document, Element element) {
element.setAttribute("groupByStrand", String.valueOf(groupByStrand));

if (labelField != null) {
element.setAttribute("featureNameProperty", labelField);
}
super.marshalXML(document, element);

}
Expand All @@ -1046,6 +1055,10 @@ public void unmarshalXML(Element element, Integer version) {

super.unmarshalXML(element, version);

if (element.hasAttribute("featureNameProperty")) {
this.labelField = element.getAttribute("featureNameProperty");
}

this.groupByStrand = "true".equals(element.getAttribute("groupByStrand"));

NodeList tmp = element.getElementsByTagName("SequenceMatchSource");
Expand Down
5 changes: 0 additions & 5 deletions src/main/java/org/broad/igv/track/MutationTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ public MutationTrack(ResourceLocator locator, String id, FeatureSource source) {
public MutationTrack() {
}

@Override
public boolean isFilterable() {
return true; // Mutation tracks, unlike most FeatureTrack types, can be filtered
}

@Override
public void overlay(RenderContext context, Rectangle rect) {
if (!context.getChr().equals(Globals.CHR_ALL) ||
Expand Down
18 changes: 14 additions & 4 deletions src/main/java/org/broad/igv/track/Track.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ enum DisplayMode {
*
* @return
*/
boolean isFilterable();
default boolean isFilterable() {
return true;
}


/**
Expand Down Expand Up @@ -128,7 +130,7 @@ void renderAttributes(Graphics2D graphics, Rectangle trackRectangle, Rectangle v

String getSample();

void setUrl(String url);
void setFeatureInfoURL(String featureInfoURL);

ResourceLocator getResourceLocator();

Expand Down Expand Up @@ -182,8 +184,6 @@ default boolean isNumeric() {
*/
void setDataRange(DataRange axisDefinition);

boolean hasDataRange();

DataRange getDataRange();

Color getColor();
Expand Down Expand Up @@ -276,6 +276,16 @@ default Color getExplicitAltColor() {

default void setShowFeatureNames(boolean b) {}

/**
* Return the java property or attribute for the feature display name. Default is "null", in which case the
* feature "name" property will be used.
*
* @return
*/
default String getLabelField() {
return null;
}

default void repaint() {
IGV.getInstance().repaint(this);
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/broad/igv/track/TrackLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,10 @@ public List<Track> load(ResourceLocator locator, Genome genome) throws DataLoadE

for (Track track : newTracks) {
if (locator.getFeatureInfoURL() != null) {
track.setUrl(locator.getFeatureInfoURL());
track.setFeatureInfoURL(locator.getFeatureInfoURL());
}
if (locator.getLabelField() != null && track instanceof FeatureTrack) {
((FeatureTrack) track).setLabelField(locator.getLabelField());
}
if (tp != null) {
track.setProperties(tp);
Expand Down
Loading

0 comments on commit b1b0824

Please sign in to comment.