Error: <path> attribute d: Expected number, "….35254915624212LNaN,NaNZ" - d3.js

I am trying to build pie-chart using D3js. I am getting an error while running the code and pie chart is not coming properly.
This is the code:
var svg = d3.select('#pie_chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var total=0;
for(var a=0;a<data.length;a++){
total=total+parseInt(data[a].count);
}
var pie_data=[];
for( var a=0;a<data.length;a++){
pie_data[a]=(data[a].count/total)*100;
}
var arc = d3.arc().outerRadius(150);
var pie = d3.pie()
.value(function(d,i) {
return pie_data[i];
}).sort(null);
var path = svg.selectAll('path')
.data(pie(data))
.enter().append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return data[i].color;
});

Set innerRadius property of d3 arc.
var arc = d3.arc().outerRadius(150).innerRadius(0);
var width = 500,
height = 400;
var data = [{
count: 10,
color: 'black'
}, {
count: 20,
color: 'green'
}, {
count: 30,
color: 'blue'
}];
var svg = d3.select('#pie_chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var total = 0;
data.forEach(function(d) {
total += d.count;
});
var pie_data = [];
for (var a = 0; a < data.length; a++) {
pie_data[a] = (data[a].count / total) * 100;
}
var arc = d3.arc().outerRadius(150).innerRadius(0);
var pie = d3.pie()
.sort(null)
.value(function(d) {
return d;
});
var path = svg.selectAll('path')
.data(pie(pie_data))
.enter().append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return data[i].color;
});
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="pie_chart"></div>

Related

How to convert D3js V2 to V4?

