Created
July 26, 2019 21:11
-
-
Save imoutsatsos/23f484f7f2ff89b779cbf1c7ba3170bc to your computer and use it in GitHub Desktop.
Expeiments with D3 brushing using an assay plate heat map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<html> | |
<head> | |
<style> | |
rect.bordered { | |
stroke: #E6E6E6; | |
stroke-width:2px; | |
} | |
text.mono { | |
font-size: 9pt; | |
font-family: Consolas, courier; | |
fill: #aaa; | |
} | |
text.axis-workweek { | |
fill: #000; | |
} | |
text.axis-worktime { | |
fill: #000; | |
} | |
.selected{ | |
fill: rgb(128, 126, 0) !important; | |
} | |
</style> | |
<script src="http://d3js.org/d3.v4.js"></script> | |
</head> | |
<body> | |
<div id="chart"></div> | |
<div id="dataset-picker"> | |
</div> | |
<script type="text/javascript"> | |
//This works, and updates correctly when user clicks on dataset buttons | |
//Last Update NOV-24-2015 | |
var margin = { top: 50, right: 0, bottom: 50, left: 30 }, | |
width = 960 - margin.left - margin.right, | |
height = 720 - margin.top - margin.bottom, | |
gridSize = Math.floor(width / 48), | |
legendElementWidth = gridSize*2, | |
buckets = 9, | |
colors = ["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"], // alternatively colorbrewer.YlGnBu[9] | |
days = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32"] | |
//["A", "B", "C", "D", "E", "F", "G","H", "I", "J", "K", "L", "M", "N","O","P"]; | |
times = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48"]; | |
datasets = ["VB00009708", "VB00009778"]; | |
var thisDataset=new Array() | |
var svg = d3.select("#chart").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.attr("id","svgChart" ) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var dayLabels = svg.selectAll(".dayLabel") | |
.data(days) | |
.enter().append("text") | |
.text(function (d) { return d; }) | |
.attr("x", 0) | |
.attr("y", function (d, i) { return i * gridSize; }) | |
.style("text-anchor", "end") | |
.attr("transform", "translate(-6," + gridSize / 1.5 + ")") | |
.attr("class", function (d, i) { return ((i >= 0 && i <= 32) ? "dayLabel mono axis axis-workweek" : "dayLabel mono axis"); }); | |
var timeLabels = svg.selectAll(".timeLabel") | |
.data(times) | |
.enter().append("text") | |
.text(function(d) { return d; }) | |
.attr("x", function(d, i) { return i * gridSize; }) | |
.attr("y", 0) | |
.style("text-anchor", "middle") | |
.attr("transform", "translate(" + gridSize / 2 + ", -6)") | |
.attr("class", function(d, i) { return ((i >= 1 && i <= 48) ? "timeLabel mono axis axis-worktime" : "timeLabel mono axis"); }); | |
var heatmapChart = function(csvFilter, thisDataset) { | |
if (thisDataset.length==0){ | |
console.log('Starting fresh thisDataset!') | |
}else{ | |
console.log('old content thisDataset!') | |
}; | |
d3.csv("data.dlm", | |
function(csv) { | |
data=csv.filter(function(row) { return row['Metadata_Barcode'] == csvFilter ; }) | |
console.log(data.length, csvFilter); | |
/* create new dataset from filtered data */ | |
data.forEach(function (d) { | |
var el= { | |
Metadata_Barcode: d.Metadata_Barcode, | |
Metadata_RowNumber: +d.Metadata_RowNumber, | |
Metadata_Column: +d.Metadata_Column, | |
value: +d.Count_CELLS | |
}; | |
thisDataset.push(el) | |
} | |
) //end for each | |
console.log('This data is: ',csvFilter, thisDataset.length) | |
/* call function for chart initialization */ | |
initialize(thisDataset); | |
} | |
); | |
} //end heatmapChart | |
// Function that is triggered when brushing is performed | |
var updateChart = function () { | |
// Get the selection coordinate | |
d = d3.event.selection // looks like [ [12,11], [132,178]] | |
st=d[[0],[0]] //start | |
stX=st[[0],[0]] | |
stY=st[[0],[1]] | |
en=d[[0],[1]] //end | |
enX=en[[0],[0]] | |
enY=en[[0],[1]] | |
dwidth=enX-stX | |
dheight=enY-stY | |
//margins needed for correct determination of brushed objects | |
var margin = { top: 50, right: 0, bottom: 50, left: 30 } | |
console.log('Brushing logic',d,stX,stY,enX,enY,dwidth,dheight) | |
d3.selectAll('rect').each(function(rect_data,i){ | |
//console.log('Rect data:',rect_data) | |
if( | |
!d3.select( this).classed("selected") && | |
this.x.animVal.value+margin.left>=stX && | |
this.x.animVal.value+margin.left+this.width.animVal.value<=enX && | |
this.y.animVal.value+margin.top>=stY && | |
this.y.animVal.value+margin.top+this.height.animVal.value<=enY | |
) { | |
console.log('Rect Object xyValue:',this.x.animVal.value, this.y.animVal.value) | |
d3.select(this) | |
.classed("selected",true); | |
} | |
}); | |
} | |
var initialize= function(data) { | |
console.log('initializing: ', data.length) | |
//add brushing | |
// d3.select("#svgChart") | |
var margin = { top: 50, right: 0, bottom: 50, left: 30 } | |
var width = 960 - margin.left - margin.right | |
var height = 720 - margin.top - margin.bottom | |
var ch= height + margin.top + margin.bottom | |
var cw= width + margin.left + margin.right | |
theHeatMap=d3.select("#svgChart") | |
theHeatMap.call(d3.brush() | |
.extent([[22,50],[950,660]]) | |
.on("start end", updateChart)) | |
var colorScale = d3.scaleQuantile() | |
.domain([0, buckets - 1, d3.max(data, function (d) { return d.value; })]) | |
.range(colors); | |
var cards = svg.selectAll(".well") | |
.data(data, function(d) {return d.Metadata_RowNumber+':'+d.Metadata_Column;}); | |
cards.append("title"); | |
cards.enter().append("rect") | |
.attr("x", function(d) { return (d.Metadata_Column - 1) * gridSize; }) | |
.attr("y", function(d) { return (d.Metadata_RowNumber - 1) * gridSize; }) | |
.attr("rx", 4) | |
.attr("ry", 4) | |
.attr("class", "well bordered") | |
.attr("width", gridSize) | |
.attr("height", gridSize) | |
.style("fill", colors[0]); | |
// Join newly formed rect to data | |
//d3.selectAll('rect').data(data) | |
cards.transition().duration(1000) | |
.style("fill", function(d) { return colorScale(d.value); }); | |
cards.select("title").text(function(d) { return d.value+":"+d.Metadata_Barcode+":"+d.Metadata_RowNumber+":"+d.Metadata_Column }); | |
cards.exit().remove(); | |
var legend = svg.selectAll(".legend") | |
.data([0].concat(colorScale.quantiles()), function(d) { return d; }); | |
legend.enter().append("g") | |
.attr("class", "legend"); | |
legend.append("rect") | |
.attr("x", function(d, i) { return legendElementWidth * i; }) | |
.attr("y", height) | |
.attr("width", legendElementWidth) | |
.attr("height", gridSize / 2) | |
.style("fill", function(d, i) { return colors[i]; }); | |
legend.append("text") | |
.attr("class", "mono") | |
.text(function(d) { return "? " + Math.round(d); }) | |
.attr("x", function(d, i) { return legendElementWidth * i; }) | |
.attr("y", height + gridSize); | |
legend.exit().remove(); | |
}; | |
heatmapChart(datasets[0], thisDataset); | |
var datasetpicker = d3.select("#dataset-picker").selectAll(".dataset-button") | |
.data(datasets); | |
datasetpicker.enter() | |
.append("input") | |
.attr("value", function(d){ return "Dataset " + d }) | |
.attr("type", "button") | |
.attr("class", "dataset-button") | |
.on("click", function(d) { | |
thisDataset.length=0 //reset the global value array | |
heatmapChart(d, thisDataset); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment