Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coloring BAM reads by strand with mismatch highlights #72

Merged
merged 28 commits into from
Jul 18, 2014
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3701d7e
Add option to show only mismatches.
May 27, 2014
7af149e
Show dots instead of matches.
May 27, 2014
37b00b3
Distinguish between feature orientation.
May 27, 2014
3044c5c
color strands, change del to # char
Jun 23, 2014
d077cfc
changed drawing for svg export
Jun 23, 2014
ec1f870
change color scheme, show quality for non-ref bases
Jun 23, 2014
5823cf0
changed strand colors to match igv
Jun 24, 2014
82ebd69
Merge pull request #1 from dev/color_strands_differently
Jun 25, 2014
69e758e
Bug fix for uncollapsing super groups
Jul 2, 2014
cd13c6b
Merge pull request #2 from dev/fix_uncollapsing_supergroup
Jul 3, 2014
54afe9d
first pass at making read drawing faster
Jul 7, 2014
f91be2c
color change, retain ref qual at max zoom
Jul 8, 2014
025fa21
add option to change strand color dynamically
Jul 8, 2014
1e8df3d
consolidate SVG drawing and colors
Jul 8, 2014
12d1e8b
change typo in colors
Jul 8, 2014
0c04cce
Merge branch 'master' into counsyl
Jul 9, 2014
ab42444
change hardcoding for bases in drawing
Jul 10, 2014
d265bf9
merging master to branch after resolving conflicts
Jul 10, 2014
5317ed2
bug fix related to merge conflict
Jul 10, 2014
e9f08b0
Merge branch 'opensource_master' into opensource_color_strands
Jul 11, 2014
635177e
Merge branch 'opensource_master' into opensource_color_strands
Jul 15, 2014
fbde313
tighten tier edit options
Jul 16, 2014
495e05d
Merge branch 'opensource_master' into opensource_color_strands
Jul 16, 2014
cf11be6
style cleanup
Jul 16, 2014
43ddec0
style cleanup
Jul 16, 2014
f2f2b30
tighten color edit options
Jul 16, 2014
1ba54c9
style cleanup
Jul 17, 2014
3251907
adjust args to SequenceGlyph constructor
Jul 17, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions js/cbrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ function Browser(opts) {
this.baseColors = {
A: 'green',
C: 'blue',
G: 'black',
T: 'red'
G: 'orange',
T: 'red',
'-' : 'hotPink' // deletion
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps there could be an option to customize these colors.

Also, the '-' character denoting deletion is currently just hardcoded here, which is probably not ideal.

};

// Registry
Expand Down
5 changes: 4 additions & 1 deletion js/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ var palette = {
white: new DColour(255, 255, 255, 'white'),
black: new DColour(0, 0, 0, 'black'),
gray: new DColour(180, 180, 180, 'gray'),
grey: new DColour(180, 180, 180, 'grey')
grey: new DColour(180, 180, 180, 'grey'),
lightskyblue: new DColour(135, 206, 250, 'lightskyblue'),
lightsalmon: new DColour(255, 160, 122, 'lightsalmon'),
hotpink: new DColour(255, 105, 180, 'hotpink')
};

var COLOR_RE = new RegExp('^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$');
Expand Down
15 changes: 13 additions & 2 deletions js/feature-draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,18 @@ function glyphForFeature(feature, y, style, tier, forceHeight, noLabel)
}
}
}
gg = new SequenceGlyph(tier.browser.baseColors, minPos, maxPos, height, seq, refSeq, style.__SEQCOLOR, quals);
if (seq && refSeq && style.__SEQCOLOR === 'mismatch') {
var mismatchSeq = [];
var match = feature.orientation === '-' ? ',' : '.';
for (var i = 0; i < seq.length; ++i)
mismatchSeq.push(seq[i] == refSeq[i] ? match : seq[i]);
seq = mismatchSeq.join('');
}

var colors = {baseColors: tier.browser.baseColors,
plusColor: style._plusColor,
minusColor: style._minusColor};
gg = new SequenceGlyph(colors, minPos, maxPos, height, seq, refSeq, feature.orientation, style.__SEQCOLOR, quals);
if (insertionLabels)
gg = new TranslatedGlyph(gg, 0, 7);
if (indels.length > 0) {
Expand Down Expand Up @@ -1125,4 +1136,4 @@ if (typeof(module) !== 'undefined') {
module.exports = {
drawFeatureTier: drawFeatureTier
};
}
}
119 changes: 67 additions & 52 deletions js/glyphs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1015,15 +1015,22 @@ TextGlyph.prototype.toSVG = function() {

var isRetina = window.devicePixelRatio > 1;
var __dalliance_SequenceGlyphCache = {};
var altPattern = new RegExp('^[ACGT-]$');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, the deletion character '-' is hardcoded here.

var isCloseUp = function(scale) {
return scale >= 8;
}

function SequenceGlyph(baseColors, min, max, height, seq, ref, scheme, quals) {
this.baseColors = baseColors;
function SequenceGlyph(colorStyle, min, max, height, seq, ref, orientation, scheme, quals) {
this.baseColors = colorStyle.baseColors;
this.plusColor = colorStyle.plusColor || "lightsalmon";
this.minusColor = colorStyle.minusColor || "lightskyblue";
this._min = min;
this._max = max;
this._height = height;
this._seq = seq;
this._ref = ref;
this._scheme = scheme;
this._orientation = orientation;
this._quals = quals;
}

Expand All @@ -1038,35 +1045,48 @@ SequenceGlyph.prototype.alphaForQual = function(qual) {

SequenceGlyph.prototype.draw = function(gc) {
var seq = this._seq;

var ref = this._ref;

var seqLength = seq ? seq.length : (this._max - this._min + 1);
var scale = (this._max - this._min + 1) / seqLength;

if (this._scheme === 'mismatch' && !isCloseUp(scale)) {
var readColor = this._orientation === '+' ? this.plusColor : this.minusColor;
gc.fillStyle = readColor;
gc.fillRect(this._min, this._height/4, this._max-this._min, this._height/2);
}

for (var p = 0; p < seqLength; ++p) {
var base = seq ? seq.substr(p, 1).toUpperCase() : 'N';

if (!altPattern.test(base) && !isCloseUp(scale))
continue;

var color = this.baseColors[base];
if (!color) {
color = 'gray';
}

if (this._scheme === 'mismatch' && this._ref) {
var refbase = this._ref.substr(p, 1).toUpperCase();
if (refbase === 'N') {
color = 'gray';
} else if (refbase === base) {
color = 'black';
} else {
color = 'red';
}
}

if (this._quals) {
var qc = this._quals.charCodeAt(p) - 33;
var oldAlpha = gc.globalAlpha; // NB hoisted!
gc.globalAlpha = this.alphaForQual(qc);
}

if (scale >= 8) {
if (!color) {
var refBase = ref ? ref.substr(p, 1).toUpperCase() : 'N';
if (base == 'N' || refBase == 'N')
color = 'gray';
else if (this._orientation == '+')
color = this.plusColor;
else if (this._orientation == '-')
color = this.minusColor;
else
color = 'white';
}

gc.fillStyle = color;

gc.fillRect(this._min + p*scale, 0, scale, this._height);

if (isCloseUp(scale) && altPattern.test(base)) {
var key = color + '_' + base
var img = __dalliance_SequenceGlyphCache[key];
if (!img) {
Expand All @@ -1082,18 +1102,15 @@ SequenceGlyph.prototype.draw = function(gc) {
if (isRetina) {
imgGc.scale(2, 2);
}
imgGc.fillStyle = color;
imgGc.fillStyle = 'black';
imgGc.fillText(base, 0, 8);
__dalliance_SequenceGlyphCache[key] = img;
}
if (isRetina)
gc.drawImage(img, this._min + p*scale, 0, 8, 10);
else
gc.drawImage(img, this._min + p*scale, 0);
} else {
gc.fillStyle = color;
gc.fillRect(this._min + p*scale, 0, scale, this._height);
}
}

if (this._quals) {
gc.globalAlpha = oldAlpha;
Expand All @@ -1103,25 +1120,24 @@ SequenceGlyph.prototype.draw = function(gc) {

SequenceGlyph.prototype.toSVG = function() {
var seq = this._seq;
var ref = this._ref;
var scale = (this._max - this._min + 1) / this._seq.length;
var g = makeElementNS(NS_SVG, 'g');

for (var p = 0; p < seq.length; ++p) {
var base = seq.substr(p, 1).toUpperCase();
var color = baseColors[base];
if (!color) {
color = 'gray';
}
var base = seq ? seq.substr(p, 1).toUpperCase() : 'N';
var color = this.baseColors[base];

if (this._scheme === 'mismatch' && this._ref) {
var refbase = this._ref.substr(p, 1).toUpperCase();
if (refbase === 'N') {
if (!color) {
var refBase = ref ? ref.substr(p, 1).toUpperCase() : 'N';
if (base == 'N' || refBase == 'N')
color = 'gray';
} else if (refbase === base) {
color = 'black';
} else {
color = 'red';
}
else if (this._orientation == '+')
color = this.plusColor;
else if (this._orientation == '-')
color = this.minusColor;
else
color = 'white';
}

var alpha = 1.0;
Expand All @@ -1130,23 +1146,22 @@ SequenceGlyph.prototype.toSVG = function() {
alpha = this.alphaForQual(qc);
}

if (scale >= 8) {
g.appendChild(
makeElementNS(NS_SVG, 'text', base, {
x: this._min + p*scale,
y: 8,
fill: color,
fillOpacity: alpha}));
} else {
g.appendChild(
makeElementNS(NS_SVG, 'rect', null, {
x:this._min + p*scale,
y: 0,
width: scale,
height: this._height,
fill: color,
fillOpacity: alpha}));
g.appendChild(
makeElementNS(NS_SVG, 'rect', null, {
x:this._min + p*scale,
y: 0,
width: scale,
height: this._height,
fill: color,
fillOpacity: alpha}));

if (isCloseUp(scale) && altPattern.test(base)) {
g.appendChild(
makeElementNS(NS_SVG, 'text', base, {
x: this._min + p*scale,
y: 8,
fill: 'black',
fillOpacity: alpha}));
}
}

Expand Down
32 changes: 31 additions & 1 deletion js/tier-edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ Browser.prototype.openTierPanel = function(tier) {
}
}
style._gradient = null;
style._plusColor = tierPlusColorField.value;
style._minusColor = tierMinusColorField.value;
}

var mutateStylesheet = function(visitor) {
Expand Down Expand Up @@ -101,8 +103,13 @@ Browser.prototype.openTierPanel = function(tier) {
var tierColorField = makeElement('input', null, {type: 'text', value: '#dd00dd'});
var tierColorField2 = makeElement('input', null, {type: 'text', value: '#dd00dd'});
var tierColorField3 = makeElement('input', null, {type: 'text', value: '#dd00dd'});

var tierPlusColorField = makeElement('input', null, {type: 'text', value: '#ffa07a'});
var tierMinusColorField = makeElement('input', null, {type: 'text', value: '#87cefa'});

try {
tierColorField.type = tierColorField2.type = tierColorField3.type = 'color';
tierPlusColorField.type = tierMinusColorField.type = 'color';
} catch (e) {
// IE throws if attempt to set type to 'color'.
}
Expand Down Expand Up @@ -259,6 +266,10 @@ Browser.prototype.openTierPanel = function(tier) {
}
setNumColors(numColors);

if (s._plusColor)
tierPlusColorField.value = dasColourForName(s._plusColor).toHexString() || s._plusColor;
if (s._minusColor)
tierMinusColorField.value = dasColourForName(s._minusColor).toHexString() || s._minusColor;
if (isDasBooleanTrue(s.SCATTER)) {
glyphField.value = 'SCATTER';
} else {
Expand Down Expand Up @@ -315,6 +326,14 @@ Browser.prototype.openTierPanel = function(tier) {
seqMismatchRow.style.display = 'none';
seqInsertRow.style.display = 'none';
}

if (seqStyle && seqMismatchToggle.checked && !isSimpleQuantitative) {
plusStrandColorRow.style.display = 'table-row';
minusStrandColorRow.style.display = 'table-row';
} else {
plusStrandColorRow.style.display = 'none';
minusStrandColorRow.style.display = 'none';
}
}

if (isQuantitative && tier.browser.sourceAdapterIsCapable(tier.featureSource, 'quantLeap'))
Expand All @@ -325,7 +344,7 @@ Browser.prototype.openTierPanel = function(tier) {

var seqMismatchToggle = makeElement('input', null, {type: 'checkbox'});
var seqMismatchRow = makeElement('tr',
[makeElement('th', 'Color mismatches'),
[makeElement('th', 'Highlight mismatches & strands'),
makeElement('td', seqMismatchToggle)]);
seqMismatchToggle.addEventListener('change', function(ev) {
var nss = copyStylesheet(tier.stylesheet);
Expand All @@ -351,6 +370,12 @@ Browser.prototype.openTierPanel = function(tier) {
var colorRow = makeElement('tr',
[makeElement('th', ['Colour(s)', colorListPlus, colorListMinus]),
colorListElement]);
var plusStrandColorRow = makeElement('tr',
[makeElement('th', 'Plus Strand Color'),
makeElement('td', tierPlusColorField)]);
var minusStrandColorRow = makeElement('tr',
[makeElement('th', 'Minus Strand Color'),
makeElement('td', tierMinusColorField)]);
var minRow = makeElement('tr',
[makeElement('th', 'Min value'),
makeElement('td', [tierMinToggle, ' ', tierMinField])]);
Expand Down Expand Up @@ -384,6 +409,8 @@ Browser.prototype.openTierPanel = function(tier) {

styleRow,
colorRow,
plusStrandColorRow,
minusStrandColorRow,
minRow,
maxRow,
quantLeapRow,
Expand Down Expand Up @@ -416,6 +443,9 @@ Browser.prototype.openTierPanel = function(tier) {
tierColorFields[ci].addEventListener('change', changeColor, false);
}

tierPlusColorField.addEventListener('change', changeColor, false);
tierMinusColorField.addEventListener('change', changeColor, false);

glyphField.addEventListener('change', function(ev) {
var nss = mutateStylesheet(function(ts) {
if (glyphField.value === 'SCATTER') {
Expand Down