I've managed to get the following working (pie chart changing dynamically based on a slider value):
var x = function() {
return $("#slider").val();
}
var data = function() {
return [x(), ((100-x())/2), ((100-x())/2)];
}
var w = 100,
h = 100,
r = 50,
color = d3.scale.category20(),
pie = d3.layout.pie().sort(null),
arc = d3.svg.arc().outerRadius(r);
var svg = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
var arcs = svg.selectAll("path")
.data(pie(data()))
.enter().append("svg:path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) { this._current = d; });
var redraw = function() {
newdata = data(); // swap the data
arcs = arcs.data(pie(newdata)); // recompute the angles and rebind the data
arcs.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
};
// Store the currently-displayed angles in this._current.
// Then, interpolate from this._current to the new angles.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
I can't seem to modify it to include dynamic labels (use an object for data rather than an array {'label': 'label1', 'value': value}. How would I modify the above code to add labels?
This should work, keeping the labels and the pie chart as separate entities:
var x = function() {
return $("#slider").val();
}
var data = function() {
return [x(), ((100-x())/2), ((100-x())/2)];
}
var labels = function() {
var label1 = "LABEL 1: " + x();
var label2 = "LABEL 2: " + ((100-x())/2);
var label3 = "LABEL 3: " + ((100-x())/2);
return [label1, label2, label3];
}
var w = 200,
h = 100,
r = 50,
color = d3.scale.category20(),
pie = d3.layout.pie().sort(null),
arc = d3.svg.arc().outerRadius(r);
var svg = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + 50 + "," + h / 2 + ")");
var arcs = svg.selectAll("path")
.data(pie(data()))
.enter().append("svg:path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) { this._current = d; });
var label_group = svg.selectAll("text")
.data(labels())
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("x", 60)
.attr("y", function(d, i) { return (i * 20) - 16; });
var redraw = function() {
newdata = data(); // swap the data
arcs = arcs.data(pie(newdata)); // recompute the angles and rebind the data
arcs.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
label_group = label_group.data(labels());
label_group.transition().delay(300).text(function(d) {
return d;
});
Related
I have a d3 layout that is intended to produce 3 charts:
Custom item layout w/ transitions
Pie chart for sales by category (with transitions at some point)
Bar chart for top 5 performing items w/ transitions.
1 & 2 work OK but when I add the third chart, I see some strange behavior. The intention is to create a bar chart where the width of each bar is tied to the sales metric for the top N items determined like so:
data = data.filter(function(d){ return d.date === someDate});
var cf = crossfilter(data);
var salesDimension = cf.dimension(function(d){ return d.sales; });
topData = salesDimension.top(5);
The problem is that instead of drawing the bar chart, my code somehow overwrites the position of 5 items in chart 1 and moves them back to the origin. If I change 5 to 10 above then 10 items are overwritten and so on.
I double checked the scope of my variables and even tried changing the names of everything in my drawTopItems() which made no difference. I suspect that I am doing something incorrectly when it comes to selecting the svg element or applying classes to the svg group elements that I want to modify but I can't for the life of me see what. Can anyone tell me what I might be doing wrong?
Here is my issue in a fiddle: https://jsfiddle.net/Sledge/4eggpd5e/12/.
Here is my javascript code:
var item_width = 40, item_height = 60;
var margin = {top: 50, right: 50, bottom: 75, left: 40},
width = 700 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([0, height]);
var colorScale = d3.scaleLinear().domain([500,3000]).range(["white","#4169e1"]);
// Pie Chart parameters
var pieWidth = 300, pieHeight = 300;
var outerRadius = Math.min(pieWidth, pieHeight) / 2,
innerRadius = outerRadius * .50;
var pieColor = d3.scaleOrdinal(['#42b9f4','#3791f2','#374ff1','#25b22e','#107222']); // custom color scale
var legendRectSize = 18; // NEW
var legendSpacing = 4; // NEW
// Top Item Parameters
var topItemMargin = {top:25, right:25, bottom: 25, left: 25};
var topItemWidth = 300 - topItemMargin.left - topItemMargin.right,
topItemHeight = 300 - topItemMargin.top - topItemMargin.bottom;
var topItemXScale = d3.scaleLinear().range([0, topItemWidth]);
var barHeight = 20, barSpacing = 5;
/* SVG */
var svgItemLayout = d3.select("#item_layout")
.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 + ")");
var svgPieChart = d3.select("#pie_chart")
.append("svg")
.attr("width", pieWidth)
.attr("height", pieHeight)
.append("g")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")") ;
var svgTopItems = d3.select("#top_items")
.append("svg")
.attr("width", topItemWidth)
.attr("height", topItemHeight)
.append("g")
.attr("transform", "translate(" + topItemMargin.left + "," + topItemMargin.top + ")");
/* DRAW FUNCTIONS */
// a single function to draw
function drawItemLayout(data, someDate){
data.forEach(function(d) {
d.x_pos = +d.x_pos;
d.y_pos = +d.y_pos;
d.sales = +d.sales;
});
// pre-filter data
data = data.filter(function(d){ return d.date === someDate});
var x_offset = 5, y_offset = 5;
x.domain(d3.extent(data, function(d) { return d.x_pos; })); // set the x domain
y.domain(d3.extent(data, function(d) { return d.y_pos; })); // set the y domain
// create an update selection with a key function
var g_sel = svgItemLayout.selectAll("g")
.data(data, function(d){
return d.item_name;
});
// get rid of those leaving the update
g_sel.exit().remove();
// our entering g
var g_ent = g_sel.enter()
.append("g");
// add our rects to our g
g_ent.append("rect")
.attr("class", "dot") // wonder if I really need this class?
.attr("width", item_width)
.attr("height", item_height)
.attr("rx", 3)
.attr("ry", 3)
.style("fill", function(d){ return colorScale(d.sales); }) // color factor variable
.style("fill-opacity", 0.5);
// add our text to our g
g_ent.append("text")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("dx", item_width/2)
.attr("dy", item_height/2)
.text(function(d){ return d.item_name; });
// UPDATE + ENTER selection
g_sel = g_ent.merge(g_sel);
// move them into position with transition
g_sel
.transition()
.duration(1200)
.delay(function(d, i) { return i *40; })
.attr("transform", function(d){
return "translate(" + (x(d.x_pos) + x_offset) + "," + (y(d.y_pos) + y_offset) + ")";
});
}
function drawPieChart(data, someDate) {
data.forEach(function(d) {
d.x_pos = +d.x_pos;
d.y_pos = +d.y_pos;
d.sales = +d.sales;
});
// pre-filter data
data = data.filter(function(d){ return d.date === someDate});
var cf = crossfilter(data);
var salesDimension = cf.dimension(function(d){ return d.sales; });
var categoryDimension = cf.dimension(function(d){ return d.category; });
var categoryGroup = categoryDimension.group();
function reduceInitial(p, v) {
return {
sales : 0,
count : 0
};
}
function reduceAdd(p, v) {
p.sales = p.sales + v.sales;
p.count = p.count + 1;
return p;
}
function reduceRemove(p, v) {
p.sales = p.sales - v.sales;
p.count = p.count - 1;
return p;
}
categoryAggregated = categoryGroup.reduce(reduceAdd, reduceRemove, reduceInitial).all();
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.pie()
.value(function(d) { return d.value.sales; })
.sort(null);
var path = svgPieChart.selectAll('path')
.data(pie(categoryAggregated))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) { return pieColor(i);});
// Add a legend:
var legend = svgPieChart.selectAll('.legend')
.data(pieColor.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * pieColor.domain().length / 2;
var horz = -3 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', pieColor)
.style('stroke', pieColor);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return categoryAggregated[d].key; }); // returns text based on data index
}
function drawTopItems (data, someDate) {
data.forEach(function(d) {
d.x_pos = +d.x_pos;
d.y_pos = +d.y_pos;
d.sales = +d.sales;
});
// pre-filter data
data = data.filter(function(d){ return d.date === someDate});
var cf = crossfilter(data);
var salesDimension = cf.dimension(function(d){ return d.sales; });
topData = salesDimension.top(5);
topItemXScale.domain(d3.extent(topData, function(d) { return d.sales; })); // set the x domain
var f_sel = svgTopItems.selectAll("g")
.data(topData,function(d){ return d.item_name; }).enter();
f_sel.exit().remove();
var f_ent = f_sel.enter().append("g");
f_ent.append("rect")
.attr("class", "dot") // wonder if I really need this class?
.attr("width", function(d){ return d.sales })
.attr("height", barHeight)
.style("fill","#351eff") // color factor variable
.style("fill-opacity", 0.75);
// add our text to our g
f_ent.append("text")
.attr("font-size", 10)
.attr("text-anchor", "left")
.attr("fill", "black")
.attr("dx", item_width/2)
.attr("dy", item_height/2)
.text(function(d){ return d.item_name});
// UPDATE + ENTER selection
f_sel = f_ent.merge(f_sel);
f_sel.transition()
.duration(1200)
.delay(function(d, i) { return i *40; })
.attr("transform", function(d, i){
return "translate( 0, "+ i*25 +")" + ")";
});
}
/* MAIN */
var data = d3.csvParse( d3.select("pre#data").text());
drawItemLayout(data, '1-20-2017');
drawPieChart(data, '1-20-2017');
drawTopItems(data, '1-20-2017');
/* UPDATE DATA */
function updateData(date) {
//d3.csv("http://localhost:8080/udacity_test_vis_1/output_fixture_data.csv", function(data) {
var data = d3.csvParse( d3.select("pre#data").text());
drawItemLayout (data, date);
drawPieChart(data, date);
drawTopItems(data, date);
}
/* GET SELECTION */
$("#select_params").change(function(){
var date = $("#select_params :selected").val();
console.log(date);
updateData(date);
})
Just three problems:
You are repeating the enter() function:
var f_sel = svgTopItems.selectAll("g")
.data(topData,function(d){ return d.item_name; }).enter();
//this is an enter selection...
var f_ent = f_sel.enter().append("g");
//and you have enter() again here
So, remove the first enter: f_sel should be just the data-binding selection.
Move your merged selection to before appending the rectangles
Your translate has an extra parenthesis:
return "translate( 0, "+ i*25 +")" + ")";
With that problems corrected, this is your updated fiddle: https://jsfiddle.net/utf5hva2/
I am using d3.js to draw a pie transition chart. But when labels are placed in the data array as show below:
data = [{"label":"sector1", "value":25}, {"label":"sector2", "value":45}]
The pie chart won't be displayed. Instead "NaN" will be printed.
The complete code is pasted below:
var w = 400,
h = 400,
r = Math.min(w, h) / 2,
data = [{"label":"sector1", "value":25}, {"label":"sector2", "value":45}], // Data with label-value pairs
color = d3.scale.category20(),
arc = d3.svg.arc().outerRadius(r),
donut = d3.layout.pie();
var vis = d3.select("body").append("svg") // Place the chart in 'pie-chart-div'
.data([data])
.attr("width", w)
.attr("height", h);
var arcs = vis.selectAll("g.arc")
.data(donut)
.enter().append("g")
.attr("class", "arc")
.attr("transform", "translate(" + r + "," + r + ")");
var paths = arcs.append("path")
.attr("fill", function(d, i) { return color(i); });
var labels = arcs.append("text")
.attr("transform", function(d) { d.innerRadius = 120; return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.value; });
paths.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
paths.transition()
.ease("elastic")
.delay(function(d, i) { return 2000 + i * 50; })
.duration(750)
.attrTween("d", tweenDonut);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) {
return arc(i(t));
};
}
function tweenDonut(b) {
b.innerRadius = r * .6;
var i = d3.interpolate({innerRadius: 0}, b);
return function(t) {
return arc(i(t));
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
How to display the label names along with the values in the chart ?
You need to call donut with your data inside like that :
data2 = data.map(function(d) { return d.value}) // [25, 45]
...
.data(donut(data2))
and then call the label ;
.text(function(d, i) { return data[i].label; });
See http://jsfiddle.net/980f0cdj/1/
I am using pie transition chart of d3.js to visualize the potential customers.
The graph is drawn, but the labels are not displayed on the graph.
Here is the code:
var w = 400,
h = 400,
r = Math.min(w, h) / 2,
data = [25,45], // Data values
color = d3.scale.category20(),
arc = d3.svg.arc().outerRadius(r),
donut = d3.layout.pie();
var vis = d3.select("#pie-chart-div").append("svg") // Place the chart in 'pie-chart-div'
.data([data])
.attr("width", w)
.attr("height", h);
var arcs = vis.selectAll("g.arc")
.data(donut)
.enter().append("g")
.attr("class", "arc")
.attr("transform", "translate(" + r + "," + r + ")");
var paths = arcs.append("path")
.attr("fill", function(d, i) { return color(i); });
paths.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
paths.transition()
.ease("elastic")
.delay(function(d, i) { return 2000 + i * 50; })
.duration(750)
.attrTween("d", tweenDonut);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) {
return arc(i(t));
};
}
function tweenDonut(b) {
b.innerRadius = r * .6;
var i = d3.interpolate({innerRadius: 0}, b);
return function(t) {
return arc(i(t));
};
}
How to display labels in the pie transition chart ?
To display the text in the "exact location" (which I supposed is in the middle of the arc), you can use the centroid() function:
var labels = arcs.append("text")
.attr("transform", function(d) {
d.innerRadius = 120;
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.text(function(d) { return d.value; });
Check this demo:
var w = 400,
h = 400,
r = Math.min(w, h) / 2,
data = [25,45], // Data values
color = d3.scale.category20(),
arc = d3.svg.arc().outerRadius(r),
donut = d3.layout.pie();
var vis = d3.select("body").append("svg") // Place the chart in 'pie-chart-div'
.data([data])
.attr("width", w)
.attr("height", h);
var arcs = vis.selectAll("g.arc")
.data(donut)
.enter().append("g")
.attr("class", "arc")
.attr("transform", "translate(" + r + "," + r + ")");
var paths = arcs.append("path")
.attr("fill", function(d, i) { return color(i); });
var labels = arcs.append("text")
.attr("transform", function(d) { d.innerRadius = 120; return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.value; });
paths.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
paths.transition()
.ease("elastic")
.delay(function(d, i) { return 2000 + i * 50; })
.duration(750)
.attrTween("d", tweenDonut);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) {
return arc(i(t));
};
}
function tweenDonut(b) {
b.innerRadius = r * .6;
var i = d3.interpolate({innerRadius: 0}, b);
return function(t) {
return arc(i(t));
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
So, I've been updating a functioning but not elegant D3 chart using https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter9/pie-chart.html
My class looks like this:
function doughnutChart(selector_div) {
"use strict";
var _chart = {};
var _width = 200, _height = 200,
_data = [],
_svg, _bodyG, _pieG,
_radius = 100,
_inner_radius = 50;
_chart.render = function() {
if (!_svg) {
_svg = d3.select(selector_div).append("svg")
.attr("height", _height)
.attr("width", _width);
}
renderBody(_svg);
};
function renderBody(svg) {
if (!_bodyG) {
_bodyG = svg.append("g")
.attr("class", "body");
}
renderDoughnut();
}
function renderDoughnut() {
var pie = d3.layout.pie()
.sort(function (d) {
return d.id;
})
.value(function (d) {
return d.count + d.abnormal;
});
var arc = d3.svg.arc()
.outerRadius(_radius)
.innerRadius(_inner_radius);
if (!_pieG) {
_pieG = _bodyG.append("g")
.attr("class", "pie")
.attr("transform", "translate("
+ _radius
+ ","
+ _radius + ")");
}
renderSlices(pie, arc);
renderLabels(pie, arc);
}
}
function renderSlices(pie, arc) {
var slices = _pieG.selectAll("path.arc")
.data(pie(_data));
slices.enter()
.append("path")
.attr("class", "arc")
.attr("fill", function(d) {
return d.data.visualisation_colour;
});
slices.transition()
.attrTween("d", function(d) {
var currentArc = this.__current__;
if (!currentArc) {
currentArc = {startAngle: 0, endAngle: 0};
}
var interpolate = d3.interpolate(currentArc, d);
this.__current__ = interpolate(1);
return function(t) {
return arc(interpolate(t));
};
});
}
function renderLabels() {
_pieG.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("class", "inside")
.text(function(d) {
var total = 0;
for (var j = 0; j < _data.length; j++) {
total = total + _data[j].count + _data[j].abnormal;
}
return total;
});
}
_chart.data = function(d) {
if (!arguments.length) {
return _data;
}
_data = d;
return _chart;
};
return _chart;
}
When I use:
var chart = doughnutChart("#chart").data(data);
chart.render()
I get a nice chart rendered. But the update doesn't work:
data = $.map(cell_types, function(key, value) {
return key;
});
chart.render();
The main issue is:
How do I update this chart? I'm not sure how to get updated data into the chart. Calling render() again does not update the data despite the data variable being updated, and I can't seem to pass new data in. The book's example doesn't appear to have this issue, as testing that works without issue.
There is actually a simple error in syntax here:
if (!_pieG) {
_pieG = _bodyG.append("g")
.attr("class", "pie")
.attr("transform", "translate("
+ _radius
+ ","
+ _radius + ")");
renderSlices(pie, arc);
renderLabels(pie, arc);
}
Should actually be:
if (!_pieG) {
_pieG = _bodyG.append("g")
.attr("class", "pie")
.attr("transform", "translate("
+ _radius
+ ","
+ _radius + ")");
}
renderSlices(pie, arc);
renderLabels(pie, arc);
And then it updates correctly.
With the click of a button, I want to add a new dataset to my doughnut chart and have it transition the new dataset. The code I've written sort of does that but it runs into an issue when the number of individual data within the dataset is different from the previous i.e. going from [1,2] to [1,2,3,4].
I think the issue is that I need to create a new path whenever there the new dataset has more data, and remove paths whenever it has less. However, when I try to append data in my click function, it will append it without removing the old paths and will overlap on the chart.
Here is a version without appending, where the arctween will work but there will be empty pie arcs because I don't append path (arctween works half the time):
http://jsfiddle.net/njrPF/1/
var pieW = 500;
var pieH = 500;
var innerRadius = 100;
var outerRadius = 200;
var results_pie = d3.layout.pie()
.sort(null);
var pie_arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var svg_pie = d3.select("#pieTotal")
.attr("width", pieW)
.attr("height", pieH)
.append("g")
.attr("transform", "translate(" + pieW / 2 + "," + pieH / 2 + ")")
.attr("class", "piechart");
var pie_path = svg_pie.selectAll("path").data(results_pie([1, 2]))
.enter().append("path")
.attr("d", pie_arc)
.each(function (d) {
this._current = d;
}) // store the initial values
.attr("class", "vote_arc")
.attr("value", function (d, i) {
return (i - 1);
});
var pie_votes = [1, 2];
var pie_colors = ["#0f0", "#f00"];
$(svg_pie).bind("monitor", worker);
$(svg_pie).trigger("monitor");
function worker(event) {
pie_path = pie_path.data(results_pie(pie_votes))
.attr("fill", function (d, i) {
return pie_colors[i];
});
pie_path.transition().duration(500).attrTween("d", arcTween).each('end', function (d) {
if (d.value <= 0) {
this.remove();
}
});
setTimeout(function () {
$(svg_pie).trigger("monitor");
}, 500);
}
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function (t) {
return pie_arc(i(t));
};
}
$('button').click(function () {
pie_votes = [];
pie_colors = [];
for (var i = 0; i < Math.floor(Math.random() * 6); i++) {
//sets new values on pie arcs
pie_votes.push(Math.floor(Math.random() * 10));
pie_colors.push("#" + (Math.floor(Math.random() * 16777215)).toString(16));
}
pie_path = pie_path.data(results_pie(pie_votes))
.attr("fill", function (d, i) {
return pie_colors[i]
});
pie_path.transition().duration(500).attrTween("d", arcTween).each('end', function (d) {
if (d.value <= 0) {
this.remove();
}
});
});
Here is a version where I try to append new paths but they overlap:
http://jsfiddle.net/njrPF/3/
var pieW = 500;
var pieH = 500;
var innerRadius = 100;
var outerRadius = 200;
var results_pie = d3.layout.pie()
.sort(null);
var pie_arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var svg_pie = d3.select("#pieTotal")
.attr("width", pieW)
.attr("height", pieH)
.append("g")
.attr("transform", "translate(" + pieW / 2 + "," + pieH / 2 + ")")
.attr("class", "piechart");
var pie_path = svg_pie.selectAll("path").data(results_pie([1, 2]))
.enter().append("path")
.attr("d", pie_arc)
.each(function (d) {
this._current = d;
}) // store the initial values
.attr("class", "vote_arc")
.attr("value", function (d, i) {
return (i - 1);
});
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function (t) {
return pie_arc(i(t));
};
}
$('button').click(function () {
pie_votes = [];
pie_colors = [];
for (var i = 0; i < Math.floor(Math.random() * 10); i++) {
//sets new values on pie arcs
pie_votes.push(Math.floor(Math.random() * 10));
pie_colors.push("#" + (Math.floor(Math.random() * 16777215)).toString(16));
}
pie_path = pie_path.data(results_pie(pie_votes))
.enter().append("path")
.attr("d", pie_arc)
.each(function (d) {
this._current = d; }) // store the initial values
.attr("class", "vote_arc")
.attr("value", function (d, i) {
return (i - 1);
});
pie_path.attr("fill", function (d, i) {
return pie_colors[i]
});
pie_path.transition().duration(500).attrTween("d", arcTween).each('end', function (d) {
if (d.value <= 0) {
this.remove();
}
});
});
Thanks in advance.
You need to handle the enter and exit selections as well as the update selection. See for example this tutorial. The relevant code in your case would be
pie_path = pie_path.data(results_pie(pie_votes));
pie_path.enter().append("path")
.attr("d", pie_arc)
.each(function (d) {
this._current = d;
}) // store the initial values
.attr("class", "vote_arc")
.attr("value", function (d, i) {
return (i - 1);
});
pie_path.exit().remove();
Complete example here.