Skip to content

Instantly share code, notes, and snippets.

@lepfhty
Last active August 29, 2015 14:04
Show Gist options
  • Save lepfhty/9aa0db5859a35ce37dcb to your computer and use it in GitHub Desktop.
Save lepfhty/9aa0db5859a35ce37dcb to your computer and use it in GitHub Desktop.
Mortality Heat Map
"use strict";
function chart() {
var margin = { top: 100, right: 50, bottom: 100, left: 150 },
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
x = d3.scale.ordinal().rangeBands([0, width]),
xlabel = d3.scale.ordinal().rangePoints([0, width], 1),
xaxis = d3.svg.axis().scale(xlabel).orient("bottom").tickSize(0,0),
y = d3.scale.ordinal().rangeBands([height, 0]),
ylabel = d3.scale.ordinal().rangePoints([height, 0], 1),
yaxis = d3.svg.axis().scale(ylabel).orient("left").tickSize(0,0),
svg = d3.select("#chart").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 + ")"),
mort_colors = d3.scale.linear().domain([0,0.7]).range(["white", "black"]),
labels,
mortality;
d3.json("labels.json", function(err, json) {
if (err) return console.warn(err);
labels = json;
if (labels && mortality)
self();
});
d3.json("mortality.json", function(err, json) {
if (err) return console.warn(err);
mortality = json;
if (labels && mortality)
self();
});
function self() {
// set the scales for the grid
x.domain(mortality.map(function(d) { return d.x; }));
xlabel.domain(mortality.map(function(d) { return d.x; }));
y.domain(mortality.map(function(d) { return d.y; }));
ylabel.domain(mortality.map(function(d) { return d.y; }));
// setup x axis
xaxis.tickFormat(function(d) { return labels.x[d]; });
svg.append("g")
.classed("axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xaxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-0.6em")
.attr("dy", "0.3em")
.attr("transform", "rotate(-90)");
// setup y axis
yaxis.tickFormat(function(d) { return labels.y[d]; });
svg.append("g")
.classed("axis", true)
.call(yaxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-0.6em");
// color the heatmap grid
var heatmap = svg.selectAll(".cell")
.data(mortality)
.enter().append("rect")
.classed("cell", true)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.attr("width", x.rangeBand())
.attr("height", y.rangeBand())
.style("fill", function(d) { return mort_colors(d.died / d.total); });
// display the mortality rate in each grid cell
var mortlabels = svg.selectAll(".mortlabels")
.data(mortality)
.enter().append("text")
.classed({mortlabels: true})
.attr("x", function(d) { return xlabel(d.x); })
.attr("y", function(d) { return ylabel(d.y); })
.attr("dy", "0.3em")
.style("text-anchor", "middle")
.style("font-size", 12)
.style("fill", function(d) {
var m = d.died / d.total;
return m < 0.5 ? "black" : "white";
})
.text(function(d) { return (d.died / d.total).toPrecision(3); });
var mort_bysf = d3.nest()
.key(function(d) { return d.x; })
.rollup(function(values) {
return d3.sum(values, function(d) { return d.died; }) / d3.sum(values, function(d) { return d.total; });
});
var mortxtotals = mort_bysf.entries(mortality);
var mort_pfexists = mort_bysf.entries(mortality.filter(function(d) { return d.y != 0; }));
// group by SF
var xtotals = svg.selectAll(".xtotals")
.data(mortxtotals)
.enter().append("rect")
.classed("xtotals", true)
.attr("x", function(d) { return x(+d.key); })
.attr("y", -40)
.attr("width", x.rangeBand())
.attr("height", 30)
.style("fill", function(d) { return mort_colors(+d.values); });
var xtotallabels = svg.selectAll(".xtotallabel")
.data(mortxtotals)
.enter().append("text")
.classed({xtotallabel: true})
.attr("x", function(d) { return xlabel(+d.key); })
.attr("y", -20)
.style("text-anchor", "middle")
.style("font-size", 12)
.text(function(d) { return d.values.toPrecision(3); });
svg.append("text")
.attr("x", 0)
.attr("y", -20)
.attr("dx", "-0.6em")
.style("text-anchor", "end")
.text("Total by SF")
// group by SF w/ PF
var pfexists = svg.selectAll(".pfexists")
.data(mort_pfexists)
.enter().append("rect")
.classed("pfexists", true)
.attr("x", function(d) { return x(+d.key); })
.attr("y", -80)
.attr("width", x.rangeBand())
.attr("height", 30)
.style("fill", function(d) { return mort_colors(+d.values); });
var pflabels = svg.selectAll(".pflabels")
.data(mort_pfexists)
.enter().append("text")
.classed({pflabels: true})
.attr("x", function(d) { return xlabel(+d.key); })
.attr("y", -60)
.style("text-anchor", "middle")
.style("font-size", 12)
.text(function(d) { return d.values.toPrecision(3); });
svg.append("text")
.attr("x", 0)
.attr("y", -60)
.attr("dx", "-0.6em")
.style("text-anchor", "end")
.text("Total by SF w/ PF")
// group by PF
var mortytotals = d3.nest()
.key(function(d) { return d.y; })
.rollup(function(values) {
return d3.sum(values, function(d) { return d.died; }) / d3.sum(values, function(d) { return d.total; });
})
.entries(mortality);
var ytotals = svg.selectAll(".ytotals")
.data(mortytotals)
.enter().append("rect")
.classed("ytotals", true)
.attr("x", width + 10)
.attr("y", function(d) { return y(+d.key); })
.attr("width", 30)
.attr("height", y.rangeBand())
.style("fill", function(d) { return mort_colors(+d.values); });
var ytotallabels = svg.selectAll(".ytotallabel")
.data(mortytotals)
.enter().append("text")
.classed({ytotallabel: true})
.style("text-anchor", "middle")
.style("font-size", 12)
.style("fill", function(d) {
return d.values < 0.5 ? "black" : "white";
})
.attr("transform", function(d) { return "translate(" + (width+30) + "," + ylabel(+d.key) + ")rotate(270)"; })
.text(function(d) { return d.values.toPrecision(3); });
svg.append("text")
.attr("dx", "-0.6em")
.attr("transform", "translate(" + (width+30) + "," + height + ")rotate(270)")
.style("text-anchor", "end")
.text("Total by PF")
}
self.width = function(value) {
if (!arguments.length) return width;
width = value;
return self;
}
self.height = function(value) {
if (!arguments.length) return height;
height = value;
return self;
}
return self;
}
$(function() {
chart();
});
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="heatmap.js"></script>
</head>
<body>
<div id="chart"/>
</body>
</html>
{
"x": ["SFNA", "SF<150", "SF150-221", "SF221-265", "SF>265"],
"y": ["No PF", "PF<100", "PF100-200", "PF200-300", "PF>300"]
}
[
{"x": 0, "y": 0, "died": 29, "total": 411},
{"x": 1, "y": 0, "died": 18, "total": 47},
{"x": 2, "y": 0, "died": 12, "total": 202},
{"x": 3, "y": 0, "died": 3, "total": 206},
{"x": 4, "y": 0, "died": 7, "total": 262},
{"x": 0, "y": 1, "died": 0, "total": 1},
{"x": 1, "y": 1, "died": 24, "total": 41},
{"x": 2, "y": 1, "died": 1, "total": 2},
{"x": 0, "y": 2, "died": 3, "total": 6},
{"x": 1, "y": 2, "died": 8, "total": 37},
{"x": 2, "y": 2, "died": 12, "total": 49},
{"x": 3, "y": 2, "died": 1, "total": 5},
{"x": 4, "y": 2, "died": 0, "total": 2},
{"x": 0, "y": 3, "died": 2, "total": 11},
{"x": 1, "y": 3, "died": 7, "total": 11},
{"x": 2, "y": 3, "died": 9, "total": 37},
{"x": 3, "y": 3, "died": 3, "total": 35},
{"x": 4, "y": 3, "died": 2, "total": 16},
{"x": 0, "y": 4, "died": 20, "total": 203},
{"x": 1, "y": 4, "died": 9, "total": 27},
{"x": 2, "y": 4, "died": 4, "total": 29},
{"x": 3, "y": 4, "died": 6, "total": 55},
{"x": 4, "y": 4, "died": 1, "total": 128}
]
.axis path,
.axis line {
fill: none;
shape-rendering: crispEdges;
}
rect {
stroke: white;
stroke-opacity: 0.5;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment