Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonasalmeida/5e2467fd5fbfbe68673b to your computer and use it in GitHub Desktop.
Save jonasalmeida/5e2467fd5fbfbe68673b to your computer and use it in GitHub Desktop.
Tree map for Diagnosis Data
<h1>Readmissions by Diagnosis Based on Primary Admission Diagnosis</h1>
<div id="body">
var treeData;
test1 = {
name:"Test1", children:[{ name: "Infection", children: [ { name: "Unspecified septicemia", icd9_code: "038.9", count: 19 }, { name: "Other postoperative infection", icd9_code: "998.59", count: 21 }, { name: "Urinary tract infection, site not specified", icd9_code: "599.0", count: 28 }, { name: "Intestinal infection due to Clostridium difficile", icd9_code: "008.45", count: 27 }, { name: "Obstructive chronic bronchitis with (acute) exacerbation", icd9_code: "491.21", count: 17 }]},{ name: "Heart Disease", children: [ { name: "Acute on chronic diastolic heart failure", icd9_code: "428.33", count: 12 }, { name: "Subendocardial infarction, initial episode of care", icd9_code: "410.71", count: 19 }, { name: "Acute on chronic systolic heart failure", icd9_code: "428.23", count: 29 }, { name: "Acute on chronic combined systolic and diastolic heart failure", icd9_code: "428.43", count: 28 }, { name: "Coronary atherosclerosis of native coronary artery", icd9_code: "414.01", count: 14 }, { name: "Atrial fibrillation", icd9_code: "427.31", count: 26 }]},{ name: "Kidney Disease", children: [ { name: "Acute kidney failure, unspecified", icd9_code: "584.9", count: 13 }]},{ name: "Neurological Disease", children: [ { name: "Cerebral embolism with cerebral infarction", icd9_code: "434.11", count: 13 }, { name: "Cerebral artery occlusion, unspecified with cerebral infarction", icd9_code: "434.91", count: 16 }, { name: "Subdural hemorrhage", icd9_code: "432.1", count: 23 }, { name: "Intracerebral hemorrhage", icd9_code: "431", count: 16 }, { name: "Unspecified transient cerebral ischemia", icd9_code: "435.9", count: 23 }, { name: "Cerebral aneurysm, nonruptured", icd9_code: "437.3", count: 13 }]},{ name: "Other", children: [ { name: "Other complications due to other vascular device, implant, and g", icd9_code: "996.74", count: 10 }, { name: "Other chest pain", icd9_code: "786.59", count: 26 }]}]
};
test2 = {
name:"Test2", children:[{ name: "Infection", children: [ { name: "Obstructive chronic bronchitis with (acute) exacerbation", icd9_code: "491.21", count: 21 }, { name: "Pneumonia, organism unspecified", icd9_code: "486", count: 35 }, { name: "Unspecified septicemia", icd9_code: "038.9", count: 30 }, { name: "Pneumonitis due to inhalation of food or vomitus", icd9_code: "507.0", count: 36 }, { name: "Intestinal infection due to Clostridium difficile", icd9_code: "008.45", count: 32 }, { name: "Obstructive chronic bronchitis with acute bronchitis", icd9_code: "491.22", count: 27 }, { name: "Cellulitis and abscess of leg, except foot", icd9_code: "682.6", count: 42 }, { name: "Urinary tract infection, site not specified", icd9_code: "599.0", count: 29 }, { name: "Acute pancreatitis", icd9_code: "577.0", count: 27 }, { name: "Bronchitis, not specified as acute or chronic", icd9_code: "490", count: 30 }]},{ name: "Heart Disease", children: [ { name: "Acute on chronic diastolic heart failure", icd9_code: "428.33", count: 43 }, { name: "Acute on chronic systolic heart failure", icd9_code: "428.23", count: 29 }, { name: "Atrial fibrillation", icd9_code: "427.31", count: 27 }, { name: "Acute on chronic combined systolic and diastolic heart failure", icd9_code: "428.43", count: 24 }, { name: "Coronary atherosclerosis of native coronary artery", icd9_code: "414.01", count: 32 }, { name: "Subendocardial infarction, initial episode of care", icd9_code: "410.71", count: 20 }, { name: "Other pulmonary embolism and infarction", icd9_code: "415.19", count: 36 }]},{ name: "Kidney Disease", children: [ { name: "Acute kidney failure, unspecified", icd9_code: "584.9", count: 25 }]},{ name: "Other", children: [ { name: "Acute and chronic respiratory failure", icd9_code: "518.84", count: 28 }, { name: "Other chest pain", icd9_code: "786.59", count: 42 }]}]
};
test3 = {
name:"Test3", children:[{ name: "Infection", children: [ { name: "Unspecified septicemia", icd9_code: "038.9", count: 30 }, { name: "Other postoperative infection", icd9_code: "998.59", count: 15 }, { name: "Pneumonia, organism unspecified", icd9_code: "486", count: 28 }, { name: "Urinary tract infection, site not specified", icd9_code: "599.0", count: 38 }, { name: "Intestinal infection due to Clostridium difficile", icd9_code: "008.45", count: 25 }, { name: "Obstructive chronic bronchitis with (acute) exacerbation", icd9_code: "491.21", count: 16 }, { name: "Cellulitis and abscess of leg, except foot", icd9_code: "682.6", count: 27 }, { name: "Pneumonitis due to inhalation of food or vomitus", icd9_code: "507.0", count: 22 }]},{ name: "Heart Disease", children: [ { name: "Coronary atherosclerosis of native coronary artery", icd9_code: "414.01", count: 32 }, { name: "Acute on chronic diastolic heart failure", icd9_code: "428.33", count: 35 }, { name: "Atrial fibrillation", icd9_code: "427.31", count: 16 }, { name: "Acute on chronic combined systolic and diastolic heart failure", icd9_code: "428.43", count: 21 }, { name: "Acute on chronic systolic heart failure", icd9_code: "428.23", count: 16 }, { name: "Subendocardial infarction, initial episode of care", icd9_code: "410.71", count: 35 }]},{ name: "Kidney Disease", children: [ { name: "Acute kidney failure, unspecified", icd9_code: "584.9", count: 28 }, { name: "Complications of transplanted kidney", icd9_code: "996.81", count: 40 }]},{ name: "Diabetes", children: [ { name: "Diabetes with other specified manifestations, type II or unspeci", icd9_code: "250.80", count: 23 }, { name: "Diabetes with neurological manifestations, type II or unspecifie", icd9_code: "250.60", count: 30 }]},{ name: "Other", children: [ { name: "Other chest pain", icd9_code: "786.59", count: 20 }, { name: "Dehydration", icd9_code: "276.51", count: 18 }]}]};
treeData = test1;
var dataSets = ["TestData1", "TestData2", "TestData3"];
var testData = [test1, test2, test3];
var selectedDataset = dataSets[0];
/*
To-do:
test multi-level
multiple datasets- transitions
*/
// buttons
d3.select("#body").append("div")
.attr("class", "chart-label")
.text("Primary Admission Diagnosis: ")
d3.select("#body").append("div")
.attr("class", "selection-buttons-container")
.selectAll("div").data(dataSets)
.enter().append("div")
.text(function(d) { return d;})
.attr("class", function(d) {
if (d == selectedDataset)
return "selection-button selected-button";
else
return "selection-button";
})
.on("click", function(d) {
d3.select(".selected-button").classed("selected-button", false);
d3.select(this).classed("selected-button", true);
selectedDataset = d;
// update data
//treeData = test2;
updateTreeMap(testData[dataSets.indexOf(d)]);
zoom(node);
});
var w = 1280 - 80,
h = 800 - 180,
x = d3.scale.linear().range([0, w]),
y = d3.scale.linear().range([0, h]),
color = d3.scale.category10(),
root,
node;
var treemap;
var svg = d3.select("#body").append("div")
.attr("class", "chart")
.style("width", w + "px")
.style("height", h + "px")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("id", "rootG")
.attr("transform", "translate(.5,.5)");
initializeTreeMap();
//d3.json("https://gist.githubusercontent.com/mbostock/1093025/raw/a05a94858375bd0ae023f6950a2b13fac5127637/flare.json", initializeTreeMap());
function initializeTreeMap() {
node = root = treeData;
treemap = d3.layout.treemap()
.padding(2)
.round(false)
.size([w, h])
.sticky(true)
.mode("squarify")
.value(function(d) { return d.count; });
var data = treemap.nodes(root)
.filter(function(d) { return d.depth == 0 ? null : d; })
.sort(function comparator(a, b) { return b.depth - a.depth;});
var nodeGroups = svg.selectAll("g").data(data)
.enter().append("svg:g")
.attr("id", function(d) { return d.name.replace(/\s/g, "_");} )
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.attr("width", function(d) { return d.dx; })
.attr("height", function(d) { return d.dy; })
.on("click", function(d) { return zoom(d.children ? d : root); });
nodeGroups
.append("title")
.text(function(d)
{
if (d.icd9_code != null)
return d.name + " (" + d.icd9_code + ")\nNumber of Readmissions: " + d.value;
else
return d.name + "\nNumber of Readmissions: " + d.value;
});
nodeGroups.filter(function(d) { return d.depth == 0 ? null : d; })
.append("svg:rect")
.attr("class", "cell")
.attr("width", function(d) { return d.dx - 1; })
.attr("height", function(d) { return d.dy - 1; })
.style("fill-opacity", function(d) { return d.children ? .7 : .9; })
.style("fill", function(d,i)
{
if (d.depth == 1) { return color(d.name); }
else { return d3.rgb(color(d.parent.name)).brighter(i*0.1); }
});
d3.select(window).on("click", function() { if (node != root) { zoom(root);} });
zoom(root);
}
function updateTreeMap(newData) {
node = root = newData;
treemap = d3.layout.treemap()
.padding(2)
.round(false)
.size([w, h])
.sticky(true)
.mode("squarify")
.value(function(d) { return d.count; });
var data = treemap.nodes(newData)
.filter(function(d) { return d.depth == 0 ? null : d; })
.sort(function comparator(a, b) { return b.depth - a.depth;});
var dataJoin = svg.selectAll("g").data(data,
function(d) { return d.name });
// remove exit
dataJoin.exit().selectAll("*").remove();
dataJoin.exit().remove();
// append enter
var enterGroups = dataJoin
.enter().append("svg:g")
.attr("id", function(d) { return d.name.replace(/\s/g, "_");} )
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.attr("width", function(d) { return d.dx; })
.attr("height", function(d) { return d.dy; })
.on("click", function(d) { return zoom(d.children ? d : root); });
enterGroups.filter(function(d) { return d.depth == 0 ? null : d; })
.append("svg:rect")
.attr("class", "cell")
.attr("width", function(d) { return 1; })
.attr("height", function(d) { return 1; })
.style("fill-opacity", function(d) { return d.children ? .7 : .9; })
.style("fill", function(d,i)
{
if (d.depth == 1) { return color(d.name); }
else { return d3.rgb(color(d.parent.name)).brighter(i*0.1); }
});
// update
// reset cell color?
// title
svg.selectAll("title").remove();
svg.selectAll("#rootG g")
.append("title")
.text(function(d) {
if (d.icd9_code != null)
return d.name + " (" + d.icd9_code + ")\nNumber of Readmissions: " + d.value;
else
return d.name + "\nNumber of Readmissions: " + d.value;
});
// redraw in correct order
svg.selectAll("#rootG g").sort(function comparator(a, b) {
return b.depth - a.depth;
});
zoom(root);
}
function accumulate(d) {
return d.children
? d.count = d.children.reduce(function(d) { return accumulate(d); }, 0)
: d.count;
}
function size(d) {
return d.size;
}
function count(d) {
return 1;
}
function zoom(d) {
// make [zoomed] root (+ancestors) container transparent
svg.selectAll("g").selectAll("rect")
.attr("display", function(d2) { return d2.depth <= d.depth ? "none" : "inline"; });
var kx = w / d.dx, ky = h / d.dy;
x.domain([d.x, d.x + d.dx]);
y.domain([d.y, d.y + d.dy]);
// destroy old text, create new
svg.selectAll("text").remove();
var newText = svg.selectAll("g")
.filter(function(d2)
{ return (d2.depth == d.depth + 1) && (d2.parent == d) ? d2 : null; })
.append("svg:text")
.attr("x", function(d) { return kx * d.dx / 2; })
.attr("y", function(d) { return ky * d.dy / 2; })
//.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("font-size", 30)
.style("opacity", 0)
.style("pointer-events", "none")
.text(function(d) { return d.name; });
newText.transition().duration(1000)
.ease("cubic")
.style("opacity", 1);
// rotate text where appropriate
svg.selectAll("g")
.filter(function(d) { return ((ky * d.dy) > 1.3*(kx * d.dx)) ? d : null; })
.selectAll("text")
.attr("transform", function(d) { return "rotate(90 " + kx * d.dx / 2 + " " + ky * d.dy / 2 + ")"; });
// add line breaks and scale appropriately
var selectGroup = svg.selectAll("g")
.filter(function(d2) { return (d2.depth == d.depth + 1) && (d2.parent == d) ? d2 : null; });
selectGroup.call(fitText, kx, ky);
// add count
selectGroup.selectAll("text").each(function(d)
{
var x = d3.select(this).attr("x");
d3.select(this)
.append("tspan")
.text(function(d) { return d.value; })
.attr("x", x)
.attr("dy", "1.1em");
});
// apply transform to g
var t = svg.selectAll("g").transition().duration(1000)
.attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });
t.select("rect")
.attr("width", function(d) { return kx * d.dx - 1; })
.attr("height", function(d) { return ky * d.dy - 1; });
node = d;
d3.event.stopPropagation();
}
function fitText(d, kx, ky) {
d.each( function()
{
// check rect bounds vs text
var g = d3.select(this);
var text = g.select("text");
var rect = g.select("rect");
var textBBox = text[0][0].getBBox();
var rectWidthLimit = rect.datum().dx * kx;
var rectHeightLimit = rect.datum().dy * ky;
if (text.attr("transform") != null)
{
rectWidthLimit = rect.datum().dy * ky;
rectHeightLimit = rect.datum().dx * kx;
}
// check for overlap, if so, wrap
if (textBBox.width > rectWidthLimit - 50)
{
var lineHeight = 1.2; // ems
var x = text.attr("x");
var y = text.attr("y");
var dy = parseFloat(text.attr("dy"));
var width = Math.round(text.text().length/2);
// find first space after mid-point of text
var breakIndex = width + text.text().substring(width, text.text().length).indexOf(" ");
if (text.text().substring(width, text.text().length).indexOf(" ") == -1)
{
breakIndex = text.text().substring(width, text.text().length).indexOf(" ");
}
// then split text in two at found space
var wrapText = text.text().substring(breakIndex + 1, text.text().length);
if (breakIndex > 0)
{
var nextText = text.text().substring(0, breakIndex + 1);
text.text(nextText).attr("dy", "-0.5em")
text.append("tspan").text(wrapText).attr("x", text.attr("x")).attr("dy", "1.1em");
}
// if text is still overlaps, decrease textSize
textBBox = text[0][0].getBBox();
while ((textBBox.width > rectWidthLimit - 50) || ((textBBox.height > rectHeightLimit - 30)))
{
/*
console.log(text.text());
console.log("text width: " + Math.round(textBBox.width));
console.log("rect limit: " + Math.round(rectLimit));
console.log("rect x: " + rect.attr("width"));
console.log("rect kx: " + kx);
console.log("text size: " + text.style("font-size"));
*/
text.style("font-size", parseInt(text.style("font-size"))-2);
textBBox = text[0][0].getBBox();
}
}
});
}
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
.chart {
display: block;
margin: auto;
margin-top: 40px;
}
rect {
fill: clear;
rx: 5;
ry: 5;
cursor: pointer;
}
.chart-label {
font-size: 20px;
margin-left: 10px;
margin-bottom: 10px;
}
.selection-buttons-container {
width: 500px;
margin-bottom: 30px;
}
.selection-button {
float: left;
font-size: 20px;
margin-left: 10px;
cursor: pointer;
color: gray;
}
.selected-button {
font-size: 20px;
font-weight: bold;
color: blue;
}
/* pointer-events: none; */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment