Skip to content

Instantly share code, notes, and snippets.

@kerryrodden
Last active January 18, 2021 11:05
  • Star 15 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kerryrodden/477c1bfb081b783f80ad to your computer and use it in GitHub Desktop.
Zoomable sunburst with updating data

I combined Mike Bostock's Zoomable Sunburst and Sunburst Partition examples, so that I could have both zooming and updating the underlying data (between count and size, in this case). A simple combination of the examples does not work; you have to edit the arcTween function used for updating the data, so that when it redraws the partition layout, it takes account of the current zoom level by adjusting the domain of the x scale.

Click on any arc to zoom in, and click on the center circle to zoom out. Use the Size/Count radio buttons to update the data.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
path {
stroke: #fff;
fill-rule: evenodd;
}
</style>
<body>
<form>
<label><input type="radio" name="mode" value="size"> Size</label>
<label><input type="radio" name="mode" value="count" checked> Count</label>
</form>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 700,
radius = Math.min(width, height) / 2;
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var color = d3.scale.category20c();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.sort(null)
.value(function(d) { return 1; });
var arc = d3.svg.arc()
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
.innerRadius(function(d) { return Math.max(0, y(d.y)); })
.outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
// Keep track of the node that is currently being displayed as the root.
var node;
d3.json("/d/4063550/flare.json", function(error, root) {
node = root;
var path = svg.datum(root).selectAll("path")
.data(partition.nodes)
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", click)
.each(stash);
d3.selectAll("input").on("change", function change() {
var value = this.value === "count"
? function() { return 1; }
: function(d) { return d.size; };
path
.data(partition.value(value).nodes)
.transition()
.duration(1000)
.attrTween("d", arcTweenData);
});
function click(d) {
node = d;
path.transition()
.duration(1000)
.attrTween("d", arcTweenZoom(d));
}
});
d3.select(self.frameElement).style("height", height + "px");
// Setup for switching data: stash the old values for transition.
function stash(d) {
d.x0 = d.x;
d.dx0 = d.dx;
}
// When switching data: interpolate the arcs in data space.
function arcTweenData(a, i) {
var oi = d3.interpolate({x: a.x0, dx: a.dx0}, a);
function tween(t) {
var b = oi(t);
a.x0 = b.x;
a.dx0 = b.dx;
return arc(b);
}
if (i == 0) {
// If we are on the first arc, adjust the x domain to match the root node
// at the current zoom level. (We only need to do this once.)
var xd = d3.interpolate(x.domain(), [node.x, node.x + node.dx]);
return function(t) {
x.domain(xd(t));
return tween(t);
};
} else {
return tween;
}
}
// When zooming: interpolate the scales.
function arcTweenZoom(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function(d, i) {
return i
? function(t) { return arc(d); }
: function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
};
}
</script>
@aalaap
Copy link

aalaap commented Mar 24, 2015

@JenniferPDX the JSON from the source is viewable at the following URL:

http://bl.ocks.org/mbostock/raw/4063550/flare.json

I hope that helps!

@parthaportfolio
Copy link

how to display the labels in each arc ?

@denjn5
Copy link

denjn5 commented Sep 18, 2016

This is great Kerry! I've updated to D3 version 4 (http://bl.ocks.org/denjn5/1a3f8e44cdcb3054121dfd991f59fbc2). That turned out to be more complex than I expected. I wouldn't have gotten there without this. I'm going to work on adding labels next. -- David

@hartzell
Copy link

This is great. I'm not particularly D3 savvy and would love to see something like the labels and/or center text from your sunburst sequence example. How hard would this be? Do you have anything similar in the works?

I'd like to use it to provide "daisydisk" like functionality for reports from a large fileserver.

@yalopov
Copy link

yalopov commented Jul 30, 2017

Seems like chart is not working because script can't fetch flare.json. What a shame, looks awesome!

@G202
Copy link

G202 commented Aug 10, 2017

Looks like someone beat me to it, but was just alerting you that the example here is currently not rendering at all.

@HenryQW
Copy link

HenryQW commented Aug 12, 2017

@hades1996 @absolute-ecomm
Replace the JSON path will fix it, see my fork: https://bl.ocks.org/WangQiru/effe919b93164bca9f59b73d37577ef1

@ReshuS19
Copy link

Hi, I am working on sunburst where I got the following issue.
Some of the nodes are not visible clearly that it is overlapped by other nodes. Could someone help me to fix it?
d3

Copy link

ghost commented Dec 15, 2018

how to show the percentage ?

@ureshvahalia
Copy link

I am trying to run this on a local system without a web server, and running into CORS errors while trying to access my local flare.js. Is there any workaround for this?

@math-alpha
Copy link

I am trying to run this on a local system without a web server, and running into CORS errors while trying to access my local flare.js. Is there any workaround for this?

Host the file on a remote source say jsonbin.io for instance then update the URL accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment