Created
May 20, 2012 22:16
-
-
Save nachocab/2759731 to your computer and use it in GitHub Desktop.
D3 heatmap using Backbone.js and CoffeeScript
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
gene_name | lassa_day_0 | lassa_day_3 | lassa_day_6 | lassa_day_8 | lassa_day_10 | lassa_day_12 | marburg_day_0 | marburg_day_1 | marburg_day_3 | marburg_day_5 | marburg_day_7 | marburg_day_9 | ebola2_day_0 | ebola2_day_1 | ebola2_day_3 | ebola2_day_4 | ebola2_day_5 | ebola2_day_6 | ebola2_day_7 | ebola2_day_8 | lcmv_day_1 | lcmv_day_2 | lcmv_day_3 | lcmv_day_4 | lcmv_day_6 | lcmv_day_7 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
GENE_1 | 0 | 0.685 | 1.047 | 1.020 | 0.957 | 8e-01 | 0 | -0.855 | -1e+00 | -1.546 | -1.359 | -1.077 | 0 | -6e-01 | -0.219 | 1.295 | 0.923 | 1.216 | 1e+00 | 1.632 | 0.550218483523337 | -0.117805570597282 | 0.0732205574710542 | -0.564914153485835 | -0.359415199104997 | 0.00898927502093986 | |
GENE_2 | 0 | 2.459 | 3.299 | 3.086 | 2.658 | 3e+00 | 0 | 0.193 | 9e-01 | 1.433 | 1.246 | 1.091 | 0 | -1e-01 | 0.392 | 2.142 | 2.734 | 3.863 | 4e+00 | 4.216 | -0.0754593963815329 | 0.0967734690139892 | 0.28316769523287 | -0.412279746153753 | -0.324753442770228 | 0.288227993676913 | |
GENE_3 | 0 | 0.121 | 2.131 | 1.628 | 1.561 | 1e+00 | 0 | -0.939 | -1e+00 | -1.544 | -1.632 | -1.055 | 0 | 2e-02 | -0.049 | 0.008 | 0.393 | 1.031 | 3e-01 | 0.324 | 0.0499325227230727 | -0.0397401531526083 | 0.2124328794823 | 0.0731657480808578 | 0.0189570855935306 | -0.0184828331741145 | |
GENE_4 | 0 | 1.676 | 4.346 | 4.042 | 3.269 | 4e+00 | 0 | 0.115 | 8e-01 | 3.771 | 4.191 | 3.518 | 0 | 4e-02 | -0.035 | 0.762 | 2.161 | 1.605 | 3e+00 | 3.167 | 2.06449965734009 | -0.594799956525603 | -0.584504652469251 | -0.474603894859595 | -0.259726435432555 | 0.0579806583150321 | |
GENE_5 | 0 | -1.130 | -1.348 | -1.989 | -1.535 | -2e+00 | 0 | -2.844 | -3e+00 | -3.151 | -3.681 | -3.138 | 0 | 4e-01 | 0.706 | 0.878 | 0.994 | -0.876 | -2e+00 | -1.453 | -0.279590446885608 | 1.02224961630431 | 0.744880787446191 | 1.29460691183579 | -0.816449305811056 | -1.65694286101226 | |
GENE_6 | 0 | 0.065 | 0.668 | 1.288 | 0.038 | 8e-01 | 0 | 2.041 | 4e+00 | 7.365 | 4.109 | 2.953 | 0 | -1e-01 | -0.138 | 0.047 | -0.372 | 0.940 | 6e-01 | 0.371 | 1.36429228597838 | -0.0719999688548307 | 0.0451050774042987 | -0.453632098514707 | 0.0825695132840576 | 0.310973766985588 | |
GENE_7 | 0 | -0.842 | -1.330 | -0.383 | -0.452 | -6e-01 | 0 | 1.572 | 2e+00 | 1.370 | 1.675 | 1.577 | 0 | 1e-01 | 0.378 | 0.625 | -0.041 | 1.103 | 2e+00 | 2.277 | -0.0783406988717628 | -0.26408360918273 | -0.23333812657729 | -0.206511162329491 | -0.465512156559216 | -0.452181609819895 | |
GENE_8 | 0 | -1.223 | -1.071 | -1.381 | -1.294 | -1e+00 | 0 | -0.520 | -7e-01 | -0.552 | -0.298 | -0.021 | 0 | 1e-01 | 0.102 | 0.672 | 0.252 | -0.030 | 2e-01 | 0.252 | -0.286173221491367 | 0.129377596439413 | 0.193374893715429 | 0.366838960713438 | -0.142400769977739 | -0.276932933803457 | |
GENE_9 | 0 | 0.052 | 1.205 | 2.849 | 2.986 | 2e+00 | 0 | 1.087 | 1e+00 | 2.391 | 4.399 | 4.194 | 0 | -4e-02 | -0.018 | 1.014 | 1.859 | 4.500 | 6e+00 | 6.571 | 0.00422716134743392 | -0.162662158890658 | -0.0792976044306068 | -0.108238651309485 | -0.320366084048266 | -0.255239845585953 | |
GENE_10 | 0 | 1.263 | 1.931 | 1.826 | 2.448 | 2e+00 | 0 | 0.321 | 1e+00 | 3.149 | 2.945 | 2.887 | 0 | -2e-02 | 0.211 | 3.930 | 4.839 | 4.302 | 4e+00 | 4.675 | 1.64521963175084 | -0.754892799863792 | -0.526039721636022 | -0.478968546603597 | -0.0684222766654527 | -0.122200661558602 |
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> | |
<html lang='en'> | |
<head> | |
<title>Backboning</title> | |
<meta charset='UTF-8'/> | |
<meta content='Nacho Caballero' name='author' /> | |
<script src='http://code.jquery.com/jquery-1.7.1.min.js'></script> | |
<script src='http://documentcloud.github.com/underscore/underscore.js'></script> | |
<script src='http://documentcloud.github.com/backbone/backbone.js'></script> | |
<script src='http://mbostock.github.com/d3/d3.js'></script> | |
<script src='main.js'></script> | |
<link href='main.css' rel='stylesheet' /> | |
<style> | |
body { | |
width: 1400px; | |
margin: 0 auto; } | |
h1 { | |
font-size: 20px; | |
font-weight: bold; | |
color: white; } | |
text { | |
font-family: Helvetica, Arial, sans-serif; | |
font-size: 16px; } | |
#heatmap .row { | |
cursor: pointer; } | |
#heatmap .row rect { | |
stroke: black; | |
stroke-width: 2px; } | |
#heatmap .row.current.clicked rect { | |
stroke: black; } | |
#heatmap .row.current text { | |
font-weight: bold; } | |
#heatmap .column text { | |
font-weight: bold; } | |
</style> | |
</head> | |
<body> | |
<header></header> | |
<main> | |
<svg id='heatmap'></svg> | |
<svg id='pcp'></svg> | |
</main> | |
<footer> | |
<p> | |
Built with | |
<a href='http://d3js.org/'>d3.js</a>. | |
</p> | |
<a href='#' rel='author'>Nacho Caballero</a> | |
</footer> | |
</body> | |
</html> |
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
$(document).ready -> | |
d3.text "genes.csv", (text) -> | |
genes = d3.csv.parse text | |
geneExpressionModel = new Backbone.Model | |
geneExpressionModel.set conditionNames: getConditionNames(genes) | |
geneExpressionModel.set geneNames: genes.map((gene) -> gene.gene_name) | |
geneExpressionModel.set geneExpressions: getGeneExpressions(genes, geneExpressionModel.get "conditionNames") | |
geneExpressionModel.set extent: d3.extent($.map(geneExpressionModel.get("geneExpressions"), (item)-> item )) # flatten matrix | |
geneExpressionModel.set clusters: genes.map (gene) -> gene.cluster | |
geneExpressionModel.set clusterColor: d3.scale.category20() | |
heatmap = new Heatmap(el: "#heatmap", model: geneExpressionModel) | |
Heatmap = Backbone.View.extend | |
initialize: -> | |
@render() | |
render: -> | |
geneExpressions = @model.get "geneExpressions" | |
conditionNames = @model.get "conditionNames" | |
geneNames = @model.get "geneNames" | |
extent = @model.get "extent" | |
clusters = @model.get "clusters" | |
clusterColor = @model.get "clusterColor" | |
heatmapColor = d3.scale.linear().domain([-1.5,0,1.5]).range(["#278DD6","#fff","#d62728"]) | |
textScaleFactor = 15 | |
conditionNamesMargin = d3.max(conditionNames.map((conditionName) -> conditionName.length)) | |
geneNamesMargin = d3.max(geneNames.map((geneName) -> geneName.length)) | |
margin = | |
top: conditionNamesMargin*textScaleFactor | |
right: 150 | |
bottom: conditionNamesMargin*textScaleFactor | |
left: geneNamesMargin*textScaleFactor | |
cell_size = 30 | |
width = cell_size*geneExpressions[0].length | |
height = cell_size*geneNames.length | |
heatmap = d3.select(@el).append("svg") | |
.attr("width", width + margin.right + margin.left) | |
.attr("height", height + margin.top + margin.bottom) | |
.attr("id","heatmap") | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") | |
x = d3.scale.ordinal().domain(d3.range(geneExpressions[0].length)).rangeBands([0, width]) | |
y = d3.scale.ordinal().domain(d3.range(geneNames.length)).rangeBands([0, height]) | |
columns = heatmap.selectAll(".column") | |
.data(conditionNames) | |
.enter().append("g") | |
.attr("class", "column") | |
.attr("transform", (d, i) -> "translate(" + x(i) + ")rotate(-90)" ) | |
# Add condition names (top) | |
columns.append("text") | |
.attr("x", 6) | |
.attr("y", x.rangeBand() / 2) | |
.attr("dy", "-.5em") # .32em before rotating | |
.attr("dx", ".5em") | |
.attr("text-anchor", "start") | |
.attr("transform","rotate(45)") | |
.text((d, i) -> conditionNames[i] ) | |
getRow = (row) -> | |
cell = d3.select(this).selectAll(".cell") | |
.data(row) | |
.enter().append("rect") | |
.attr("class", "cell") | |
.attr("x", (d,i) -> x(i)) | |
.attr("width", x.rangeBand()) | |
.attr("height", x.rangeBand()) | |
.text((d) -> d) | |
.style("fill", (d) -> heatmapColor(d)) | |
rows = heatmap.selectAll(".row") | |
.data(geneExpressions) | |
.enter().append("g") | |
.attr("class", "row") | |
.attr("name", (d,i) -> "gene_" + i) | |
.attr("transform", (d, i) -> "translate(0," + y(i) + ")") | |
.each(getRow) | |
# Add gene names | |
rows.append("text") | |
.attr("x", -6) | |
.attr("y", x.rangeBand() / 2) | |
.attr("dy", ".32em") | |
.attr("text-anchor", "end") | |
.text((d, i) -> geneNames[i]) | |
getGeneExpressions = (genes, conditionNames) -> | |
genes.map (gene) -> | |
conditionNames.map (condition) -> | |
+gene[condition] # make numeric | |
getConditionNames = (genes) -> | |
Object.keys(genes[0]).filter (columnName) -> | |
!columnName.match(/cluster/) && isNumber(genes[1][columnName]) | |
isNumber = (n) -> | |
!isNaN(parseFloat(n)) and isFinite(n) | |
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
// Generated by CoffeeScript 1.3.1 | |
(function() { | |
var Heatmap, getConditionNames, getGeneExpressions, isNumber; | |
$(document).ready(function() { | |
return d3.text("genes.csv", function(text) { | |
var geneExpressionModel, genes, heatmap; | |
genes = d3.csv.parse(text); | |
geneExpressionModel = new Backbone.Model; | |
geneExpressionModel.set({ | |
conditionNames: getConditionNames(genes) | |
}); | |
geneExpressionModel.set({ | |
geneNames: genes.map(function(gene) { | |
return gene.gene_name; | |
}) | |
}); | |
geneExpressionModel.set({ | |
geneExpressions: getGeneExpressions(genes, geneExpressionModel.get("conditionNames")) | |
}); | |
geneExpressionModel.set({ | |
extent: d3.extent($.map(geneExpressionModel.get("geneExpressions"), function(item) { | |
return item; | |
})) | |
}); | |
geneExpressionModel.set({ | |
clusters: genes.map(function(gene) { | |
return gene.cluster; | |
}) | |
}); | |
geneExpressionModel.set({ | |
clusterColor: d3.scale.category20() | |
}); | |
return heatmap = new Heatmap({ | |
el: "#heatmap", | |
model: geneExpressionModel | |
}); | |
}); | |
}); | |
Heatmap = Backbone.View.extend({ | |
initialize: function() { | |
return this.render(); | |
}, | |
render: function() { | |
var cell_size, clusterColor, clusters, columns, conditionNames, conditionNamesMargin, extent, geneExpressions, geneNames, geneNamesMargin, getRow, heatmap, heatmapColor, height, margin, rows, textScaleFactor, width, x, y; | |
geneExpressions = this.model.get("geneExpressions"); | |
conditionNames = this.model.get("conditionNames"); | |
geneNames = this.model.get("geneNames"); | |
extent = this.model.get("extent"); | |
clusters = this.model.get("clusters"); | |
clusterColor = this.model.get("clusterColor"); | |
heatmapColor = d3.scale.linear().domain([-1.5, 0, 1.5]).range(["#278DD6", "#fff", "#d62728"]); | |
textScaleFactor = 15; | |
conditionNamesMargin = d3.max(conditionNames.map(function(conditionName) { | |
return conditionName.length; | |
})); | |
geneNamesMargin = d3.max(geneNames.map(function(geneName) { | |
return geneName.length; | |
})); | |
margin = { | |
top: conditionNamesMargin * textScaleFactor, | |
right: 150, | |
bottom: conditionNamesMargin * textScaleFactor, | |
left: geneNamesMargin * textScaleFactor | |
}; | |
cell_size = 30; | |
width = cell_size * geneExpressions[0].length; | |
height = cell_size * geneNames.length; | |
heatmap = d3.select(this.el).append("svg").style("margin-top", "100px").attr("width", width + margin.right + margin.left).attr("height", height + margin.top + margin.bottom).attr("id", "heatmap").append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
x = d3.scale.ordinal().domain(d3.range(geneExpressions[0].length)).rangeBands([0, width]); | |
y = d3.scale.ordinal().domain(d3.range(geneNames.length)).rangeBands([0, height]); | |
columns = heatmap.selectAll(".column").data(conditionNames).enter().append("g").attr("class", "column").attr("transform", function(d, i) { | |
return "translate(" + x(i) + ")rotate(-90)"; | |
}); | |
columns.append("text").attr("x", 6).attr("y", x.rangeBand() / 2).attr("dy", "-.5em").attr("dx", ".5em").attr("text-anchor", "start").attr("transform", "rotate(45)").text(function(d, i) { | |
return conditionNames[i]; | |
}); | |
getRow = function(row) { | |
var cell; | |
return cell = d3.select(this).selectAll(".cell").data(row).enter().append("rect").attr("class", "cell").attr("x", function(d, i) { | |
return x(i); | |
}).attr("width", x.rangeBand()).attr("height", x.rangeBand()).text(function(d) { | |
return d; | |
}).style("fill", function(d) { | |
return heatmapColor(d); | |
}); | |
}; | |
rows = heatmap.selectAll(".row").data(geneExpressions).enter().append("g").attr("class", "row").attr("name", function(d, i) { | |
return "gene_" + i; | |
}).attr("transform", function(d, i) { | |
return "translate(0," + y(i) + ")"; | |
}).each(getRow); | |
return rows.append("text").attr("x", -6).attr("y", x.rangeBand() / 2).attr("dy", ".32em").attr("text-anchor", "end").text(function(d, i) { | |
return geneNames[i]; | |
}); | |
} | |
}); | |
getGeneExpressions = function(genes, conditionNames) { | |
return genes.map(function(gene) { | |
return conditionNames.map(function(condition) { | |
return +gene[condition]; | |
}); | |
}); | |
}; | |
getConditionNames = function(genes) { | |
return Object.keys(genes[0]).filter(function(columnName) { | |
return !columnName.match(/cluster/) && isNumber(genes[1][columnName]); | |
}); | |
}; | |
isNumber = function(n) { | |
return !isNaN(parseFloat(n)) && isFinite(n); | |
}; | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment