Skip to content

Commit

Permalink
Implement user preferences for base modification threshold and colors
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobinso committed Aug 1, 2023
1 parent 76ca0be commit 3b144d8
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 93 deletions.
64 changes: 42 additions & 22 deletions src/main/java/org/broad/igv/prefs/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ private Constants() {
public static final String LAST_GENOME_IMPORT_DIRECTORY = "LAST_GENOME_IMPORT_DIRECTORY";
public static final String DEFINE_GENOME_INPUT_DIRECTORY_KEY = "DEFINE_GENOME_INPUT_DIRECTORY_KEY";
public static final String DEFAULT_GENOME = "DEFAULT_GENOME_KEY";
public static final String AUTO_UPDATE_GENOMES = "AUTO_UPDATE_GENOMES";
public static final String FRAME_BOUNDS_KEY = "IGV.Bounds";


Expand Down Expand Up @@ -112,7 +111,6 @@ private Constants() {
public static final String SAM_SHADE_QUALITY_HIGH = "SAM.SHADE_QUALITY_HIGH";
public static final String SAM_SHADE_ALIGNMENT_BY = "SAM.SHADE_ALIGNMENT_BY";
public static final String SAM_ALIGNMENT_SCORE_THRESHOLD = "SAM.ALIGNMENT_SCORE_THRESHOLD";
public static final String SAM_BASEMOD_THRESHOLD = "SAM.BASEMOD_THRESHOLD";
public static final String SAM_COMPUTE_ISIZES = "SAM.COMPUTE_ISIZES";
public static final String SAM_MAX_INSERT_SIZE_THRESHOLD = "SAM.INSERT_SIZE_THRESHOLD";
public static final String SAM_MIN_INSERT_SIZE_THRESHOLD = "SAM.MIN_INSERT_SIZE_THRESHOLD";
Expand Down Expand Up @@ -183,6 +181,25 @@ private Constants() {
public static final String SAM_DISPLAY_PAIRED = "SAM.DISPLAY_PAIRED";
public static final String KNOWN_SNPS = "KNOWN_SNPS_FILE";


// Base modification settings
public static final String BASEMOD_THRESHOLD = "BASEMOD.THRESHOLD";
public static final String BASEMOD_M_COLOR = "BASEMOD.M_COLOR";
public static final String BASEMOD_H_COLOR = "BASEMOD.H_COLOR";
public static final String BASEMOD_F_COLOR = "BASEMOD.F_COLOR";
public static final String BASEMOD_C_COLOR = "BASEMOD.C_COLOR";
public static final String BASEMOD_G_COLOR = "BASEMOD.G_COLOR";
public static final String BASEMOD_E_COLOR = "BASEMOD.E_COLOR";
public static final String BASEMOD_B_COLOR = "BASEMOD.B_COLOR";
public static final String BASEMOD_A_COLOR = "BASEMOD.A_COLOR";
public static final String BASEMOD_O_COLOR = "BASEMOD.O_COLOR";
public static final String BASEMOD_OTHER_COLOR = "BASEMOD.OTHER_COLOR";

public static final String BASEMOD_NONE_A_COLOR = "BASEMOD.NONE_A_COLOR";
public static final String BASEMOD_NONE_C_COLOR = "BASEMOD.NONE_C_COLOR";
public static final String BASEMOD_NONE_T_COLOR = "BASEMOD.NONE_T_COLOR";
public static final String BASEMOD_NONE_G_COLOR = "BASEMOD.NONE_G_COLOR";
public static final String BASEMOD_NONE_N_COLOR = "BASEMOD.NONE_N_COLOR";
public static final String SMRT_KINETICS_SHOW_OPTIONS = "SMRT_KINETICS.SHOW_OPTIONS";

// Sequence track settings
Expand Down Expand Up @@ -242,25 +259,10 @@ private Constants() {
public static final String PROBE_MAPPING_FILE = "PROBE_MAPPING_FILE";
public static final String USE_PROBE_MAPPING_FILE = "USE_PROBE_MAPPING_FILE";

// Genome space
public static final String GENOME_SPACE_ENABLE = "GENOME_SPACE_ENABLE";
public static final String GENOME_SPACE_DM_SERVER = "GENOME_SPACE_DM_SERVER";
public static final String GENOME_SPACE_ATM_SERVER = "GENOME_SPACE_ATM_SERVER";
public static final String GENOME_SPACE_IDENTITY_SERVER = "GENOME_SPACE_IDENTITY_SERVER";

// Google
public static final String GOOGLE_API_KEY = "GOOGLE_API_KEY";
public static final String GOOGLE_PROJECT = "GOOGLE_PROJECT";
public static final String ENABLE_GOOGLE_MENU = "ENABLE_GOOGLE_MENU";
public static final String SAVE_GOOGLE_CREDENTIALS = "SAVE_GOOGLE_CREDENTIALS";

// CBIO connections
public static final String CBIO_MUTATION_THRESHOLD = "CBIO_MUTATION_THRESHOLD";
public static final String CBIO_AMPLIFICATION_THRESHOLD = "CBIO_AMPLIFICATION_THRESHOLD";
public static final String CBIO_DELETION_THRESHOLD = "CBIO_DELETION_THRESHOLD";
public static final String CBIO_EXPRESSION_UP_THRESHOLD = "CBIO_EXPRESSION_UP_THRESHOLD";
public static final String CBIO_EXPRESSION_DOWN_THRESHOLD = "CBIO_EXPRESSION_DOWN_THRESHOLD";

// Proxy settings
public static final String USE_PROXY = "PROXY.USE";
public static final String PROXY_HOST = "PROXY.HOST";
Expand Down Expand Up @@ -289,8 +291,6 @@ private Constants() {
public static final String CIRC_VIEW_PORT = "CIRC_VIEW_PORT";
public static final String CIRC_VIEW_HOST = "CIRC_VIEW_HOST";

// Experimental
public static final String SCORE_VARIANTS = "SCORE_VARIANTS";


/**
Expand All @@ -312,8 +312,7 @@ private Constants() {
SAM_FILTER_SECONDARY_ALIGNMENTS,
SAM_FILTER_SUPPLEMENTARY_ALIGNMENTS,
SAM_JUNCTION_MIN_FLANKING_WIDTH,
SAM_JUNCTION_MIN_COVERAGE,
SAM_BASEMOD_THRESHOLD
SAM_JUNCTION_MIN_COVERAGE
);

/**
Expand All @@ -330,7 +329,28 @@ private Constants() {
SAM_GROUP_BY_TAG,
SAM_SHADE_QUALITY_LOW,
SAM_SHADE_QUALITY_HIGH,
SAM_SHADE_ALIGNMENT_BY
SAM_SHADE_ALIGNMENT_BY,
BASEMOD_THRESHOLD,
SMRT_KINETICS_SHOW_OPTIONS
);

static java.util.List<String> BASEMOD_COLOR_KEYS = Arrays.asList(

BASEMOD_M_COLOR,
BASEMOD_H_COLOR,
BASEMOD_F_COLOR,
BASEMOD_C_COLOR,
BASEMOD_G_COLOR,
BASEMOD_E_COLOR,
BASEMOD_B_COLOR,
BASEMOD_A_COLOR,
BASEMOD_O_COLOR,
BASEMOD_OTHER_COLOR,
BASEMOD_NONE_A_COLOR,
BASEMOD_NONE_C_COLOR,
BASEMOD_NONE_T_COLOR,
BASEMOD_NONE_G_COLOR,
BASEMOD_NONE_N_COLOR
);

/**
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/org/broad/igv/prefs/IGVPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.broad.igv.logging.Logger;
import org.broad.igv.renderer.ColorScaleFactory;
import org.broad.igv.renderer.ContinuousColorScale;
import org.broad.igv.sam.mods.BaseModificationColors;
import org.broad.igv.track.TrackType;
import org.broad.igv.ui.IGV;
import org.broad.igv.ui.UIConstants;
Expand Down Expand Up @@ -329,6 +330,13 @@ private void checkForAlignmentChanges(Map<String, String> updatedPreferenceMap)
break;
}
}
for (String key : BASEMOD_COLOR_KEYS) {
if (updatedPreferenceMap.containsKey(key)) {
refreshSAM = true;
BaseModificationColors.updateColors();
break;
}
}

if (reloadSAM) {
IGVEventBus.getInstance().post(new AlignmentTrackEvent(this, AlignmentTrackEvent.Type.RELOAD));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/sam/AlignmentRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ private void drawAlignment(

// Base modification
if (colorOption.isBaseMod()) {
BaseModificationRenderer.drawModifications(alignment, bpStart, locScale, rowRect, context.getGraphics(), colorOption, renderOptions.getBasemodFilter());
BaseModificationRenderer.drawModifications(alignment, bpStart, locScale, rowRect, context.getGraphics(), colorOption, renderOptions.getBasemodFilter(), renderOptions.getBasemodThreshold());
}

// Kinetic data
Expand Down
21 changes: 18 additions & 3 deletions src/main/java/org/broad/igv/sam/AlignmentTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,8 @@ public static class RenderOptions implements Cloneable, Persistable {

private BaseModficationFilter basemodFilter;

private Float basemodThreshold;

BisulfiteContext bisulfiteContext = BisulfiteContext.CG;
Map<String, PEStats> peStats;

Expand Down Expand Up @@ -1606,6 +1608,14 @@ public BaseModficationFilter getBasemodFilter() {
return basemodFilter;
}

public float getBasemodThreshold() {
return basemodThreshold == null ? getPreferences().getAsFloat(BASEMOD_THRESHOLD) : basemodThreshold.floatValue();
}

public void setBasemodThreshold(float basemodThreshold) {
this.basemodThreshold = basemodThreshold;
}

public void setBasemodFilter(BaseModficationFilter basemodFilter) {
this.basemodFilter = basemodFilter;
}
Expand Down Expand Up @@ -1707,7 +1717,10 @@ public void marshalXML(Document document, Element element) {
element.setAttribute("showInsertionMarkers", showInsertionMarkers.toString());
}
if (basemodFilter != null) {
element.setAttribute("basemodfilter", basemodFilter.toString());
element.setAttribute("basemodFilter", basemodFilter.toString());
}
if(basemodThreshold != null) {
element.setAttribute("basemodThredhold", String.valueOf(basemodThreshold));
}
}

Expand Down Expand Up @@ -1824,10 +1837,12 @@ public void unmarshalXML(Element element, Integer version) {
if (element.hasAttribute("showInsertionMarkers")) {
showInsertionMarkers = Boolean.parseBoolean(element.getAttribute("showInsertionMarkers"));
}
if (element.hasAttribute("basemodfilter")) {
if (element.hasAttribute("basemodFilter")) {
basemodFilter = BaseModficationFilter.fromString(element.getAttribute("basemodfilter"));
}

if (element.hasAttribute("basemodThreshold")) {
basemodFilter = BaseModficationFilter.fromString(element.getAttribute("basemodThreshold"));
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/broad/igv/sam/CoverageTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,8 @@ private void paint(final RenderContext context, final Rectangle rect, final Alig
}
} else if (colorOption.isBaseMod()) {
BaseModficationFilter basemodFilter = alignmentTrack != null ? alignmentTrack.getRenderOptions().getBasemodFilter() : null;
BaseModificationCoverageRenderer.drawModifications(context, pX, bottomY, dX, barHeight, pos, alignmentCounts, colorOption, basemodFilter, simplexModifications);
float threshold = alignmentTrack.getRenderOptions().getBasemodThreshold();
BaseModificationCoverageRenderer.drawModifications(context, pX, bottomY, dX, barHeight, pos, alignmentCounts, colorOption, basemodFilter, threshold, simplexModifications);
} else {
if (refBases != null) {
int refIdx = pos - intervalStart;
Expand Down
56 changes: 27 additions & 29 deletions src/main/java/org/broad/igv/sam/mods/BaseModificationColors.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import org.broad.igv.logging.LogManager;
import org.broad.igv.logging.Logger;
import org.broad.igv.prefs.Constants;
import org.broad.igv.prefs.IGVPreferences;
import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.sam.AlignmentTrack;

import static org.broad.igv.prefs.Constants.*;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -28,32 +31,25 @@ public class BaseModificationColors {
static HashMap<String, Color> colors5MC = new HashMap<>();

static Color genericColor = new Color(132, 178, 158);
public static Color noModColor = Color.blue;

static Color hColor = new Color(11, 132, 165);
static Color oColor = new Color(111, 78, 129);
static Color fColor = new Color(246, 200, 95);
static Color cColor = new Color(157, 216, 102);
static Color gColor = new Color(255, 160, 86);
static Color eColor = new Color(141, 221, 208);
static Color bColor = new Color(0, 100, 47);
static Color aColor = new Color(51, 0, 111);

static {
colors.put("m", Color.red);
colors.put("h", hColor);
colors.put("o", oColor);
colors.put("f", fColor);
colors.put("c", cColor);
colors.put("g", gColor);
colors.put("e", eColor);
colors.put("b", bColor);
colors.put("a", aColor);
colors.put("NONE_A", noModColor);
colors.put("NONE_C", noModColor);
colors.put("NONE_T", noModColor);
colors.put("NONE_G", noModColor);
colors5MC.put("h", new Color(255, 0, 255)); // Modify h for 5mC to distinguish from blue

public static void updateColors () {
IGVPreferences preferences = PreferencesManager.getPreferences();
colors.put("m", preferences.getAsColor(BASEMOD_M_COLOR));
colors.put("h", preferences.getAsColor(BASEMOD_H_COLOR));
colors.put("o", preferences.getAsColor(BASEMOD_O_COLOR));
colors.put("f", preferences.getAsColor(BASEMOD_F_COLOR));
colors.put("c", preferences.getAsColor(BASEMOD_C_COLOR));
colors.put("g", preferences.getAsColor(BASEMOD_G_COLOR));
colors.put("e", preferences.getAsColor(BASEMOD_E_COLOR));
colors.put("b", preferences.getAsColor(BASEMOD_B_COLOR));
colors.put("a", preferences.getAsColor(BASEMOD_A_COLOR));
colors.put("other", preferences.getAsColor(BASEMOD_OTHER_COLOR));
colors.put("NONE_A", preferences.getAsColor(BASEMOD_NONE_A_COLOR));
colors.put("NONE_C", preferences.getAsColor(BASEMOD_NONE_C_COLOR));
colors.put("NONE_U", preferences.getAsColor(BASEMOD_NONE_C_COLOR));
colors.put("NONE_T", preferences.getAsColor(BASEMOD_NONE_T_COLOR));
colors.put("NONE_G", preferences.getAsColor(BASEMOD_NONE_G_COLOR));
colors.put("NONE_N", preferences.getAsColor(BASEMOD_NONE_N_COLOR));
}

/**
Expand All @@ -64,8 +60,10 @@ public class BaseModificationColors {

public static Color getModColor(String modification, int l, AlignmentTrack.ColorOption colorOption) {

if(colors.isEmpty()) updateColors();

// Note the pallete will always return a color, either an initially seeded one if supplied or a random color.
Color baseColor = getBaseColor(modification, colorOption);
Color baseColor = getBaseColor(modification);

if (l > 210) {
return baseColor;
Expand All @@ -81,7 +79,7 @@ public static Color getModColor(String modification, int l, AlignmentTrack.Color
}


private static Color getBaseColor(String modification, AlignmentTrack.ColorOption colorOption) {
private static Color getBaseColor(String modification) {
if (colors.containsKey(modification)) {
return colors.get(modification);
} else {
Expand Down
44 changes: 17 additions & 27 deletions src/main/java/org/broad/igv/sam/mods/BaseModificationCounts.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class BaseModificationCounts {

Map<BaseModificationKey, Map<Integer, ByteArrayList>> likelihoods;

transient float lastThreshold;


public BaseModificationCounts() {
allModifications = new LinkedHashSet<>();
Expand Down Expand Up @@ -48,11 +50,8 @@ public void incrementCounts(Alignment alignment) {

int blockIdx = i - block.getBases().startOffset;
int position = block.getStart() + blockIdx;
if(position == 119094723) {
System.out.println();
}
// Loop through base modification sets

// Loop through base modification sets
char canonicalBase = 0;
int noModLH = 255;
for (BaseModificationSet bmSet : baseModificationSets) {
Expand All @@ -61,7 +60,7 @@ public void incrementCounts(Alignment alignment) {
byte byteLikelihood = bmSetLikelihoods.get(i);
BaseModificationKey modKey = BaseModificationKey.getKey(bmSet.getBase(), bmSet.getStrand(), bmSet.getModification());
allModifications.add(modKey);
pushLikelihood(position, byteLikelihood, modKey, likelihoods);
pushLikelihood(position, byteLikelihood, modKey);

canonicalBase = bmSet.getCanonicalBase(); // Assumed same for all modifications at this position, modificatons on both bases at a position not supported
noModLH -= Byte.toUnsignedInt(byteLikelihood);
Expand All @@ -71,15 +70,15 @@ public void incrementCounts(Alignment alignment) {
if (canonicalBase != 0) {
BaseModificationKey noModKey = BaseModificationKey.getKey(canonicalBase, '+', "NONE_" + canonicalBase);
allModifications.add(noModKey);
pushLikelihood(position, (byte) noModLH, noModKey, likelihoods);
pushLikelihood(position, (byte) noModLH, noModKey);
}

}
}
}
}

private void pushLikelihood(int position, byte byteLikelihood, BaseModificationKey modKey, Map<BaseModificationKey, Map<Integer, ByteArrayList>> likelihoods) {
private void pushLikelihood(int position, byte byteLikelihood, BaseModificationKey modKey) {
Map<Integer, ByteArrayList> t = likelihoods.get(modKey);
if (t == null) {
t = new HashMap<>();
Expand All @@ -93,21 +92,18 @@ private void pushLikelihood(int position, byte byteLikelihood, BaseModificationK
byteArrayList.add(byteLikelihood);
}

public int getCount(int position, BaseModificationKey key, int threshold) {
public int getCount(int position, BaseModificationKey key, float threshold) {
lastThreshold = threshold;
float scaledThreshold = threshold * 255;
Map<Integer, ByteArrayList> t = likelihoods.get(key);
return _getCount(position, threshold, t);
}


private int _getCount(int position, int threshold, Map<Integer, ByteArrayList> t) {
ByteArrayList byteArrayList = t.get(position);
if (byteArrayList == null) {
return 0;
} else {
int count = 0;
for (int i = 0; i < byteArrayList.size(); i++) {
int lh = Byte.toUnsignedInt(byteArrayList.get(i));
if (lh > threshold) {
if (lh > scaledThreshold) {
count++;
}
}
Expand All @@ -134,21 +130,15 @@ public String getValueString(int position, AlignmentTrack.ColorOption colorOptio
BaseModificationKey key = entry.getKey();
Map<Integer, ByteArrayList> t = entry.getValue();
if (t.containsKey(position)) {
int count = this.getCount(position, key, 255 / 2);
String modName = BaseModificationUtils.modificationName(key.modification);
buffer.append("Modification: " + modName + " (" + key.base + key.strand + "), count > threshold: " + count + "<br>");
if(key.modification.startsWith("NONE_")) continue;
int count = this.getCount(position, key, lastThreshold);
if(count > 0) {
String modName = BaseModificationUtils.modificationName(key.modification);
buffer.append("Modification " + modName + " (" + key.base + key.strand + "): " + count + " with likelihood > " + (lastThreshold * 100) + "%<br>");
}
}
}
// for (Map.Entry<BaseModificationKey, Map<Integer, ByteArrayList>> entry : nomodLikelihoods.entrySet()) {
// BaseModificationKey key = entry.getKey();
// Map<Integer, ByteArrayList> t = entry.getValue();
// if (t.containsKey(position)) {
// int count = this.getCount(position, key, 255 / 2);
// String modName = BaseModificationUtils.modificationName(key.modification);
// buffer.append("Modification: " + modName + " (" + key.base + key.strand + "), count > threshold: " + count + "<br>");
// }
//
// }

return buffer.toString();
}
}
Loading

0 comments on commit 3b144d8

Please sign in to comment.