#Unbelievable clickme d3 straight from R
I deserve no credit for this. Go to clickme for the guy that deserves all the credit. I just simply put it in Gist form for it to show up on bl.ocks.org
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>PCP Heatmap</title>
<script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
<script src="//code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="//documentcloud.github.com/underscore/underscore.js"></script>
<script src="//documentcloud.github.com/backbone/backbone.js"></script>
<script src="//twitter.github.com/bootstrap/assets/js/bootstrap-tooltip.js"></script>
<script src="//twitter.github.com/bootstrap/assets/js/bootstrap-popover.js"></script>
<script src="//mbostock.github.com/d3/d3.js"></script>
<script src="helper.js"></script>
<script src="longitudinal_model.js"></script>
<script src="dashboard_view.js"></script>
<script src="heatmap_view.js"></script>
<script src="pcp_view.js"></script>
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet">
<link href="leanback_style.css" rel="stylesheet">
<link href="longitudinal.css" rel="stylesheet">
</head>
<body>
<div id='dashboard'>
<div class='clusters'></div>
<h1></h1>
</div>
<main>
<svg id='heatmap'></svg>
<svg id='pcp'></svg>
</main>
<script type="text/javascript">
var urlVars = getUrlVars();
$(document).ready(function() {
d3.text("data.csv", function(text) {
var parsedGenes = d3.csv.parse(text);
var userOptions = { urlVars: urlVars, rowNameColumn: "gene_symbol", rowType: "genes", yAxisName: "log-ratio" };
var model = new window.LongitudinalModel(parsedGenes, userOptions);
var dashboardView = new window.DashboardView({ el: "#dashboard", model: model});
var heatmapView = new window.HeatmapView({ el: "#heatmap", model: model});
var pcpView = new window.PcpView({ el: "#pcp", model: model});
d3.select("body").style("padding-top", d3.select("#dashboard").node().offsetHeight);
resetOnClick(model);
});
});
</script>
</body>
</html>
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
window.DashboardView = (function(_super) {
__extends(DashboardView, _super);
function DashboardView() {
return DashboardView.__super__.constructor.apply(this, arguments);
}
DashboardView.prototype.initialize = function() {
var _this = this;
this.render();
this.model.on("change:currentCluster", function() {
return _this.showTitle();
});
return this.model.on("change:currentTag", function() {
return _this.showTitle();
});
};
DashboardView.prototype.events = function() {
return {
"click #dashboard .clusters span": "changeCurrentCluster"
};
};
DashboardView.prototype.changeCurrentCluster = function(e) {
var currentCluster;
e.stopPropagation();
this.model.attributes['currentTag'] = null;
d3.selectAll(".tag_name").classed("current", 0);
currentCluster = d3.select(e.target);
d3.selectAll(".clusters span").classed("current", 0);
if (currentCluster && this.model.get("currentCluster") === currentCluster.attr("name")) {
return this.model.set({
currentCluster: null
});
} else {
currentCluster.classed("current", 1);
return this.model.set({
currentCluster: currentCluster.attr("name")
});
}
};
DashboardView.prototype.showTitle = function() {
var currentCluster, currentTag, title;
title = "" + (this.getCurrentRows().length) + " " + this.model.options.rowType;
if (this.model.options.showGroups) {
title += " from " + (joinSentence(this.model.columnGroups));
}
if (this.model.options.showClusters && (currentCluster = this.model.get("currentCluster"))) {
title += " (Cluster " + currentCluster + ")";
}
if (this.model.options.showTags && (currentTag = this.model.get("currentTag"))) {
title += " (Tagged " + currentTag + ")";
}
d3.select("title").text(title);
return d3.select("#dashboard h1").text(title);
};
DashboardView.prototype.getCurrentRows = function() {
var currentCluster, currentTag;
if (this.model.options.showClusters && (currentCluster = this.model.get("currentCluster"))) {
return d3.selectAll(".row[cluster='" + currentCluster + "']")[0];
} else if (this.model.options.showTags && (currentTag = this.model.get("currentTag"))) {
return d3.selectAll(".tag[name='" + currentTag + "']")[0];
} else {
return this.model.parsedData;
}
};
DashboardView.prototype.render = function() {
var _this = this;
this.showTitle();
if (this.model.options.showClusters) {
return d3.select("#dashboard .clusters").selectAll("span").data(this.model.clusterNames).enter().append("span").attr("name", function(d) {
return d;
}).text(function(d) {
return "Cluster " + d;
}).style("background", function(d) {
return window.clusterColor(d);
});
}
};
return DashboardView;
})(Backbone.View);
}).call(this);
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
window.HeatmapView = (function(_super) {
__extends(HeatmapView, _super);
function HeatmapView() {
return HeatmapView.__super__.constructor.apply(this, arguments);
}
HeatmapView.prototype.initialize = function() {
var _this = this;
if (!this.model.options.hideHeatmap) {
this.render();
this.model.on("change:currentRowId", function() {
return _this.showCurrentRow();
});
this.model.on("change:clickedRowId", function() {
return _this.showClickedRow();
});
this.model.on("change:currentCluster", function() {
return _this.showCurrentCluster();
});
return this.model.on("change:currentTag", function() {
return _this.showCurrentTag();
});
}
};
HeatmapView.prototype.events = function() {
return {
"mouseover .cell": "changeCurrentRowId",
"mouseout .row": "changeCurrentRowId",
"click .row": "changeClickedRowId",
"click .tag": "changeCurrentTag",
"click .tag_name": "changeCurrentTag"
};
};
HeatmapView.prototype.render = function() {
var columnName, rowName,
_this = this;
this.heatmapColor = d3.scale.linear().domain([-1.5, 0, 1.5]).range(["#278DD6", "#fff", "#d62728"]);
this.rowTextScaleFactor = 15;
this.columnTextScaleFactor = 10;
this.columnNamesMargin = d3.max((function() {
var _i, _len, _ref, _results;
_ref = this.model.columnNames;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
columnName = _ref[_i];
_results.push(columnName.length);
}
return _results;
}).call(this));
this.rowNamesMargin = d3.max((function() {
var _i, _len, _ref, _results;
_ref = this.model.rowNames;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rowName = _ref[_i];
_results.push(rowName.length);
}
return _results;
}).call(this));
this.margin = {
top: 250,
right: this.calculateRightMargin(),
bottom: 50,
left: 50
};
this.cellSize = 25;
this.width = this.cellSize * this.model.columnNames.length;
this.height = this.cellSize * this.model.rowNames.length;
this.heatmap = d3.select(this.el).attr("width", this.width + this.margin.right + this.margin.left).attr("height", this.height + this.margin.top + this.margin.bottom).attr("class", "heatmap").append("g").attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
this.x = d3.scale.ordinal().domain(d3.range(this.model.longitudinalData[0].length)).rangeBands([0, this.width]);
this.y = d3.scale.ordinal().domain(d3.range(this.model.rowNames.length)).rangeBands([0, this.height]);
this.columns = this.heatmap.selectAll(".column").data(this.model.columnNames).enter().append("g").attr("class", "column");
this.columns.append("text").attr("x", 6).attr("y", this.x.rangeBand() / 2).attr("dy", "-.5em").attr("dx", ".5em").attr("text-anchor", "start").attr("transform", function(d, i) {
return "translate(" + (_this.x(i)) + ") rotate(-45)";
}).text(function(d, i) {
return _this.model.columnNames[i];
});
this.addRows();
if (this.model.options.tagFile) {
this.addTags();
}
this.$("rect.cell").tooltip({
title: function() {
return this.__data__.condition.split("_").join(" ") + "<br>" + d3.round(this.__data__.value, 2);
},
placement: "top"
});
return this.$("rect.tag").tooltip({
title: function() {
return this.__data__;
},
placement: "top"
});
};
HeatmapView.prototype.calculateRightMargin = function() {
var maxrowNameLength;
maxrowNameLength = d3.max(this.model.rowNames.map(function(x) {
return x.length;
}));
return maxrowNameLength * 18;
};
HeatmapView.prototype.addRows = function() {
var getRow, rows, that,
_this = this;
that = this;
getRow = function(row) {
var cell,
_this = this;
return cell = d3.select(this).selectAll(".cell").data(row).enter().append("rect").attr("class", "cell").attr("x", function(d, i) {
return that.x(i);
}).attr("width", that.x.rangeBand()).attr("height", that.x.rangeBand()).text(function(d) {
return d;
}).style("fill", function(d) {
return that.heatmapColor(d.value);
});
};
rows = this.heatmap.selectAll(".row").data(this.model.longitudinalData).enter().append("g").attr("class", "row").attr("row-id", function(d, i) {
return _this.model.rowIds[i];
}).attr("cluster", function(d, i) {
return _this.model.clusters[i];
}).attr("transform", function(d, i) {
return "translate(0," + (_this.y(i)) + ")";
}).each(getRow);
if (!this.model.options.hideRowNames) {
return rows.append("text").attr("x", this.width + this.calculateRightMargin()).attr("y", this.x.rangeBand() / 2).attr("dy", ".32em").attr("text-anchor", "end").text(function(d, i) {
return _this.model.rowNames[i];
});
}
};
HeatmapView.prototype.addTags = function() {
var heatmapWidth, maxTagNameLength, tagMargin, tagNames, tagScale, tagSize, tags,
_this = this;
tags = "";
$.ajax({
url: this.model.options.tagFile,
context: document.body,
async: false,
success: function(data) {
return tags = window.parseTags(data);
}
});
tagNames = window.getTagNames(tags);
maxTagNameLength = d3.max(tagNames.map(function(x) {
return x.length;
})) * 12;
tagSize = this.cellSize / 2;
tagMargin = 12;
heatmapWidth = d3.select("#heatmap").node().offsetWidth;
tagScale = d3.scale.ordinal().domain(d3.range(tagNames.length)).rangeBands([0, (tagNames.length - 1) * (tagSize + tagMargin)]);
this.heatmap.selectAll(".row").selectAll(".tag").data(function(d, i) {
return tags[_this.model.rowNames[i]];
}).enter().append("rect").attr("class", "tag").attr("x", heatmapWidth).attr("y", this.x.rangeBand() / 4).attr("transform", function(d, i) {
return "translate(" + tagScale(tagNames.indexOf(d)) + ",0)";
}).attr("width", this.x.rangeBand() / 2).attr("height", this.x.rangeBand() / 2).attr("row-id", function(d) {
return d;
}).text(function(d) {
return d;
}).style("fill", function(d, i) {
return window.tagColor(d);
}).style("stroke", "none");
this.heatmap.selectAll(".tag_name").data(tagNames).enter().append("text").attr("class", "tag_name").attr("dx", heatmapWidth + 10).attr("dy", 0).attr("transform", function(d, i) {
return "translate(" + tagScale(tagNames.indexOf(d)) + (",0) rotate(-45 " + heatmapWidth + " 0)");
}).attr("text-anchor", "start").attr("name", function(d) {
return d;
}).text(function(d) {
return d;
}).attr("fill", "black");
return d3.select("#heatmap").attr("width", parseInt(d3.select("#heatmap").attr("width")) + tagNames.length * 25 + 100);
};
HeatmapView.prototype.changeCurrentRowId = function(e) {
e.stopPropagation();
return this.model.set({
currentRowId: e.type === "mouseover" ? d3.select(e.target.parentNode).attr("row-id") : null
});
};
HeatmapView.prototype.changeClickedRowId = function(e) {
e.stopPropagation();
return this.model.set({
clickedRowId: d3.select(e.target.parentNode).attr("row-id")
});
};
HeatmapView.prototype.changeCurrentTag = function(e) {
var currentTag;
e.stopPropagation();
this.model.attributes['currentCluster'] = null;
d3.selectAll(".clusters span").classed("current", 0);
d3.selectAll(".tag_name").classed("current", 0);
currentTag = d3.select(e.target);
if (currentTag && this.model.get("currentTag") === currentTag.attr("name")) {
return this.model.set({
currentTag: null
});
} else {
d3.selectAll(".tag_name[row-id=" + (currentTag.text()) + "]").classed("current", 1);
return this.model.set({
currentTag: currentTag.text()
});
}
};
HeatmapView.prototype.showCurrentRow = function() {
var currentRowId, currentRowIdId;
d3.selectAll(".row").filter(":not(.clicked)").classed("current", 0);
currentRowIdId = this.model.get("currentRowIdId");
if (currentRowIdId != null) {
currentRowId = this.heatmap.select("[row-id=" + currentRowIdId + "]");
return currentRowId.classed("current", 1);
}
};
HeatmapView.prototype.showClickedRow = function() {
var clickedRow, clickedRowId;
clickedRowId = this.model.get("clickedRowId");
if (clickedRowId != null) {
clickedRow = this.heatmap.select("[row-id=" + clickedRowId + "]");
d3.select("#pcp").style("top", Math.max(150, clickedRow.filter(".row").node().offsetParent.scrollTop) + 50);
this.removeClickedRow();
return clickedRow.classed("current clicked", 1);
}
};
HeatmapView.prototype.removeClickedRow = function() {
return d3.selectAll(".row").classed("current clicked", 0);
};
HeatmapView.prototype.showCurrentCluster = function() {
var currentCluster, rowsToUpdate,
_this = this;
currentCluster = this.model.get("currentCluster");
$(".row").hide();
if (currentCluster) {
rowsToUpdate = this.heatmap.selectAll(".row[cluster='" + currentCluster + "']");
} else {
rowsToUpdate = this.heatmap.selectAll(".row");
}
$(rowsToUpdate[0]).show();
return rowsToUpdate.attr("transform", function(d, i) {
return "translate(0," + (_this.y(i)) + ")";
});
};
HeatmapView.prototype.showCurrentTag = function() {
var currentTag, rowsToUpdate,
_this = this;
currentTag = this.model.get("currentTag");
$(".row").hide();
if (currentTag) {
rowsToUpdate = d3.selectAll($(".tag[row-id='" + currentTag + "']").parent());
} else {
rowsToUpdate = this.heatmap.selectAll(".row");
}
$(rowsToUpdate[0]).show();
return rowsToUpdate.attr("transform", function(d, i) {
return "translate(0," + (_this.y(i)) + ")";
});
};
return HeatmapView;
})(Backbone.View);
}).call(this);
// Generated by CoffeeScript 1.4.0
(function() {
window.clusterColor = d3.scale.category10();
window.tagColor = d3.scale.category20();
window.no_tag = "-";
window.parseTags = function(content) {
var tag_lines, tags;
tag_lines = d3.csv.parseRows(content);
tags = {};
tag_lines.map(function(tag_line) {
var values;
values = tag_line.slice(1);
return tags[tag_line[0]] = values.indexOf(window.no_tag) === -1 ? values : [];
});
return tags;
};
window.getFrequencies = function(array) {
var frequencies;
frequencies = {};
_.chain(array).groupBy(function(p) {
return p;
}).each(function(e, i) {
return frequencies[i] = _.size(e);
});
return frequencies;
};
window.getTagNames = function(tags) {
var tagFrequencies, tagValues;
tagValues = _.chain(tags).values().flatten();
tagFrequencies = window.getFrequencies(tagValues.value());
return tagValues.unique().sortBy(function(x) {
return tagFrequencies[x];
}).value().reverse();
};
window.replace = function(array, replaceItem, replaceWith) {
var item, _i, _len, _results;
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
item = array[_i];
if (item === replaceItem) {
_results.push(replaceWith);
} else {
_results.push(item);
}
}
return _results;
};
window.isNumber = function(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
window.getUrlVars = function() {
var vars;
vars = {};
window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/g, function(m, key, value) {
return vars[key] = value;
});
return vars;
};
window.resetOnClick = function(model) {
return d3.select("body").on("click", function() {
model.set({
clickedRowId: null
});
model.set({
currentTag: null
});
d3.selectAll(".tag_name").classed("current", 0);
model.set({
currentCluster: null
});
return d3.selectAll(".clusters span").classed("current", 0);
});
};
window.joinSentence = function(arr) {
var arr2, last, sentence;
arr2 = arr.slice(0);
last = arr2.pop();
if (arr2.length > 0) {
sentence = arr2.join(", ");
return sentence + " and " + last;
} else {
return last;
}
};
}).call(this);
/* clearfix */
.clearfix:before,
.clearfix:after {
content: "";
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
zoom: 1;
}
body, .gist-meta {
font: 14px Helvetica Neue;
/*background: #f4f4f4 url(../images/background.png);*/
}
a {
color: steelblue !important;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
body, .gist {
text-rendering: optimizeLegibility;
margin-top: 1em;
}
.body {
width: 960px;
margin: auto;
}
.logo {
color: steelblue;
}
.readme {
margin-bottom: 3em;
}
.time {
color: #666;
font-size: smaller;
font-style: oblique;
}
h1 {
font-size: 36px;
font-weight: 300;
}
h2 {
font-weight: normal;
color: #666;
}
h2 .description {
color: #000;
font-weight: bold;
}
iframe {
width: 960px;
height: 500px;
border: 1px solid #DEDEDE;
}
.about {
display: block;
font-weight: 300;
line-height: 60px;
}
.about .domain {
color: black;
}
.right {
float: right;
}
body {
margin: 0 auto;
padding: 50px 0 0 0; }
main {
display: block; }
text {
font-family: Helvetica, Arial, sans-serif;
font-size: 16px; }
#landing {
font-size: 24px;
margin: 0 auto;
width: 960px; }
#landing a {
font-weight: bold; }
.pcp {
position: absolute;
cursor: pointer; }
.pcp .title {
font-size: 25px;
font-weight: bold; }
.pcp .expression-line {
stroke-width: 6;
stroke-opacity: 0.5;
stroke-linecap: round;
stroke-join: round;
fill: none; }
.pcp .expression-line.current {
stroke-opacity: 1;
stroke: #d62728; }
.pcp .expression-text {
font-weight: bold; }
.pcp .expression-point {
fill: white;
stroke: black;
stroke-width: 4px; }
.pcp .axis path, .pcp .axis .tick {
stroke: black;
stroke-opacity: 1;
stroke-width: 2; }
.pcp .axis line {
shape-rendering: crispEdges; }
.pcp .axis.zero {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
stroke-dasharray: 8, 5;
fill: none; }
.pcp .axis text {
font-weight: bold; }
.tag_name {
fill: black; }
.tag_name:hover {
fill: #d62728; }
.tag_name.current {
fill: #d62728; }
.heatmap {
float: left;
cursor: pointer; }
.heatmap .row rect {
stroke: black;
stroke-width: 1px; }
.heatmap .row.current.clicked rect {
stroke: black; }
.heatmap .row.current text {
font-weight: bold; }
.heatmap .column text {
font-weight: normal; }
#dashboard {
position: fixed;
top: 0;
width: 100%;
z-index: 9999;
background-color: black;
padding: 20px; }
#dashboard h1 {
line-height: 40px;
color: white;
margin: 0;
font-family: Lobster, Helvetica, Arial, sans-serif;
font-weight: bold; }
#dashboard .clusters {
float: right;
width: 800px;
padding: 0 40px 0 0;
font-family: Lobster, Georgia, serif;
font-weight: bold; }
#dashboard .clusters span {
cursor: pointer;
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
color: white;
width: 140px;
float: left;
font-size: 30px;
margin: 0 5px 5px 0;
padding: 5px 0;
text-align: center;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px; }
#dashboard .clusters span.current {
-webkit-box-shadow: 0px 4px 4px 0px #aaaaaa;
-moz-box-shadow: 0px 4px 4px 0px #aaaaaa;
box-shadow: 0px 4px 4px 0px #aaaaaa; }
#dashboard .clusters span:active {
position: relative;
top: 3px; }
.tooltip {
position: absolute;
z-index: 1020;
display: block;
padding: 5px;
font-size: 20px;
transform: translate(12px, 0);
opacity: 0;
visibility: visible; }
.tooltip.in {
opacity: 0.8;
filter: alpha(opacity=80); }
.tooltip.top {
margin-top: -2px; }
.tooltip.right {
margin-left: 2px; }
.tooltip.bottom {
margin-top: 2px; }
.tooltip.left {
margin-left: -2px; }
.tooltip.top .tooltip-arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top: 5px solid black;
border-right: 5px solid transparent;
border-left: 5px solid transparent; }
.tooltip.left .tooltip-arrow {
top: 50%;
right: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid black; }
.tooltip.bottom .tooltip-arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-right: 5px solid transparent;
border-bottom: 5px solid black;
border-left: 5px solid transparent; }
.tooltip.right .tooltip-arrow {
top: 50%;
left: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-right: 5px solid black;
border-bottom: 5px solid transparent; }
.tooltip-inner {
max-width: 200px;
padding: 3px 8px;
color: white;
font-weight: bold;
text-align: center;
text-decoration: none;
background-color: black;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px; }
.tooltip-arrow {
position: absolute;
width: 0;
height: 0; }
.popover {
position: absolute;
top: 0;
left: 0;
z-index: 1010;
display: none;
padding: 5px; }
.popover.top {
margin-top: -5px; }
.popover.right {
margin-left: 5px; }
.popover.bottom {
margin-top: 5px; }
.popover.left {
margin-left: -5px; }
.popover.top .arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top: 5px solid black;
border-right: 5px solid transparent;
border-left: 5px solid transparent; }
.popover.right .arrow {
top: 50%;
left: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-right: 5px solid black;
border-bottom: 5px solid transparent; }
.popover.bottom .arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-right: 5px solid transparent;
border-bottom: 5px solid black;
border-left: 5px solid transparent; }
.popover.left .arrow {
top: 50%;
right: 0;
margin-top: -5px;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid black; }
.popover .arrow {
position: absolute;
width: 0;
height: 0; }
.popover-inner {
width: 280px;
padding: 3px;
overflow: hidden;
background: black;
background: rgba(0, 0, 0, 0.8);
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); }
.popover-title {
padding: 9px 15px;
line-height: 1;
background-color: #f5f5f5;
border-bottom: 1px solid #eeeeee;
-webkit-border-radius: 3px 3px 0 0;
-moz-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0; }
.popover-content {
padding: 14px;
background-color: white;
-webkit-border-radius: 0 0 3px 3px;
-moz-border-radius: 0 0 3px 3px;
border-radius: 0 0 3px 3px;
-webkit-background-clip: padding-box;
-moz-background-clip: padding-box;
background-clip: padding-box; }
.popover-content p, .popover-content ul, .popover-content ol {
margin-bottom: 0; }
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
window.LongitudinalModel = (function(_super) {
var defaults;
__extends(LongitudinalModel, _super);
function LongitudinalModel() {
return LongitudinalModel.__super__.constructor.apply(this, arguments);
}
defaults = {
currentRowId: null,
clickedRowId: null,
currentCluster: null,
currentTag: null
};
LongitudinalModel.prototype.initialize = function(parsedData, userOptions) {
var id;
if (userOptions == null) {
userOptions = {};
}
this.options = {
rowNameColumn: userOptions.rowNameColumn || "id",
yAxisName: userOptions.yAxisName || "log-ratio",
specialColumnNames: userOptions.specialColumnNames || ["cluster"],
rowType: userOptions.rowType,
tagFile: userOptions.urlVars["tags"],
showGroups: userOptions.urlVars["groups"],
hideHeatmap: userOptions.urlVars["no_heatmap"],
hidePCP: userOptions.urlVars["no_pcp"],
hideRowNames: userOptions.urlVars["no_row_names"]
};
this.options.specialColumnNames = _.union(this.options.specialColumnNames, this.options.rowNameColumn);
this.parsedData = parsedData;
this.rowNames = _.pluck(this.parsedData, this.options.rowNameColumn);
this.rowIds = (function() {
var _i, _ref, _results;
_results = [];
for (id = _i = 1, _ref = this.parsedData.length; 1 <= _ref ? _i <= _ref : _i >= _ref; id = 1 <= _ref ? ++_i : --_i) {
_results.push("_row_" + id);
}
return _results;
}).call(this);
this.columnNames = this.getColumnNames();
this.columnGroups = this.getColumnGroups();
this.longitudinalData = this.getLongitudinalData();
this.groupedLongitudinalData = this.getGroupedLongitudinalData();
this.clusters = _.pluck(this.parsedData, "cluster");
this.options.showClusters = _.uniq(this.clusters).length > 1;
return this.clusterNames = this.getClusterNames();
};
LongitudinalModel.prototype.getRowName = function(rowName) {
return this.rowNames[this.rowIds.indexOf(rowName)];
};
LongitudinalModel.prototype.getColumnGroups = function() {
return _.chain(this.columnNames).map(function(columnName) {
return columnName.split("_")[0];
}).uniq().value();
};
LongitudinalModel.prototype.getLongitudinalValueExtent = function() {
var longitudinalValues;
longitudinalValues = _.flatten(this.longitudinalData.map(function(longitudinalDataRow) {
return longitudinalDataRow.map(function(item) {
return item.value;
});
}));
return d3.extent(longitudinalValues);
};
LongitudinalModel.prototype.getColumnNames = function() {
var _this = this;
return _.keys(this.parsedData[0]).filter(function(columnName) {
return !_.include(_this.options.specialColumnNames, columnName);
});
};
LongitudinalModel.prototype.getLongitudinalData = function() {
var _this = this;
return this.parsedData.map(function(row) {
return _this.columnNames.map(function(columnName) {
return {
condition: columnName,
value: +row[columnName]
};
});
});
};
LongitudinalModel.prototype.getGroupedLongitudinalData = function() {
var _this = this;
return this.parsedData.map(function(row) {
var columnGroups, currentGroup, longitudinalValues;
columnGroups = _this.columnGroups.slice(0);
currentGroup = columnGroups.shift();
longitudinalValues = [];
_this.columnNames.map(function(columnName) {
if (!columnName.match(RegExp("^" + currentGroup + "_"))) {
longitudinalValues.push({
condition: "",
value: null
});
currentGroup = columnGroups.shift();
}
return longitudinalValues.push({
condition: columnName,
value: +row[columnName]
});
});
return longitudinalValues;
});
};
LongitudinalModel.prototype.getClusterNames = function() {
var clusterFrequencies;
clusterFrequencies = window.getFrequencies(this.clusters);
return _.chain(clusterFrequencies).keys().sortBy(function(x) {
return clusterFrequencies[x];
}).value().reverse();
};
return LongitudinalModel;
})(Backbone.Model);
}).call(this);
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
window.PcpView = (function(_super) {
__extends(PcpView, _super);
function PcpView() {
return PcpView.__super__.constructor.apply(this, arguments);
}
PcpView.prototype.initialize = function() {
var _this = this;
if (!this.model.options.hidePCP) {
this.render();
this.model.on("change:currentRowId", function() {
return _this.showCurrentRow();
});
this.model.on("change:clickedRowId", function() {
return _this.showClickedRow();
});
this.model.on("change:currentCluster", function() {
return _this.showCurrentCluster();
});
return this.model.on("change:currentTag", function() {
return _this.showCurrentTag();
});
}
};
PcpView.prototype.events = function() {
return {
"mouseover .expression-line": "changeCurrentRowId",
"mouseout .expression-line": "changeCurrentRowId",
"click .expression-line": "changeClickedRowId",
"click .expression-point": "showExpressionPointText"
};
};
PcpView.prototype.render = function() {
var columnName,
_this = this;
this.columnNamesMargin = d3.max((function() {
var _i, _len, _ref, _results;
_ref = this.model.columnNames;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
columnName = _ref[_i];
_results.push(columnName.length);
}
return _results;
}).call(this));
this.margin = {
top: 300,
right: 50,
bottom: this.columnNamesMargin * 30,
left: 150
};
this.width = d3.max([400, this.model.columnNames.length * 40]);
this.height = 300;
this.pcp = d3.select(this.el).attr("width", this.width + this.margin.right + this.margin.left).attr("height", this.height + this.margin.top + this.margin.bottom).attr("class", "pcp").append("g").attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
this.x = d3.scale.ordinal().domain(this.model.columnNames).rangePoints([0, this.width], .2);
this.y = d3.scale.linear().domain(this.model.getLongitudinalValueExtent()).range([this.height, 0], .2);
this.line = d3.svg.line().defined(function(d) {
return _.isFinite(d.value);
}).x(function(d) {
return _this.x(d.condition);
}).y(function(d) {
return _this.y(d.value);
});
this.xAxis = d3.svg.axis().scale(this.x).tickSize(6, 0);
this.renderedXAxis = this.pcp.append("g").attr("class", "x axis").attr("transform", "translate(0," + this.height + ")").call(this.xAxis);
this.renderedXAxis.selectAll("text").attr("dx", "-.5em").attr("dy", ".3em").attr("text-anchor", "end").attr("transform", "rotate(-45)");
this.yAxis = d3.svg.axis().scale(this.y).ticks(4).tickSize(6, 0).orient("left");
this.renderedYAxis = this.pcp.append("g").attr("class", "y axis").attr("transform", "translate(0,0)").call(this.yAxis);
this.renderedYAxis.append("text").attr("text-anchor", "middle").attr("dy", "-.5em").text(this.model.options.yAxisName);
this.addLongitudinalDataLines();
return this.pcp.append("line").attr("y1", this.y(0)).attr("y2", this.y(0)).attr("x2", this.width).attr("class", "axis zero");
};
PcpView.prototype.addLongitudinalDataLines = function() {
var _this = this;
this.pcp.selectAll(".expression-line").data(this.getLongitudinalData()).enter().append("path").attr("class", "expression-line").attr("row-id", function(d, i) {
return _this.model.rowIds[i];
}).attr("stroke", "steelblue").attr("stroke-opacity", .5).attr("d", this.line);
if (this.model.options.showClusters) {
return this.pcp.selectAll(".expression-line").attr("cluster", function(d, i) {
return _this.model.clusters[i];
}).attr("stroke", function(d, i) {
return window.clusterColor(_this.model.clusters[i]);
});
}
};
PcpView.prototype.getLongitudinalData = function() {
if (this.model.options.showGroups) {
return this.model.groupedLongitudinalData;
} else {
return this.model.longitudinalData;
}
};
PcpView.prototype.changeCurrentRowId = function(e) {
e.stopPropagation();
return this.model.set({
currentRowId: e.type === "mouseover" ? d3.select(e.target).attr("row-id") : null
});
};
PcpView.prototype.changeClickedRowId = function(e) {
e.stopPropagation();
return this.model.set({
clickedRowId: d3.select(e.target).attr("row-id")
});
};
PcpView.prototype.showExpressionPointText = function(e) {
var d;
e.stopPropagation();
d = e.target.__data__;
return this.pcp.append("text").attr("class", "expression-text").attr("x", this.x(d.condition)).attr("y", this.y(d.value)).attr("text-anchor", "middle").attr("dy", "-.8em").text(d3.round(d.value, 2));
};
PcpView.prototype.showCurrentRow = function() {
var currentRow, currentRowId;
this.pcp.selectAll(".expression-line").filter(":not(.clicked)").classed("current", 0);
this.pcp.selectAll("text.title").filter(":not(.clicked)").remove();
currentRowId = this.model.get("currentRowId");
if (currentRowId != null) {
currentRow = this.pcp.select("[row-id=" + currentRowId + "]");
currentRow.classed("current", 1);
if (this.pcp.select(".clicked").empty()) {
currentRow.node().parentNode.appendChild(currentRow.node());
}
this.pcp.selectAll("text.title").filter(".clicked").style("display", "none");
return this.pcp.append("text").attr("class", "title").attr("x", this.width / 2).attr("y", -40).attr("text-anchor", "middle").text(this.model.getRowName(currentRowId));
} else {
return this.pcp.selectAll("text.title").filter(".clicked").style("display", "block");
}
};
PcpView.prototype.showClickedRow = function() {
var clickedRow, clickedRowId, data;
clickedRowId = this.model.get("clickedRowId");
if (clickedRowId != null) {
clickedRow = this.pcp.select("[row-id=" + clickedRowId + "]");
clickedRow.node().parentNode.appendChild(clickedRow.node());
this.removeClickedRow();
clickedRow.classed("current clicked", 1);
data = clickedRow.node().__data__;
this.pcp.selectAll(".expression-point").data(data.filter(function(d) {
return _.isFinite(d.value);
})).enter().append("circle").attr("class", "expression-point").attr("cx", this.line.x()).attr("cy", this.line.y()).attr("r", 5);
this.pcp.selectAll(".expression-text").data(data.filter(this.filterTextDatapoints)).enter().append("text").attr("class", "expression-text").attr("x", this.line.x()).attr("y", this.line.y()).attr("text-anchor", "middle").attr("dy", "-.8em").text(function(d, i) {
return d3.round(d.value, 2);
});
return this.pcp.select("text.title").classed("clicked", 1).text(this.model.getRowName(clickedRowId));
} else {
return this.removeClickedRow();
}
};
PcpView.prototype.filterTextDatapoints = function(item, i, arr) {
var significantDifference;
significantDifference = .5;
return (i === 0 && _.isFinite(item.value)) || ((i === arr.length - 1) && _.isFinite(item.value)) || (arr[i - 1].value === null && _.isFinite(item.value)) || (arr[i + 1].value === null && _.isFinite(item.value)) || (_.isFinite(item.value) && item.value > arr[i - 1].value && item.value > arr[i + 1].value && (Math.abs(item.value - arr[i - 1].value) > significantDifference || Math.abs(item.value - arr[i + 1].value) > significantDifference)) || (_.isFinite(item.value) && item.value < arr[i - 1].value && item.value < arr[i + 1].value && (Math.abs(item.value - arr[i - 1].value) > significantDifference || Math.abs(item.value - arr[i + 1].value) > significantDifference));
};
PcpView.prototype.removeClickedRow = function() {
this.pcp.selectAll(".expression-point").remove();
this.pcp.selectAll(".expression-text").remove();
this.pcp.selectAll(".expression-line").classed("current clicked", 0);
return this.pcp.select("text.title").text("");
};
PcpView.prototype.showCurrentCluster = function() {
var currentCluster,
_this = this;
currentCluster = this.model.get("currentCluster");
d3.select("#pcp").style("top", d3.select("body").node().scrollTop);
if (currentCluster) {
this.pcp.selectAll(".expression-line").attr("stroke", "#999");
return this.pcp.selectAll(".expression-line[cluster='" + currentCluster + "']").attr("stroke", function(d, i) {
return window.clusterColor(currentCluster);
}).each(function() {
return this.parentNode.appendChild(this);
});
} else {
this.pcp.selectAll(".expression-line").remove();
return this.addLongitudinalDataLines();
}
};
PcpView.prototype.showCurrentTag = function() {
var currentTag, taggedRowIds;
currentTag = this.model.get("currentTag");
d3.select("#pcp").style("top", 0);
scroll(0, 0);
if (currentTag) {
taggedRowIds = _(d3.selectAll("#heatmap .row")).chain().first().filter(function(d) {
return d.style.display !== "none";
}).map(function(d) {
return d3.select(d).attr("row-id");
}).value();
return this.pcp.selectAll(".expression-line").attr("stroke", "#999").filter(function(d, i) {
return _.include(taggedRowIds, d3.select(this).attr("row-id"));
}).attr("stroke", function(d, i) {
return window.clusterColor(d3.select(this).attr("cluster"));
}).each(function() {
return this.parentNode.appendChild(this);
});
} else {
this.pcp.selectAll(".expression-line").remove();
return this.addLongitudinalDataLines();
}
};
return PcpView;
})(Backbone.View);
}).call(this);