ideogram
Version:
Chromosome visualization for the web
201 lines (174 loc) • 5.5 kB
JavaScript
/**
* Get containers to group individual annotations into higher-level "bar"
* annotations.
*/
function getRawBars(chrModels, ideo) {
var chr, chrModel, lastBand, numBins, bar, h, i, px,
barWidth = ideo.config.barWidth,
bars = [];
for (h = 0; h < ideo.chromosomesArray.length; h++) {
chr = ideo.chromosomesArray[h].name;
chrModel = chrModels[chr];
lastBand = chrModel.bands[chrModel.bands.length - 1];
numBins = Math.round(lastBand.px.stop / barWidth); // chrPxStop / barWidth
bar = {chr: chr, annots: []};
for (i = 0; i < numBins; i++) {
px = i * barWidth - ideo.bump;
bar.annots.push({
bp: ideo.convertPxToBp(chrModel, px + ideo.bump),
px: px,
count: 0,
chrIndex: chrModel.chrIndex,
chrName: chr,
color: ideo.config.annotationsColor,
annots: []
});
}
bars.push(bar);
}
return bars;
}
/**
* Assign how many, and which annotations each histogram bar contains
*/
function assignAnnotsToBars(annots, bars, chrModels, ideo) {
var chrAnnots, chrModel, barAnnots, h, i, annot, px, j, barPx, nextBarPx,
barWidth = ideo.config.barWidth;
for (h = 0; h < annots.length; h++) {
chrAnnots = annots[h].annots;
chrModel = chrModels[annots[h].chr]; // get chr by name
barAnnots = bars[chrModel.chrIndex].annots;
for (i = 0; i < chrAnnots.length; i++) {
annot = chrAnnots[i];
px = annot.px - ideo.bump;
for (j = 0; j < barAnnots.length; j++) {
barPx = barAnnots[j].px;
nextBarPx = barPx + barWidth;
if (j === barAnnots.length - 1) nextBarPx += barWidth;
if (px >= barPx && px < nextBarPx) {
bars[chrModel.chrIndex].annots[j].count += 1;
bars[chrModel.chrIndex].annots[j].annots.push(annot);
break;
}
}
}
}
return bars;
}
function setIdeoMaxAnnotsPerBar(bars, isFirstGet, ideo) {
var maxAnnotsPerBarAllChrs, i, maxAnnotsPerBar, annots, chr, j, barCount;
if (isFirstGet || ideo.config.histogramScaling === 'relative') {
maxAnnotsPerBarAllChrs = 0;
for (i = 0; i < bars.length; i++) {
maxAnnotsPerBar = 0;
annots = bars[i].annots;
chr = bars[i].chr;
for (j = 0; j < annots.length; j++) {
barCount = annots[j].count;
if (barCount > maxAnnotsPerBar) maxAnnotsPerBar = barCount;
if (barCount > maxAnnotsPerBarAllChrs) {
maxAnnotsPerBarAllChrs = barCount;
}
}
ideo.maxAnnotsPerBar[chr] = maxAnnotsPerBar;
}
ideo.maxAnnotsPerBarAllChrs = maxAnnotsPerBarAllChrs;
}
}
/**
* Set each bar's height to be proportional to the height of the bar with the
* most annotations
*/
function setProportionalBarHeight(bars, ideo) {
var i, annots, chr, j, barCount, barCountRatio, height,
ideoIsRotated = ideo._layout._isRotated;
for (i = 0; i < bars.length; i++) {
annots = bars[i].annots;
chr = bars[i].chr;
for (j = 0; j < annots.length; j++) {
barCount = annots[j].count;
if (ideo.config.histogramScaling === 'relative') {
barCountRatio = barCount / ideo.maxAnnotsPerBar[chr];
} else {
barCountRatio = barCount / ideo.maxAnnotsPerBarAllChrs;
}
if (ideoIsRotated === false) {
height = barCountRatio * ideo.config.chrMargin;
} else {
height = barCountRatio * ideo.config.chrHeightOriginal * 3;
}
if (isNaN(height)) {
height = 0;
}
bars[i].annots[j].height = height;
}
}
return bars;
}
function reportGetHistogramBarPerformance(t0, ideo) {
var t1 = new Date().getTime();
if (ideo.config.debug) {
console.log('Time spent in getHistogramBars: ' + (t1 - t0) + ' ms');
}
}
function setIdeoHistogramScaling(ideo) {
if ('histogramScaling' in ideo.config === false) {
ideo.config.histogramScaling = 'absolute';
}
}
/**
* Returns and sets bars used for histogram
*/
function getHistogramBars(annots) {
var chrModels, bars,
isFirstGet = false,
t0 = new Date().getTime(),
ideo = this;
chrModels = ideo.chromosomes[ideo.config.taxid];
setIdeoHistogramScaling(ideo);
if (typeof ideo.maxAnnotsPerBar === 'undefined') {
ideo.maxAnnotsPerBar = {};
isFirstGet = true;
}
bars = getRawBars(chrModels, ideo);
bars = assignAnnotsToBars(annots, bars, chrModels, ideo);
setIdeoMaxAnnotsPerBar(bars, isFirstGet, ideo);
bars = setProportionalBarHeight(bars, ideo);
reportGetHistogramBarPerformance(t0, ideo);
ideo.bars = bars;
return bars;
}
function getHistogramPoints(d, chrWidth, chrWidths, ideo) {
var x1, x2, y1, y2;
x1 = d.px + ideo.bump;
x2 = d.px + ideo.config.barWidth + ideo.bump;
y1 = chrWidth;
y2 = chrWidth + d.height;
var thisChrWidth = chrWidths[d.chr];
if (x2 > thisChrWidth) {
x2 = thisChrWidth;
}
return (
x1 + ',' + y1 + ' ' +
x2 + ',' + y1 + ' ' +
x2 + ',' + y2 + ' ' +
x1 + ',' + y2
);
}
function writeHistogramAnnots(chrAnnot, ideo) {
var chrs, chr,
chrWidths = {},
chrWidth = ideo.config.chrWidth;
chrs = ideo.chromosomes[ideo.config.taxid];
for (chr in chrs) {
chrWidths[chr] = chrs[chr];
}
chrAnnot.append('polygon')
// .attr('id', function(d, i) { return d.id; })
.attr('class', 'annot')
.attr('points', function(d) {
return getHistogramPoints(d, chrWidth, chrWidths, ideo);
})
.attr('fill', function(d) {return d.color;});
}
export {getHistogramBars, writeHistogramAnnots};