Last active
August 29, 2015 14:14
-
-
Save bartaelterman/52478dbded1372d21c2d to your computer and use it in GitHub Desktop.
Bilevel sunburst example
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
{"name": "Coccinellidae", "children": [{"name": "Adalia", "children": [{"name": "Adalia bipunctata", "size": "3350"}, {"name": "Adalia decempunctata", "size": "1901"}]}, {"name": "Anatis", "children": [{"name": "Anatis ocellata", "size": "482"}]}, {"name": "Anisosticta", "children": [{"name": "Anisosticta novemdecimpunctata", "size": "784"}]}, {"name": "Aphidecta", "children": [{"name": "Aphidecta obliterata", "size": "500"}]}, {"name": "Calvia", "children": [{"name": "Calvia decemguttata", "size": "664"}, {"name": "Calvia quatuordecimguttata", "size": "1069"}]}, {"name": "Chilocorus", "children": [{"name": "Chilocorus bipustulatus", "size": "173"}, {"name": "Chilocorus renipustulatus", "size": "252"}]}, {"name": "Clitostethus", "children": [{"name": "Clitostethus arcuatus", "size": "7"}]}, {"name": "Coccidula", "children": [{"name": "Coccidula rufa", "size": "433"}, {"name": "Coccidula scutellata", "size": "271"}]}, {"name": "Coccinella", "children": [{"name": "Coccinella hieroglyphica", "size": "163"}, {"name": "Coccinella magnifica", "size": "162"}, {"name": "Coccinella quinquepunctata", "size": "763"}, {"name": "Coccinella septempunctata", "size": "5819"}, {"name": "Coccinella undecimpunctata", "size": "845"}]}, {"name": "Coccinula", "children": [{"name": "Coccinula quatuordecimpustulata", "size": "280"}]}, {"name": "Cryptolaemus", "children": [{"name": "Cryptolaemus montrouzieri", "size": "1"}]}, {"name": "Cynegetis", "children": [{"name": "Cynegetis impunctata", "size": "68"}]}, {"name": "Exochomus", "children": [{"name": "Exochomus nigromaculatus", "size": "282"}, {"name": "Exochomus quadripustulatus", "size": "1118"}]}, {"name": "Halyzia", "children": [{"name": "Halyzia sedecimguttata", "size": "1120"}]}, {"name": "Harmonia", "children": [{"name": "Harmonia axyridis", "size": "4882"}, {"name": "Harmonia quadripunctata", "size": "645"}]}, {"name": "Henosepilachna", "children": [{"name": "Henosepilachna argus", "size": "381"}]}, {"name": "Hippodamia", "children": [{"name": "Hippodamia septemmaculata", "size": "19"}, {"name": "Hippodamia tredecimpunctata", "size": "339"}, {"name": "Hippodamia variegata", "size": "840"}]}, {"name": "Hyperaspis", "children": [{"name": "Hyperaspis campestris", "size": "15"}]}, {"name": "Myrrha", "children": [{"name": "Myrrha octodecimguttata", "size": "261"}]}, {"name": "Myzia", "children": [{"name": "Myzia oblongoguttata", "size": "189"}]}, {"name": "Nephus", "children": [{"name": "Nephus bipunctatus", "size": "18"}, {"name": "Nephus redtenbacheri", "size": "5"}]}, {"name": "Oenopia", "children": [{"name": "Oenopia conglobata", "size": "638"}, {"name": "Oenopia impustulata", "size": "24"}]}, {"name": "Platynaspis", "children": [{"name": "Platynaspis luteorubra", "size": "86"}]}, {"name": "Propylea", "children": [{"name": "Propylea quatuordecimpunctata", "size": "3951"}]}, {"name": "Psyllobora", "children": [{"name": "Psyllobora vigintiduopunctata", "size": "2171"}]}, {"name": "Rhyzobius", "children": [{"name": "", "size": "10"}, {"name": "Rhyzobius chrysomeloides", "size": "321"}, {"name": "Rhyzobius forestieri", "size": "4"}, {"name": "Rhyzobius litura", "size": "211"}]}, {"name": "Scymnus", "children": [{"name": "Scymnus abietis", "size": "6"}, {"name": "Scymnus apetzi", "size": "19"}, {"name": "Scymnus ater", "size": "6"}, {"name": "Scymnus auritus", "size": "113"}, {"name": "Scymnus frontalis", "size": "116"}, {"name": "Scymnus haemorrhoidalis", "size": "59"}, {"name": "Scymnus interruptus", "size": "6"}, {"name": "Scymnus limbatus", "size": "2"}, {"name": "Scymnus mimulus", "size": "6"}, {"name": "Scymnus nigrinus", "size": "71"}, {"name": "Scymnus rubromaculatus", "size": "73"}, {"name": "Scymnus suturalis", "size": "138"}]}, {"name": "Sospita", "children": [{"name": "Sospita vigintiguttata", "size": "4"}]}, {"name": "Stethorus", "children": [{"name": "Stethorus punctillum", "size": "79"}]}, {"name": "Subcoccinella", "children": [{"name": "Subcoccinella vigintiquatuorpunctata", "size": "533"}]}, {"name": "Tytthaspis", "children": [{"name": "Tytthaspis sedecimpunctata", "size": "1068"}]}, {"name": "Vibidia", "children": [{"name": "Vibidia duodecimguttata", "size": "4"}]}]} |
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"> | |
<style> | |
circle, | |
path { | |
cursor: pointer; | |
} | |
circle { | |
fill: none; | |
pointer-events: all; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
var margin = {top: 350, right: 480, bottom: 350, left: 480}, | |
radius = Math.min(margin.top, margin.right, margin.bottom, margin.left) - 10; | |
var hue = d3.scale.category10(); | |
var luminance = d3.scale.sqrt() | |
.domain([0, 1e6]) | |
.clamp(true) | |
.range([90, 20]); | |
var svg = d3.select("body").append("svg") | |
.attr("width", margin.left + margin.right) | |
.attr("height", margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var partition = d3.layout.partition() | |
.sort(function(a, b) { return d3.ascending(a.name, b.name); }) | |
.size([2 * Math.PI, radius]); | |
var arc = d3.svg.arc() | |
.startAngle(function(d) { return d.x; }) | |
.endAngle(function(d) { return d.x + d.dx - .01 / (d.depth + .5); }) | |
.innerRadius(function(d) { return radius / 3 * d.depth; }) | |
.outerRadius(function(d) { return radius / 3 * (d.depth + 1) - 1; }); | |
d3.json("/bartaelterman/raw/52478dbded1372d21c2d/cocc_taxonomy.json", function(error, root) { | |
// Compute the initial layout on the entire tree to sum sizes. | |
// Also compute the full name and fill color for each node, | |
// and stash the children so they can be restored as we descend. | |
partition | |
.value(function(d) { return d.size; }) | |
.nodes(root) | |
.forEach(function(d) { | |
d._children = d.children; | |
d.sum = d.value; | |
d.key = key(d); | |
d.fill = fill(d); | |
}); | |
// Now redefine the value function to use the previously-computed sum. | |
partition | |
.children(function(d, depth) { return depth < 2 ? d._children : null; }) | |
.value(function(d) { return d.sum; }); | |
var center = svg.append("circle") | |
.attr("r", radius / 3) | |
.on("click", zoomOut); | |
center.append("title") | |
.text("zoom out"); | |
var path = svg.selectAll("path") | |
.data(partition.nodes(root).slice(1)) | |
.enter().append("path") | |
.attr("d", arc) | |
.style("fill", function(d) { return d.fill; }) | |
.each(function(d) { this._current = updateArc(d); }) | |
.on("click", zoomIn) | |
.on("mouseover", function(d) {console.log(d.name)}) | |
; | |
function zoomIn(p) { | |
if (p.depth > 1) p = p.parent; | |
if (!p.children) return; | |
zoom(p, p); | |
} | |
function zoomOut(p) { | |
if (!p.parent) return; | |
zoom(p.parent, p); | |
} | |
// Zoom to the specified new root. | |
function zoom(root, p) { | |
if (document.documentElement.__transition__) return; | |
// Rescale outside angles to match the new layout. | |
var enterArc, | |
exitArc, | |
outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]); | |
function insideArc(d) { | |
return p.key > d.key | |
? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key | |
? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0} | |
: {depth: 0, x: 0, dx: 2 * Math.PI}; | |
} | |
function outsideArc(d) { | |
return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)}; | |
} | |
center.datum(root); | |
// When zooming in, arcs enter from the outside and exit to the inside. | |
// Entering outside arcs start from the old layout. | |
if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]); | |
path = path.data(partition.nodes(root).slice(1), function(d) { return d.key; }); | |
// When zooming out, arcs enter from the inside and exit to the outside. | |
// Exiting outside arcs transition to the new layout. | |
if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]); | |
d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() { | |
path.exit().transition() | |
.style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; }) | |
.attrTween("d", function(d) { return arcTween.call(this, exitArc(d)); }) | |
.remove(); | |
path.enter().append("path") | |
.style("fill-opacity", function(d) { return d.depth === 2 - (root === p) ? 1 : 0; }) | |
.style("fill", function(d) { return d.fill; }) | |
.on("click", zoomIn) | |
.each(function(d) { this._current = enterArc(d); }); | |
path.transition() | |
.style("fill-opacity", 1) | |
.attrTween("d", function(d) { return arcTween.call(this, updateArc(d)); }); | |
}); | |
} | |
}); | |
function key(d) { | |
var k = [], p = d; | |
while (p.depth) k.push(p.name), p = p.parent; | |
return k.reverse().join("."); | |
} | |
function fill(d) { | |
var p = d; | |
while (p.depth > 1) p = p.parent; | |
var c = d3.lab(hue(p.name)); | |
c.l = luminance(d.sum); | |
return c; | |
} | |
function arcTween(b) { | |
var i = d3.interpolate(this._current, b); | |
this._current = i(0); | |
return function(t) { | |
return arc(i(t)); | |
}; | |
} | |
function updateArc(d) { | |
return {depth: d.depth, x: d.x, dx: d.dx}; | |
} | |
d3.select(self.frameElement).style("height", margin.top + margin.bottom + "px"); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment