mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Charts: Heatmaps revised plugin code, now modularized and enabled for variable data
This commit is contained in:
@@ -4,6 +4,7 @@ return {
|
||||
title : 'Heatmap',
|
||||
library : '',
|
||||
tag : 'div',
|
||||
use_panels : true,
|
||||
columns : {
|
||||
col_label : {
|
||||
title : 'Columns',
|
||||
|
||||
@@ -20,313 +20,215 @@ return Backbone.View.extend(
|
||||
cellSize: 0,
|
||||
|
||||
// color buckets
|
||||
colorBuckets: 0,
|
||||
nColors: 0,
|
||||
|
||||
// default settings
|
||||
optionsDefault: {
|
||||
margin : {
|
||||
pace : 1000,
|
||||
margin : {
|
||||
top : 50,
|
||||
right : 10,
|
||||
bottom : 50,
|
||||
left : 100
|
||||
},
|
||||
colors : ['#005824','#1A693B','#347B53','#4F8D6B','#699F83','#83B09B','#9EC2B3','#B8D4CB','#D2E6E3','#EDF8FB','#FFFFFF','#F1EEF6','#E6D3E1','#DBB9CD','#D19EB9','#C684A4','#BB6990','#B14F7C','#A63467','#9B1A53','#91003F']
|
||||
colors : ['#005824','#1A693B','#347B53','#4F8D6B','#699F83','#83B09B','#9EC2B3','#B8D4CB','#D2E6E3','#EDF8FB','#FFFFFF','#F1EEF6','#E6D3E1','#DBB9CD','#D19EB9','#C684A4','#BB6990','#B14F7C','#A63467','#9B1A53','#91003F']
|
||||
},
|
||||
|
||||
// initialize
|
||||
initialize: function(options) {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// load options
|
||||
this.options = Utils.merge(options, this.optionsDefault)
|
||||
|
||||
// add ui elements
|
||||
this.options.div.append(this._templateTooltip());
|
||||
this.options.div.append(this._templateSelect());
|
||||
// check requirements
|
||||
if (!this.options.data || !this.options.div) {
|
||||
console.debug('FAILED - HeatMapPlugin::initialize() - Parameters (container and/or data) missing.');
|
||||
return;
|
||||
}
|
||||
|
||||
// access data
|
||||
var data = this.options.data;
|
||||
// link data
|
||||
this.data = this.options.data;
|
||||
|
||||
// identify unique labels
|
||||
var col_hash = {};
|
||||
var row_hash = {};
|
||||
// set element
|
||||
this.setElement(this.options.div);
|
||||
|
||||
// create label indices
|
||||
this.colNumber = 0;
|
||||
this.rowNumber = 0;
|
||||
for (var i in data) {
|
||||
var cell = data[i];
|
||||
//
|
||||
// data indexing
|
||||
//
|
||||
|
||||
// labels in alphabetical order
|
||||
this.rowLabel = [];
|
||||
this.colLabel = [];
|
||||
|
||||
// unique keys (key indices are unique per label and indicate the labels rank in the alphabetical sorting)
|
||||
this.colRank = {};
|
||||
this.rowRank = {};
|
||||
|
||||
// identify unqiue labels
|
||||
for (var i in this.data) {
|
||||
var cell = this.data[i];
|
||||
|
||||
// add label to index list
|
||||
var col_label = cell.col_label;
|
||||
if (col_hash[col_label] === undefined) {
|
||||
col_hash[col_label] = ++this.colNumber;
|
||||
if (this.colRank[col_label] === undefined) {
|
||||
this.colRank[col_label] = true;
|
||||
this.colLabel.push(col_label);
|
||||
}
|
||||
var row_label = cell.row_label;
|
||||
if (row_hash[row_label] === undefined) {
|
||||
row_hash[row_label] = ++this.rowNumber;
|
||||
if (this.rowRank[row_label] === undefined) {
|
||||
this.rowRank[row_label] = true;
|
||||
this.rowLabel.push(row_label);
|
||||
}
|
||||
}
|
||||
|
||||
// add indices to data
|
||||
for (var i in data) {
|
||||
var cell = data[i];
|
||||
cell.col = col_hash[cell.col_label];
|
||||
cell.row = row_hash[cell.row_label];
|
||||
}
|
||||
// set sizes
|
||||
this.rowNumber = this.rowLabel.length
|
||||
this.colNumber = this.colLabel.length
|
||||
|
||||
// add row labels
|
||||
// sort labels alphabetical
|
||||
this.rowLabel.sort();
|
||||
this.colLabel.sort();
|
||||
|
||||
// generate sorted key list for rows
|
||||
this.rowIndex = []
|
||||
for (var key in row_hash) {
|
||||
this.rowLabel.push(key);
|
||||
this.rowIndex.push(row_hash[key]);
|
||||
for (var i in this.rowLabel) {
|
||||
var row_label = this.rowLabel[i];
|
||||
var row_index = parseInt(i);
|
||||
this.rowRank[row_label] = row_index;
|
||||
|
||||
// should contain clustering
|
||||
this.rowIndex.push(row_index);
|
||||
}
|
||||
|
||||
// add col labels
|
||||
// generate sorted key list for columns
|
||||
this.colIndex = []
|
||||
for (var key in col_hash) {
|
||||
this.colLabel.push(key);
|
||||
this.colIndex.push(col_hash[key]);
|
||||
for (var i in this.colLabel) {
|
||||
var col_label = this.colLabel[i];
|
||||
var col_index = parseInt(i);
|
||||
this.colRank[col_label] = col_index;
|
||||
|
||||
// should contain clustering
|
||||
this.colIndex.push(col_index);
|
||||
}
|
||||
console.log(this.rowIndex);
|
||||
console.log(this.colIndex);
|
||||
|
||||
//
|
||||
// parse indexing to cells, identify data range
|
||||
//
|
||||
|
||||
// min/max
|
||||
this.max = undefined;
|
||||
this.min = undefined
|
||||
|
||||
// add indices to data
|
||||
for (var i in this.data) {
|
||||
// get cell data
|
||||
var cell = this.data[i];
|
||||
|
||||
// add rank
|
||||
cell.col_rank = this.colRank[cell.col_label];
|
||||
cell.row_rank = this.rowRank[cell.row_label];
|
||||
|
||||
// identify max/min values
|
||||
if (this.min == undefined || this.min > cell.value) {
|
||||
this.min = cell.value;
|
||||
}
|
||||
if (this.max == undefined || this.max < cell.value) {
|
||||
this.max = cell.value;
|
||||
}
|
||||
}
|
||||
|
||||
// middle
|
||||
this.mid = (this.max + this.min) / 2;
|
||||
|
||||
//
|
||||
// set colors
|
||||
//
|
||||
// identify buckets
|
||||
this.colorBuckets = this.options.colors.length;
|
||||
|
||||
// draw
|
||||
this._draw(this.options.div, this.options.data);
|
||||
},
|
||||
|
||||
_draw: function(container, data) {
|
||||
// get height
|
||||
this.width = parseInt(container.width()) - this.options.margin.left;
|
||||
this.height = parseInt(container.height()) - 2*this.options.margin.top;
|
||||
|
||||
// calculate cell size
|
||||
this.cellSize = Math.min( this.height / (this.rowNumber),
|
||||
this.width / (this.colNumber));
|
||||
|
||||
// set width/height for plugin
|
||||
this.width = this.options.cellSize * this.colNumber;
|
||||
this.height = this.options.cellSize * this.rowNumber;
|
||||
|
||||
// set legend width
|
||||
this.legendElementWidth = this.options.cellSize * 2.5;
|
||||
|
||||
// configure
|
||||
var margin = this.options.margin;
|
||||
var cellSize = this.cellSize;
|
||||
var colNumber = this.colNumber;
|
||||
var rowNumber = this.rowNumber;
|
||||
var colorBuckets = this.colorBuckets;
|
||||
var colors = this.options.colors;
|
||||
var rowIndex = this.rowIndex;
|
||||
var colIndex = this.colIndex;
|
||||
var colLabel = this.colLabel;
|
||||
var rowLabel = this.rowLabel;
|
||||
var width = this.width;
|
||||
var height = this.height;
|
||||
var legendElementWidth = this.legendElementWidth;
|
||||
this.nColors = this.options.colors.length;
|
||||
|
||||
// color scale
|
||||
var colorScale = d3.scale.quantile()
|
||||
.domain([ -10, 0, 10])
|
||||
.range(colors);
|
||||
this.colorScale = d3.scale.quantile()
|
||||
.domain([this.min, this.mid, this.max])
|
||||
.range(this.options.colors);
|
||||
|
||||
// add graph
|
||||
var svg = d3.select(container[0]).append('svg')
|
||||
//
|
||||
// add ui elements
|
||||
//
|
||||
// create ui elements
|
||||
this.$tooltip = $(this._templateTooltip());
|
||||
this.$select = $(this._templateSelect());
|
||||
|
||||
// append
|
||||
this.$el.append(this.$tooltip);
|
||||
this.$el.append(this.$select);
|
||||
|
||||
// add event to select field
|
||||
this.$select.on('change', function(){
|
||||
self._order(this.value);
|
||||
});
|
||||
|
||||
//
|
||||
// draw
|
||||
//
|
||||
this._draw();
|
||||
},
|
||||
|
||||
_draw: function() {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// container
|
||||
var container_width = this.$el.width();
|
||||
var container_height = this.$el.height();
|
||||
|
||||
// get height
|
||||
this.width = this.$el.width() - this.options.margin.left - this.options.margin.right;
|
||||
this.height = this.$el.height() - this.options.margin.top - this.options.margin.bottom;
|
||||
|
||||
// calculate cell size
|
||||
this.cellSize = Math.min(parseInt(this.height / this.rowNumber),
|
||||
parseInt(this.width / this.colNumber));
|
||||
|
||||
// set width/height for plugin
|
||||
this.width = this.cellSize * this.colNumber;
|
||||
this.height = this.cellSize * this.rowNumber;
|
||||
|
||||
// get dimensions
|
||||
var margin = this.options.margin;
|
||||
var width = this.width;
|
||||
var height = this.height;
|
||||
|
||||
// add main group and translate
|
||||
this.svg = d3.select(this.$el[0]).append('svg')
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
||||
.attr("transform", "translate(" + (container_width - width) / 2 + "," + (container_height - height) / 2 + ")")
|
||||
|
||||
// row labels
|
||||
var rowSortOrder=false;
|
||||
var colSortOrder=false;
|
||||
var rowLabels = svg.append("g")
|
||||
.selectAll(".rowLabelg")
|
||||
.data(rowLabel)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text(function (d) { return d; })
|
||||
.attr("x", 0)
|
||||
.attr("y", function (d, i) { return rowIndex.indexOf(i+1) * cellSize; })
|
||||
.style("font-size", cellSize + "px")
|
||||
.style("text-anchor", "end")
|
||||
.attr("transform", "translate(-10," + cellSize / 1.5 + ")")
|
||||
.attr("class", function (d,i) { return "rowLabel mono r"+i;} )
|
||||
.on("mouseover", function(d) {
|
||||
d3.select(this).classed("text-hover",true);
|
||||
d3.select(this).style("font-size", parseInt(cellSize * 1.3) + "px");
|
||||
})
|
||||
.on("mouseout" , function(d) {
|
||||
d3.select(this).classed("text-hover",false);
|
||||
d3.select(this).style("font-size", parseInt(cellSize) + "px");
|
||||
})
|
||||
.on("click", function(d,i) {rowSortOrder=!rowSortOrder; sortbylabel("r",i,rowSortOrder);d3.select("#order").property("selectedIndex", 4).node().focus();;});
|
||||
|
||||
// column labels
|
||||
var colLabels = svg.append("g")
|
||||
.selectAll(".colLabelg")
|
||||
.data(colLabel)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text(function (d) { return d; })
|
||||
.attr("x", 0)
|
||||
.attr("y", function (d, i) { return colIndex.indexOf(i+1) * cellSize; })
|
||||
.style("font-size", cellSize + "px")
|
||||
.style("text-anchor", "left")
|
||||
.attr("transform", "translate("+cellSize/2 + ",-17) rotate (-90)")
|
||||
.attr("class", function (d,i) { return "colLabel mono c"+i;} )
|
||||
.on("mouseover", function(d) {
|
||||
d3.select(this).classed("text-hover",true);
|
||||
d3.select(this).style("font-size", parseInt(cellSize * 1.3) + "px");
|
||||
})
|
||||
.on("mouseout" , function(d) {
|
||||
d3.select(this).classed("text-hover",false);
|
||||
d3.select(this).style("font-size", parseInt(cellSize) + "px");
|
||||
})
|
||||
.on("click", function(d,i) {colSortOrder=!colSortOrder; sortbylabel("c",i,colSortOrder);d3.select("#order").property("selectedIndex", 4).node().focus();;});
|
||||
|
||||
// heat map
|
||||
var heatMap = svg.append("g").attr("class","g3")
|
||||
.selectAll(".cellg")
|
||||
.data(data,function(d){return d.row+":"+d.col;})
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", function(d) { return colIndex.indexOf(d.col) * cellSize; })
|
||||
.attr("y", function(d) { return rowIndex.indexOf(d.row) * cellSize; })
|
||||
.attr("class", function(d){return "cell cell-border cr"+(d.row-1)+" cc"+(d.col-1);})
|
||||
.attr("width", cellSize)
|
||||
.attr("height", cellSize)
|
||||
.style("fill", function(d) { return colorScale(d.value); })
|
||||
// .on("click", function(d) {
|
||||
// var rowtext=d3.select(".r"+(d.row-1));
|
||||
// if(rowtext.classed("text-selected")==false){
|
||||
// rowtext.classed("text-selected",true);
|
||||
// }else{
|
||||
// rowtext.classed("text-selected",false);
|
||||
// }
|
||||
//})
|
||||
.on("mouseover", function(d){
|
||||
//highlight text
|
||||
d3.select(this).classed("cell-hover",true);
|
||||
d3.selectAll(".rowLabel").classed("text-highlight",function(r,ri){ return ri==(d.row-1);});
|
||||
d3.selectAll(".colLabel").classed("text-highlight",function(c,ci){ return ci==(d.col-1);});
|
||||
//d3.selectAll(".colLabel").style("font-size", parseInt(cellSize * 1.3) + "px");
|
||||
//d3.selectAll(".rowLabel").style("font-size", parseInt(cellSize * 1.3) + "px");
|
||||
|
||||
//Update the tooltip position and value
|
||||
d3.select("#heatmap-tooltip")
|
||||
.style("left", (d3.event.pageX+10) + "px")
|
||||
.style("top", (d3.event.pageY-10) + "px")
|
||||
.select("#value")
|
||||
.text("lables:"+rowLabel[d.row-1]+","+colLabel[d.col-1]+"\ndata:"+d.value+"\nrow-col-idx:"+d.col+","+d.row+"\ncell-xy "+this.x.baseVal.value+", "+this.y.baseVal.value);
|
||||
//Show the tooltip
|
||||
d3.select("#heatmap-tooltip").classed("hidden", false);
|
||||
})
|
||||
.on("mouseout", function(){
|
||||
d3.select(this).classed("cell-hover",false);
|
||||
d3.selectAll(".rowLabel").classed("text-highlight",false);
|
||||
d3.selectAll(".colLabel").classed("text-highlight",false);
|
||||
//d3.selectAll(".colLabel").style("font-size", parseInt(cellSize) + "px");
|
||||
//d3.selectAll(".rowLabel").style("font-size", parseInt(cellSize) + "px");
|
||||
d3.select("#heatmap-tooltip").classed("hidden", true);
|
||||
});
|
||||
|
||||
var legend = svg.selectAll(".legend")
|
||||
.data([-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10])
|
||||
.enter().append("g")
|
||||
.attr("class", "legend");
|
||||
|
||||
legend.append("rect")
|
||||
.attr("x", function(d, i) { return legendElementWidth * i; })
|
||||
.attr("y", height+(cellSize*2))
|
||||
.attr("width", legendElementWidth)
|
||||
.attr("height", cellSize)
|
||||
.style("fill", function(d, i) { return colors[i]; });
|
||||
|
||||
legend.append("text")
|
||||
.attr("class", "mono")
|
||||
.text(function(d) { return d; })
|
||||
.attr("width", legendElementWidth)
|
||||
.attr("x", function(d, i) { return legendElementWidth * i; })
|
||||
.attr("y", height + (cellSize*4))
|
||||
.style("font-size", cellSize + "px");
|
||||
|
||||
// change ordering of cells
|
||||
function sortbylabel(rORc,i,sortOrder) {
|
||||
var t = svg.transition().duration(3000);
|
||||
var values=[];
|
||||
var sorted; // sorted is zero-based index
|
||||
d3.selectAll(".c"+rORc+i)
|
||||
.filter(function(ce){
|
||||
values.push(ce.value);
|
||||
});
|
||||
if(rORc=="r"){ // sort valuesatio of a gene
|
||||
sorted=d3.range(colNumber).sort(function(a,b){ if(sortOrder){ return values[b]-values[a];}else{ return values[a]-values[b];}});
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) { return sorted.indexOf(d.col-1) * cellSize; });
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) { return sorted.indexOf(i) * cellSize; });
|
||||
} else { // sort valuesatio of a contrast
|
||||
sorted=d3.range(rowNumber).sort(function(a,b){if(sortOrder){ return values[b]-values[a];}else{ return values[a]-values[b];}});
|
||||
t.selectAll(".cell")
|
||||
.attr("y", function(d) { return sorted.indexOf(d.row-1) * cellSize; });
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) { return sorted.indexOf(i) * cellSize; });
|
||||
}
|
||||
}
|
||||
|
||||
d3.select("#order").on("change",function(){
|
||||
order(this.value);
|
||||
});
|
||||
|
||||
function order(value) {
|
||||
if(value=="hclust"){
|
||||
var t = svg.transition().duration(3000);
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) { return colIndex.indexOf(d.col) * cellSize; })
|
||||
.attr("y", function(d) { return rowIndex.indexOf(d.row) * cellSize; });
|
||||
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) { return rowIndex.indexOf(i+1) * cellSize; });
|
||||
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) { return colIndex.indexOf(i+1) * cellSize; });
|
||||
|
||||
} else if (value=="probecontrast") {
|
||||
var t = svg.transition().duration(3000);
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) { return (d.col - 1) * cellSize; })
|
||||
.attr("y", function(d) { return (d.row - 1) * cellSize; });
|
||||
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) { return i * cellSize; });
|
||||
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) { return i * cellSize; });
|
||||
} else if (value=="probe") {
|
||||
var t = svg.transition().duration(3000);
|
||||
t.selectAll(".cell")
|
||||
.attr("y", function(d) { return (d.row - 1) * cellSize; });
|
||||
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) { return i * cellSize; });
|
||||
} else if (value=="contrast"){
|
||||
var t = svg.transition().duration(3000);
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) { return (d.col - 1) * cellSize; });
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) { return i * cellSize; });
|
||||
}
|
||||
}
|
||||
// reset sorting
|
||||
this.rowSortOrder = false;
|
||||
this.colSortOrder = false;
|
||||
|
||||
// build
|
||||
this.rowLabels = this._buildRowLabels();
|
||||
this.colLabels = this._buildColLabels();
|
||||
this.heatMap = this._buildHeatMap();
|
||||
this.legend = this._buildLegend();
|
||||
},
|
||||
|
||||
// selection of cells
|
||||
_addSelectionTool: function() {
|
||||
//
|
||||
// selection
|
||||
//
|
||||
var sa=d3.select(".g3")
|
||||
.on("mousedown", function() {
|
||||
if( !d3.event.altKey) {
|
||||
d3.selectAll(".cell-selected").classed("cell-selected",false);
|
||||
d3.selectAll(".rowLabel").classed("text-selected",false);
|
||||
d3.selectAll(".colLabel").classed("text-selected",false);
|
||||
d3.selectAll(".cell-selected").classed("cell-selected", false);
|
||||
d3.selectAll(".rowLabel").classed("text-selected", false);
|
||||
d3.selectAll(".colLabel").classed("text-selected", false);
|
||||
}
|
||||
var p = d3.mouse(this);
|
||||
sa.append("rect")
|
||||
@@ -374,8 +276,7 @@ return Backbone.View.extend(
|
||||
// deselect all temporary selected state objects
|
||||
d3.selectAll(".cell-selection.cell-selected").classed("cell-selected", false);
|
||||
d3.selectAll(".text-selection.text-selected").classed("text-selected",false);
|
||||
|
||||
d3.selectAll('.cell').filter(function(cell_d, i) {
|
||||
d3.selectAll(".cell").filter(function(cell_d, i) {
|
||||
if(!d3.select(this).classed("cell-selected") &&
|
||||
// inner circle inside selection frame
|
||||
(this.x.baseVal.value)+cellSize >= d.x && (this.x.baseVal.value)<=d.x+d.width &&
|
||||
@@ -385,11 +286,11 @@ return Backbone.View.extend(
|
||||
.classed("cell-selection", true)
|
||||
.classed("cell-selected", true);
|
||||
|
||||
d3.select(".r"+(cell_d.row-1))
|
||||
d3.select(".r"+(cell_d.row_rank))
|
||||
.classed("text-selection",true)
|
||||
.classed("text-selected",true);
|
||||
|
||||
d3.select(".c"+(cell_d.col-1))
|
||||
d3.select(".c"+(cell_d.col_rank))
|
||||
.classed("text-selection",true)
|
||||
.classed("text-selected",true);
|
||||
}
|
||||
@@ -417,14 +318,353 @@ return Backbone.View.extend(
|
||||
});
|
||||
},
|
||||
|
||||
// build legend
|
||||
_buildLegend: function() {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// gather data
|
||||
var cellSize = this.cellSize;
|
||||
var height = this.height;
|
||||
var legendCellWidth = this.width / this.nColors;
|
||||
|
||||
// create range labels
|
||||
var dataRange = [];
|
||||
for(var i = 0; i < this.nColors; i++) {
|
||||
dataRange.push('');
|
||||
}
|
||||
|
||||
// prepare indices
|
||||
var dataRangeMin = 0;
|
||||
var dataRangeMid = parseInt((dataRange.length - 1) / 2);
|
||||
var dataRangeMax = dataRange.length - 1;
|
||||
|
||||
// add labels
|
||||
dataRange[dataRangeMin] = this.min;
|
||||
dataRange[dataRangeMid] = this.mid;
|
||||
dataRange[dataRangeMax] = this.max;
|
||||
|
||||
// create legend
|
||||
var legend = this.svg.selectAll(".legend")
|
||||
.data(dataRange)
|
||||
.enter().append("g")
|
||||
.attr("class", "legend");
|
||||
|
||||
// add boxes
|
||||
legend.append("rect")
|
||||
.attr("x", function(d, i) {
|
||||
return legendCellWidth * i;
|
||||
})
|
||||
.attr("y", height + cellSize)
|
||||
.attr("width", legendCellWidth)
|
||||
.attr("height", cellSize)
|
||||
.style("fill", function(d, i) {
|
||||
return self.options.colors[i];
|
||||
});
|
||||
|
||||
// add text
|
||||
legend.append("text")
|
||||
.attr("class", "mono")
|
||||
.text(function(d) {
|
||||
return d;
|
||||
})
|
||||
.attr("width", legendCellWidth)
|
||||
.attr("x", function(d, i) {
|
||||
return legendCellWidth * i;
|
||||
})
|
||||
.attr("y", height + cellSize)
|
||||
.style("font-size", cellSize + "px");
|
||||
},
|
||||
|
||||
// build column labels
|
||||
_buildColLabels: function() {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// gather data
|
||||
var cellSize = this.cellSize;
|
||||
var colIndex = this.colIndex;
|
||||
var colLabel = this.colLabel;
|
||||
|
||||
// column labels
|
||||
var colLabels = this.svg.append("g")
|
||||
.selectAll(".colLabelg")
|
||||
.data(colLabel)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text(function (d) {
|
||||
return d;
|
||||
})
|
||||
.attr("x", 0)
|
||||
.attr("y", function (d, i) {
|
||||
return colIndex.indexOf(i) * cellSize;
|
||||
})
|
||||
.style("font-size", cellSize + "px")
|
||||
.style("text-anchor", "left")
|
||||
.attr("transform", "translate(" + cellSize / 2 + ", -17) rotate (-90)")
|
||||
.attr("class", function (d, i) {
|
||||
return "colLabel mono c" + i;
|
||||
})
|
||||
.on("mouseover", function(d) {
|
||||
d3.select(this).classed("text-hover",true);
|
||||
d3.select(this).style("font-size", parseInt(cellSize * 1.3) + "px");
|
||||
})
|
||||
.on("mouseout" , function(d) {
|
||||
d3.select(this).classed("text-hover",false);
|
||||
d3.select(this).style("font-size", parseInt(cellSize) + "px");
|
||||
})
|
||||
.on("click", function(d, i) {
|
||||
self.colSortOrder=!self.colSortOrder;
|
||||
self._sortByLabel("c", i, self.colSortOrder);
|
||||
d3.select("#order").property("selectedIndex", 4).node().focus();
|
||||
});
|
||||
},
|
||||
|
||||
// build row labels
|
||||
_buildRowLabels: function() {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// gather data
|
||||
var cellSize = this.cellSize;
|
||||
var rowIndex = this.rowIndex;
|
||||
var rowLabel = this.rowLabel;
|
||||
|
||||
// draw labels
|
||||
var rowLabels = this.svg.append("g")
|
||||
.selectAll(".rowLabelg")
|
||||
.data(rowLabel)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text(function (d) {
|
||||
return d;
|
||||
})
|
||||
.attr("x", 0)
|
||||
.attr("y", function (d, i) {
|
||||
return rowIndex.indexOf(i) * cellSize;
|
||||
})
|
||||
.style("font-size", cellSize + "px")
|
||||
.style("text-anchor", "end")
|
||||
.attr("transform", "translate(-10," + cellSize / 1.5 + ")")
|
||||
.attr("class", function (d, i) {
|
||||
return "rowLabel mono r" + i;
|
||||
} )
|
||||
.on("mouseover", function(d) {
|
||||
d3.select(this).classed("text-hover",true);
|
||||
d3.select(this).style("font-size", parseInt(cellSize * 1.3) + "px");
|
||||
})
|
||||
.on("mouseout" , function(d) {
|
||||
d3.select(this).classed("text-hover",false);
|
||||
d3.select(this).style("font-size", parseInt(cellSize) + "px");
|
||||
})
|
||||
.on("click", function(d, i) {
|
||||
self.rowSortOrder=!self.rowSortOrder;
|
||||
self._sortByLabel("r", i, self.rowSortOrder);
|
||||
d3.select("#order").property("selectedIndex", 4).node().focus();
|
||||
});
|
||||
},
|
||||
|
||||
// build heat map
|
||||
_buildHeatMap: function() {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// gather data
|
||||
var cellSize = this.cellSize;
|
||||
var rowIndex = this.rowIndex;
|
||||
var rowLabel = this.rowLabel;
|
||||
var colIndex = this.colIndex;
|
||||
var colLabel = this.colLabel;
|
||||
|
||||
// heat map
|
||||
var heatMap = this.svg.append("g").attr("class","g3")
|
||||
.selectAll(".cellg")
|
||||
.data(self.data, function(d) {
|
||||
return d.row_rank + ":" + d.col_rank;
|
||||
})
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", function(d) {
|
||||
return colIndex.indexOf(d.col_rank) * cellSize;
|
||||
})
|
||||
.attr("y", function(d) {
|
||||
return rowIndex.indexOf(d.row_rank) * cellSize;
|
||||
})
|
||||
.attr("class", function(d){
|
||||
return "cell cell-border cr" + d.row_rank + " cc" + d.col_rank;
|
||||
})
|
||||
.attr("width", cellSize)
|
||||
.attr("height", cellSize)
|
||||
.style("fill", function(d) {
|
||||
return self.colorScale(d.value);
|
||||
})
|
||||
.on("mouseover", function(d){
|
||||
// highlight text
|
||||
d3.select(this).classed("cell-hover",true);
|
||||
d3.selectAll(".rowLabel").classed("text-highlight",function(r,ri){ return ri==(d.row_rank);});
|
||||
d3.selectAll(".colLabel").classed("text-highlight",function(c,ci){ return ci==(d.col_rank);});
|
||||
|
||||
// update the tooltip position and value
|
||||
d3.select("#heatmap-tooltip")
|
||||
.style("left", (d3.event.pageX+10) + "px")
|
||||
.style("top", (d3.event.pageY-10) + "px")
|
||||
.select("#value")
|
||||
.text("Label: " + rowLabel[d.row_rank] + " | " + colLabel[d.col_rank] + ", Value: " + d.value);
|
||||
// show the tooltip
|
||||
d3.select("#heatmap-tooltip").classed("hidden", false);
|
||||
})
|
||||
.on("mouseout", function(){
|
||||
d3.select(this).classed("cell-hover",false);
|
||||
d3.selectAll(".rowLabel").classed("text-highlight",false);
|
||||
d3.selectAll(".colLabel").classed("text-highlight",false);
|
||||
d3.select("#heatmap-tooltip").classed("hidden", true);
|
||||
});
|
||||
},
|
||||
|
||||
// change ordering of cells
|
||||
_sortByLabel: function(rORc, i, sortOrder) {
|
||||
// get cell size
|
||||
var cellSize = this.cellSize;
|
||||
|
||||
// define transition / prepare element
|
||||
var t = this.svg.transition().duration(this.options.pace);
|
||||
|
||||
// collect cells
|
||||
var cells=[];
|
||||
t.selectAll(".c" + rORc + i)
|
||||
.filter(function(ce){
|
||||
cells.push(ce);
|
||||
});
|
||||
|
||||
// sort cells
|
||||
cells.sort(function(a, b) {
|
||||
if (sortOrder) {
|
||||
return b.value - a.value;
|
||||
} else {
|
||||
return a.value - b.value;
|
||||
}
|
||||
});
|
||||
|
||||
// rows or columns
|
||||
if(rORc == "r") {
|
||||
// get sorted key list
|
||||
var sorted = [];
|
||||
for (var i in cells) {
|
||||
sorted.push(cells[i].col_rank);
|
||||
}
|
||||
|
||||
// sort cells
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) {
|
||||
return sorted.indexOf(d.col_rank) * cellSize;
|
||||
});
|
||||
|
||||
// sort labels
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) {
|
||||
return sorted.indexOf(i) * cellSize;
|
||||
});
|
||||
} else {
|
||||
// get sorted key list
|
||||
sorted = [];
|
||||
for (var i in cells) {
|
||||
sorted.push(cells[i].row_rank);
|
||||
}
|
||||
|
||||
// sort cells
|
||||
t.selectAll(".cell")
|
||||
.attr("y", function(d) {
|
||||
return sorted.indexOf(d.row_rank) * cellSize;
|
||||
});
|
||||
|
||||
// sort labels
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) {
|
||||
return sorted.indexOf(i) * cellSize;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// sort function
|
||||
_order: function (value) {
|
||||
// link this
|
||||
var self = this;
|
||||
|
||||
// gather data
|
||||
var cellSize = this.cellSize;
|
||||
var rowIndex = this.rowIndex;
|
||||
var rowLabel = this.rowLabel;
|
||||
var colIndex = this.colIndex;
|
||||
var colLabel = this.colLabel;
|
||||
|
||||
// set duration / select element
|
||||
var t = this.svg.transition().duration(this.options.pace);
|
||||
if(value=="hclust"){
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) {
|
||||
return colIndex.indexOf(d.col_rank) * cellSize;
|
||||
})
|
||||
.attr("y", function(d) {
|
||||
return rowIndex.indexOf(d.row_rank) * cellSize;
|
||||
});
|
||||
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function(d, i) {
|
||||
return rowIndex.indexOf(i) * cellSize;
|
||||
});
|
||||
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function(d, i) {
|
||||
return colIndex.indexOf(i) * cellSize;
|
||||
});
|
||||
|
||||
} else if (value=="byboth") {
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) {
|
||||
return d.col_rank * cellSize;
|
||||
})
|
||||
.attr("y", function(d) {
|
||||
return d.row_rank * cellSize;
|
||||
});
|
||||
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) {
|
||||
return i * cellSize;
|
||||
});
|
||||
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) {
|
||||
return i * cellSize;
|
||||
});
|
||||
} else if (value=="byrow") {
|
||||
t.selectAll(".cell")
|
||||
.attr("y", function(d) {
|
||||
return d.row_rank * cellSize;
|
||||
});
|
||||
|
||||
t.selectAll(".rowLabel")
|
||||
.attr("y", function (d, i) {
|
||||
return i * cellSize;
|
||||
});
|
||||
} else if (value=="bycol"){
|
||||
t.selectAll(".cell")
|
||||
.attr("x", function(d) {
|
||||
return d.col_rank * cellSize;
|
||||
});
|
||||
t.selectAll(".colLabel")
|
||||
.attr("y", function (d, i) {
|
||||
return i * cellSize;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// template
|
||||
_templateSelect: function() {
|
||||
return '<select id="order">' +
|
||||
'<option value="hclust">by cluster</option>' +
|
||||
'<option value="probecontrast">by probe name and contrast name</option>' +
|
||||
'<option value="probe">by probe name</option>' +
|
||||
'<option value="contrast">by contrast name</option>' +
|
||||
'<option value="custom">by log2 ratio</option>' +
|
||||
'<option value="hclust">Cluster</option>' +
|
||||
'<option value="byboth">Sort by row and column</option>' +
|
||||
'<option value="byrow">Sort by row label</option>' +
|
||||
'<option value="bycol">Sort by column label</option>' +
|
||||
'</select>';
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// dependencies
|
||||
define(['utils/utils', 'plugin/charts/heatmap/heatmap-plugin'], function(Utils, Plugin) {
|
||||
define(['utils/utils', 'plugin/charts/heatmap/heatmap-plugin'], function(Utils, HeatmapPlugin) {
|
||||
|
||||
// widget
|
||||
return Backbone.View.extend(
|
||||
@@ -17,13 +17,17 @@ return Backbone.View.extend(
|
||||
var self = this;
|
||||
this.app.datasets.request(request_dictionary, function() {
|
||||
|
||||
console.log(request_dictionary.groups);
|
||||
// loop through data groups
|
||||
for (var group_index in request_dictionary.groups) {
|
||||
// get group
|
||||
var group = request_dictionary.groups[group_index];
|
||||
|
||||
// draw plot
|
||||
new Plugin({
|
||||
'data' : request_dictionary.groups[0].values,
|
||||
'div' : self.options.canvas[0]
|
||||
});
|
||||
// draw plot
|
||||
var heatmap = new HeatmapPlugin({
|
||||
'data' : group.values,
|
||||
'div' : self.options.canvas[group_index]
|
||||
});
|
||||
}
|
||||
|
||||
// set chart state
|
||||
chart.state('ok', 'Heat map drawn.');
|
||||
|
||||
Reference in New Issue
Block a user