I tried to migrate D3js V2 to V4 of below example:
https://jasonneylon.wordpress.com/2013/09/05/two-sided-horizontal-barchart-using-d3-js/
But getting error while migrating:
Error: attribute y: Expected length, "NaN".
at line no 201:
.attr("y", function(d, z){ return y(z) + y.bandwidth()/2; } )
and
line no 223:
.attr("y", function(d){ return y(d) + y.bandwidth()/2; }
Please advice.
<!DOCTYPE html>
<html>
<head>
<title>Bar Chart</title>
<script src="http://d3js.org/d3.v4.js"></script>
<style type="text/css">
.chart {
background: #00ccff;
margin: 10px;
padding-top: 10px;
}
.chart .right {
stroke: white;
fill: indianred;
}
.chart .left {
stroke: white;
fill: steelblue;
}
.chart rect:hover {
fill: #64707d;
}
.chart text {
fill: white;
}
.chart text.name {
fill: black;
}
</style>
</head>
<body>
<h1>Two sided horiztontal bar chart</h1>
<script type="text/javascript">
var randomNumbers = function() {
var numbers = [];
for (var i = 0; i < 20; i++) {
numbers.push(parseInt(Math.random() * 19) + 1);
}
return numbers;
};
var randomNames = function() {
var names = [];
for (var i = 0; i < 20; i++) {
names.push(String.fromCharCode(65 + Math.random() * 25) + String.fromCharCode(65 + Math.random() * 25) + String.fromCharCode(65 + Math.random() * 25));
}
return names;
};
var names = randomNames();
var leftData = randomNumbers();
var rightData = randomNumbers();
for (var i= 0; i< names.length; i++) {
console.log(names[i] + " from: " + leftData[i] + " to: " + rightData[i]);
}
var labelArea = 160;
var chart,
width = 400,
bar_height = 20,
height = bar_height * (names.length);
var rightOffset = width + labelArea;
var chart = d3.select("body")
.append('svg')
.attr('class', 'chart')
.attr('width', labelArea + width + width)
.attr('height', height);
var xFrom = d3.scaleLinear()
.domain([0, d3.max(leftData)])
.range([0, width]);
var y = d3.scaleBand()
.domain(names)
.rangeRound([10, height]);
console.log('Y Range: '+y.range());
console.log('y.bandwidth(): '+y.bandwidth()); // 33
var yPosByIndex = function(d, index){ return y(index); }
chart.selectAll("rect.left")
.data(leftData)
.enter().append("rect")
.attr("x", function(pos) { return width - xFrom(pos); })
.attr("y", yPosByIndex)
.attr("class", "left")
.attr("width", xFrom)
.attr("height", y.bandwidth());
chart.selectAll("text.leftscore")
.data(leftData)
.enter().append("text")
.attr("x", function(d) { return width - xFrom(d); })
.attr("y", function(d, z){ return y(z) + y.bandwidth()/2; } )
.attr("dx", "20")
.attr("dy", ".36em")
.attr("text-anchor", "end")
.attr('class', 'leftscore')
.text(String);
chart.selectAll("text.name")
.data(names)
.enter().append("text")
.attr("x", (labelArea / 2) + width)
.attr("y", function(d){ return y(d) + y.bandwidth()/2; } )
.attr("dy", ".20em")
.attr("text-anchor", "middle")
.attr('class', 'name')
.text(String);
var xTo = d3.scaleLinear()
.domain([0, d3.max(rightData)])
.range([0, width]);
chart.selectAll("rect.right")
.data(rightData)
.enter().append("rect")
.attr("x", rightOffset)
.attr("y", yPosByIndex)
.attr("class", "right")
.attr("width", xTo)
.attr("height", y.bandwidth());
chart.selectAll("text.score")
.data(rightData)
.enter().append("text")
.attr("x", function(d) { return xTo(d) + rightOffset; })
.attr("y", function(d,z){ console.log(y(z)); return y(z) + y.bandwidth()/2; } )
.attr("dx", -5)
.attr("dy", ".36em")
.attr("text-anchor", "end")
.attr('class', 'score')
.text(String);
</script>
</body>
</html>
You call console.log(y(z)); and you get 40 undefined. And you don't investigate why?
What is the domain of y? Strings
So if you give it a number it most likely gives you a wrong answer.
The same reason why your function
var yPosByIndex = function(d, index){ return y(index); }
is wrong.
The main reason you have all these problems is that you have multiple arrays of information that are related based on the index. Create 1 array with objects that contain all the related data.
var data = d3.range(20).map(i => { return {name: randomName(), left:randomNumber(), right:randomNumber()}; } );
Now adjust your program to use d.name, d.left, d.right.
Don't use parseInt if you want to calculate the integer part of a number, it is slow and unclear what you want, use Math.floor()
Better to use the same xScale for the left and right bars. Why should a bar with value 10 be smaller on one of the sides?

move a slice of the pie chart using d3.js

In the code below, a simple pie chart is created, but I am not able to move one slice towards the outer side of the chart when selected.
I want the individual (element) slice to be positioned outer the pie and the rest of the pie chart elements(slices) in its usual position, something like this:
Here is my code:
<!DOCTYPE html>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data = [35, 20, 45];
var width = 300,
height = 300,
radius = 150;
var arc = d3.arc()
.outerRadius(130);
var arcLabel = d3.arc()
.outerRadius(radius - 30)
.innerRadius(radius - 20);
var pie = d3.pie()
.value(function(d) {
return d;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var emptyPies = svg.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
emptyPies.append("path")
.attr("d", arc)
.style("fill", function(d, i) {
return color[i];
})
emptyPies.append("text")
.attr("transform", function(d) {
return "translate(" + arcLabel.centroid(d) + ")";
})
.text(function(d) {
return d.data;
});
</script>
A simple solution is creating a different arc generator:
var arc2 = d3.arc()
.outerRadius(radius)
.innerRadius(60);
And, when setting the "d" attribute, choosing which arc generator to use. For instance, moving the red slice:
emptyPies.append("path")
.attr("d", function(d,i){
return i != 1 ? arc(d) : arc2(d);
})
Here is your code with that change:
<!DOCTYPE html>
<style>
.arc text {
text-anchor: middle;
}
.arc path {
stroke: white;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data = [35, 20, 45];
var width = 300,
height = 300,
radius = Math.min(width, height) / 2;
var color = ["brown", "red", "blue"];
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(50);
var arc2 = d3.arc()
.outerRadius(radius)
.innerRadius(60);
var arcLabel = d3.arc()
.outerRadius(radius - 30)
.innerRadius(radius - 20);
var pie = d3.pie()
.value(function(d) {
return d;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var emptyPies = svg.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
emptyPies.append("path")
.attr("d", function(d,i){
return i != 1 ? arc(d) : arc2(d);})
.style("fill", function(d, i) {
return color[i];
})
emptyPies.append("text")
.attr("transform", function(d) {
return "translate(" + arcLabel.centroid(d) + ")";
})
.text(function(d) {
return d.data;
});
</script>
A simple solution is to use multiple arc() but to do slice we can use arc.centroid() of 2nd arc. The following code will work in v5.
function onDrawPieChart() {
var data = [35, 20, 45];
var color = d3.schemeCategory10;
var width = 600;
var height = 600;
var radius = 100;
var pie = d3.pie().value((d) => d);
var arc = d3.arc().innerRadius(0).outerRadius(130);
var arc2 = d3.arc().innerRadius(0).outerRadius(20);
var slicedIndex = 1;
var pieData = pie(data);
var centroid = arc2.centroid(pieData[slicedIndex]);
var svg = d3
.select("body")
.append("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height].join(" "))
.attr("width", width)
.attr("height", height)
.append("g");
svg
.selectAll("path")
.data(pieData)
.join("path")
.attr("fill", (d, i) => color[i])
.attr("d", (d) => arc(d))
.attr("transform", (d, i) => {
if (i === slicedIndex) {
var [x, y] = centroid;
return "translate(" + x + ", " + y + ")";
}
});
}

Text is not appearing on arc donut in D3js

Text is not appearing on the Donut Chart.Help me to fix this thing along with explanation.I am very new to D3js.
This is my sample code.
my html code is:
.arc text {
font: 10px sans-serif;
}
.arc path {
stroke: #fff;
}
and js code is:
var width = 600, height = 500, radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var arc = d3.svg.arc().outerRadius(radius - 10)
.innerRadius(radius - 70);
var pie = d3.layout.pie()
.value(function(d) {
return d.population;
});
var svg = d3.select("body").append("svg").attr("width", width).attr(
"height", height).append("g").attr("transform",
"translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("date.csv", type, function(error, data) {
if (error)
throw error;
var g = svg.selectAll(".arc").data(pie(data)).enter().append("g")
.attr("class", "arc");
g.append("path").attr("d", arc).style("fill", function(d, i) {
return color(i);
});
//.style("fill", function(d) { return color(d.date.age); });
g.append("text").attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
}).attr("dy", ".35em").text(function(d) {
return d.date.age;
});
});
function type(d) {
d.population = +d.population;
return d;
}
csv file is
age,population
5,2704659
13,4499890
17,2159981
24,3853788

d3 how to tween inner radius for pie chart

I need to animate pie chart into a donut chart (or ring chart).
Here is my code:
var arc = d3.svg.arc().outerRadius(radius-margin).innerRadius(0)
var arc2 = d3.svg.arc().outerRadius(radius-margin).innerRadius(60)
var path = pie_chart.selectAll('path')
.data(pie(data))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color_scale(d.data.device)
})
.transition().attr('d', arc2)
Some times it's working but sometimes it is not. I have tried to apply transition to arc but not working.
var arc2 = d3.svg.arc().outerRadius(radius-margin).innerRadius(0).transition().innerRadius(60)
I would write my own arcTween function for this to take complete control of the transition:
function arcTween(d) {
var i = d3.interpolateNumber(0, radius-70); //<-- radius of 0 to donut
return function(t) {
var r = i(t),
arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(r); //<-- create arc
return arc(d); //<-- return arc path
};
}
Full code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.category10();
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var data = [10, 20, 30, 40];
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d, i) {
return color(i);
})
.transition()
.delay(100)
.duration(5000)
.attrTween("d", arcTween);
function arcTween(d) {
var i = d3.interpolateNumber(0, radius-70);
return function(t) {
var r = i(t),
arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(r);
return arc(d);
};
}
</script>
</body>
Or just give someone a headache:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.category10();
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var data = [10, 20, 30, 40];
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
var arcs = g.append("path")
.attr("d", arc)
.style("fill", function(d, i) {
return color(i);
});
(function repeat() {
arcs.transition()
.duration(500)
.attrTween("d", arcTweenOut)
.transition()
.duration(500)
.attrTween("d", arcTweenIn)
.each('end', repeat)
})();
function arcTweenOut(d) {
var i = d3.interpolateNumber(0, radius-70);
return function(t) {
var r = i(t),
arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(r);
return arc(d);
};
}
function arcTweenIn(d) {
var i = d3.interpolateNumber(radius-70, 0);
return function(t) {
var r = i(t),
arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(r);
return arc(d);
};
}
</script>
</body>

