Skip to content

Instantly share code, notes, and snippets.

@mbostock
Forked from mbostock/.block
Last active December 19, 2023 11:14
Show Gist options
  • Save mbostock/1346410 to your computer and use it in GitHub Desktop.
Save mbostock/1346410 to your computer and use it in GitHub Desktop.
Pie Chart Update, II
license: gpl-3.0

This variation of a donut chart demonstrates how to update values with an animated transition. Clicking on the radio buttons changes the displayed metric.

Next: Missing Data
Previous: Static Update

apples oranges
53245 200
28479 200
19697 200
24037 200
40245 200
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
text {
font: 10px sans-serif;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
</style>
<form>
<label><input type="radio" name="dataset" value="apples" checked> Apples</label>
<label><input type="radio" name="dataset" value="oranges"> Oranges</label>
</form>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.value(function(d) { return d.apples; })
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.tsv("data.tsv", type, function(error, data) {
if (error) throw error;
var path = svg.datum(data).selectAll("path")
.data(pie)
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) { this._current = d; }); // store the initial angles
d3.selectAll("input")
.on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"oranges\"]").property("checked", true).each(change);
}, 2000);
function change() {
var value = this.value;
clearTimeout(timeout);
pie.value(function(d) { return d[value]; }); // change the value function
path = path.data(pie); // compute the new angles
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
});
function type(d) {
d.apples = +d.apples;
d.oranges = +d.oranges;
return d;
}
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
</script>
@mbostock
Copy link
Author

@evaughen Visualizing an all-zero dataset with a pie or donut chart won’t work very well.

@evaughen
Copy link

I hope some day soon the code for D3 will seem less like magic and more like logic. I'll just to deal with the all zero dataset before it reaches the interpolate stage. Thanks for all your hard work...

@whiter4bbit
Copy link

function arcTween(a) {
  var i = d3.interpolate(this._current, a);
  /*
   *  I think, that it makes sense to change to this._current = i(1) to store latest transition, it works now, because of
   *  references. Change this._current = jQuery(this, {}, i(0)); will break animation.
   */
  this._current = i(0);
  return function(t) {
    return arc(i(t));
  };
} 

@bmaland
Copy link

bmaland commented Apr 8, 2014

Here's a jsbin version: http://jsbin.com/hegob/1/edit?js,output

@mcordingley
Copy link

Shouldn't line 85 read this._current = i(1); to set the value for the next update? I don't see how "_current is updated in-place by d3.interpolate".

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