Why are events from d3 in firefox not handled

Please look at http://bl.ocks.org/HoffmannP/95392bf4a37344793786 and help me find an explenation why it just doesn't work in FF but works like a charm in Chrome.
because you're using .style for width, height and x when you need to use .attr.
Having these as .styles is part of SVG 2 and not SVG 1.1 and SVG 2 is unfinished. Firefox does not yet implement this part of SVG 2, although it does implement other parts that Chrome does not.
var margin = {top: 50, right: 20, bottom: 60, left: 70};
var width = 800 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([0, 4])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, 60])
.range([height, 0]);
var yVal = d3.scale.linear()
.domain([60, 0])
.range([height, 0]);
var yAxisMinor = d3.svg.axis()
.scale(y)
.ticks(13)
.tickSize(width, 0)
.orient('right');
var yAxisMajor = d3.svg.axis()
.scale(y)
.ticks(7)
.tickSize(width, 0)
.tickPadding(-(width + 5))
.tickFormat(d3.format('d'))
.orient('right');
var svg = d3.select('body').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 xLabel = svg.append('g')
.attr('class', 'x label')
.attr('transform', 'translate(0, ' + height/2 + ') rotate(-90)')
.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '-40')
.text('Prozent');
var gx = svg
.append('g').attr('class', 'x axis');
gx.append('g')
.attr('transform', 'translate(7, -15)')
.append('line')
.attr('x2', '0')
.attr('y2', height + 15);
gx.append('g')
.attr('transform', 'translate(0, -26) scale(0.15, 0.15)')
.append('path')
.attr('d', 'M0,86.6L50,0L100,86.6C50,75 50,75 0,86.6z');
var gyMinor = svg.append('g')
.attr('class', 'y axis minor')
.call(yAxisMinor);
gyMinor.selectAll('text').remove();
var gyMajor = svg.append('g')
.attr('class', 'y axis major')
.call(yAxisMajor);
gyMajor.selectAll('text')
.style('text-anchor', 'end')
.attr('dy', '7px');
var drawArea = svg.append('g')
.attr('class', 'block')
.attr('transform', 'translate(' + 20 + ', ' + height + ') scale(1, -1)');
var backBlocks = drawArea
.selectAll('rect.back')
.data([64, 64, 64, 64])
.enter()
.append('rect')
.attr('class', 'back')
.attr('width', width/5)
.attr('height', yVal)
.attr('x', function (d, i) { return x(i); });
var frontBlocks = drawArea
.selectAll('rect.front')
.data([0,0,0,0])
.enter()
.append('rect')
.attr('class', 'front')
.attr('width', width/5)
.attr('height', yVal)
.attr('x', function (d, i) { return x(i); });
var newHeight = function (d, i) {
var y = d3.event.clientY;
d3.select(frontBlocks[0][i % 4]).style('height', height + margin.bottom - y);
};
var currentActiveBlock = false;
drawArea.selectAll('rect')
.on('mouseover', function (d, i) {
d3.select(backBlocks[0][i % 4]).style('opacity', '0.5');
})
.on('mouseout', function () {
backBlocks.style('opacity', '0');
})
.on('mousedown', function (d, i) {
d3.select(backBlocks[0][i % 4]).style('opacity', '0.5');
newHeight.call(this, d, i);
currentActiveBlock = i % 4;
})
.on('mousemove', function (d, i) {
if (currentActiveBlock === false) {
return;
}
newHeight.call(this, d, currentActiveBlock);
})
.on('mouseup', function (d, i) {
d3.select(frontBlocks[0][currentActiveBlock]).style('opacity', '1');
newHeight.call(this, d, currentActiveBlock);
currentActiveBlock = false;
});
body {
font: 18px sans-serif;
}
svg {
}
.label text {
font-weight: bold;
}
.y.axis path {
display: none;
}
.x.axis path {
fill: #333;
}
.axis line {
shape-rendering: crispEdges;
stroke: #333;
stroke-width: 2px;
}
.axis.minor line {
stroke-width: 1px;
}
.axis text {
text-anchor: end;
}
.block rect {
cursor: ns-resize;
}
.block rect.back {
opacity: 0.0;
fill: #ddd;
}
}
.block rect.front {
fill: #222;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Resources