How to solve duplicate label in zoom - d3.js

i have a problem when i do a zoom in my map because the labels appears duplicate. I know that my problem appears because in my zoom i dont delete the label. I know where is the problem, i need to delete the oldest label when i do a zoom but i dont know how and where to solve this.
Any idea? Ty for all.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
margin: 0;
}
path {
fill: none;
stroke: green;
stroke-linejoin: round;
stroke-width: 1.5px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<script src="d3.geo.tile.min.js"></script>
<script>
var width = Math.max(960, window.innerWidth),
height = Math.max(600, window.innerHeight);
var tile = d3.geo.tile()
.size([width, height]);
var projection = d3.geo.mercator()
.scale((3 << 12) / 2 / Math.PI)
.translate([width / 2, height / 2]);
var center = projection([-3, 36]);
var path = d3.geo.path()
.projection(projection);
var zoom = d3.behavior.zoom()
.scale(projection.scale() * 2 * Math.PI)
.translate([width - center[0], height - center[1]])
.on("zoom", zoomed);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var raster = svg.append("g");
var g = svg.append("g");
var vector = svg.append("path");
d3.json("es.json", function(error, es) {
if (error) throw error;
svg.call(zoom);
vector.datum(topojson.mesh(es, es.objects.provinces));
zoomed();
});
function zoomed() {
d3.csv("data/country-capitals.csv", function(err, capitals) {
capitals.forEach(function(i){
addpoint(i.CapitalLongitude, i.CapitalLatitude, i.CapitalName );
});
});
var tiles = tile
.scale(zoom.scale())
.translate(zoom.translate())
();
projection
.scale(zoom.scale() / 2 / Math.PI)
.translate(zoom.translate());
vector
.attr("d", path);
var image = raster
.attr("transform", "scale(" + tiles.scale + ")translate(" + tiles.translate + ")")
.selectAll("image")
.data(tiles, function(d) { return d; });
image.exit()
.remove();
image.enter().append("image")
.attr("xlink:href", function(d) { return "http://" + ["a", "b", "c"][Math.random() * 3 | 0] + ".tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] + ".png"; })
.attr("width", 1)
.attr("height", 1)
.attr("x", function(d) { return d[0]; })
.attr("y", function(d) { return d[1]; });
}
function addpoint(lat,lon,text) {
var gpoint = g.append("g").attr("class", "gpoint");
var x = projection([lat,lon])[0];
var y = projection([lat,lon])[1];
gpoint.append("svg:circle")
.attr("cx", x)
.attr("cy", y)
.attr("class","point")
.attr("r", 1.5);
//conditional in case a point has no associated text
if(text.length>0){
gpoint.append("text")
.attr("x", x+2)
.attr("y", y+2)
.attr("class","text")
.text(text);
}
}
</script>
CSV is here:
CountryName,CapitalName,CapitalLatitude,CapitalLongitude,CountryCode,ContinentName
Brazil,Brasilia,-15.783333333333333,-47.916667,BR,South America
Colombia,Bogota,4.6,-74.083333,CO,South America
Egypt,Cairo,30.05,31.250000,EG,Africa
France,Paris,48.86666666666667,2.333333,FR,Europe
Iraq,Baghdad,33.333333333333336,44.400000,IQ,Asia
South Korea,Seoul,37.55,126.983333,KR,Asia
Kosovo,Pristina,42.666666666666664,21.166667,KO,Europe
Mexico,Mexico City,19.433333333333334,-99.133333,MX,Central America

Before you zoom you can remove all the group containing text and circle like this:
function zoomed() {
d3.selectAll(".gpoint").remove();
d3.csv("my.csv", function(err, capitals) {
capitals.forEach(function(i){
addpoint(i.CapitalLongitude, i.CapitalLatitude, i.CapitalName );
});
});
//your code
Working code here

Related

D3 transition along segments of path and pause at coordinate values

I would like to be able to click on a circle (coordinate points); bring the marker to the position of the circle and pause at the position of the circle and then resume again along the path.
In addition I would like to activate a circle when marker is paused on them - they are clicked (or their Voronoi cell is clicked). My intention is to have an on click function to an href for the circle coordinates eventually.
I think I need to pass the index of the path coordinates into the translateAlong function instead of the time variables but can't work out how to do this.
I’m not sure if the Voronoi cells are necessary - I tried to add this thinking I could pause my transition and activate my circles with the Voronoi cells. In any case I can’t activate the circle with the Voronoi cell.
I was helped considerably recently on Stackoverflow d3 on click on circle pause and resume transition of marker along line
and I am hoping for assistance again
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>basic_animateBetweenCircles</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
path {
stroke: #848484;
fill: none;
}
circle {
fill: steelblue;
stroke: steelblue;
stroke-width: 3px;
}
.line {
fill: none;
stroke: #FE642E;
stroke-width: 4;
stroke-dasharray: 4px, 8px;
}
.point{
fill:#DF013A;
}
</style>
</head>
<body>
<script>
var width = 960,
height = 500;
var data = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
//check index of path data
for (var i = 0; i < data.length; i++) {
var coordindex = i + " " + data[i];
console.log("Coordindex: " + coordindex);
//return coordindex;
};
var duration = 20000;
var line = d3.line()
.x(function(d) {return (d)[0];})
.y(function(d) {return (d)[1];});
var voronoi = d3.voronoi()
.extent([[0, 0], [width, height]]);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//path to animate - marker transitions along this path
var path = svg.append("path")
.data([data])
.attr("d", line)
.attr('class', 'line')
.attr("d", function(d) {
return line(d)
});
//voronoi
var voronoiPath = svg.append("g")
.selectAll("path")
.data(voronoi.polygons(data))
.enter().append("path")
.attr("d", polygon)
.on("touchmove mousemove", function() {
d3.select(this)
.style("fill", "purple");
});
//Want to activate circles when marker paused on them / in voronoi cell - intention is to have on click to href
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class", "point")
.attr("r", 10)
.attr("transform", function(d) { return "translate(" + d + ")"; })
.on('click', function(d, i) {
d3.select(this)
.style("fill", "green");
if (d3.active(this)) {
marker.transition();
setTimeout(function() {
pauseValues.lastTime = pauseValues.currentTime;
//console.log(pauseValues);
}, 100);
} else {
transition();
}
});
var pauseValues = {
lastTime: 0,
currentTime: 0
};
//marker to transition along path
var marker = svg.append("circle")
.attr("r", 19)
.attr("transform", "translate(" + (data[0]) + ")")
.on('click', function(d, i) {
if (d3.active(this)) {
marker.transition();
setTimeout(function() {
pauseValues.lastTime = pauseValues.currentTime;
//console.log(pauseValues);
}, 100);
} else {
transition();
}
});
function transition() {
marker.transition()
.duration(duration - (duration * pauseValues.lastTime))
.attrTween("transform", translateAlong(path.node()))
.on("end", function() {
pauseValues = {
lastTime: 0,
currentTime: 0
};
transition()
});
}
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
t += pauseValues.lastTime;
var p = path.getPointAtLength(t * l);
pauseValues.currentTime = t;
return "translate(" + p.x + "," + p.y + ")";
};
};
}
function polygon(d) {
return "M" + d.join("L") + "Z";
}
</script>
</body>
If you want to pause at points, I would not run one transition across the entire path. Instead, I would break it up into N transitions, moving from point to point. Before starting the circle on it's next leg, you can pause it for a time. To do this, I would just transition along each line segment with a little algebra:
// copy our data
transData = data.slice();
function transition() {
marker.transition()
.ease(d3.easeLinear)
.duration(duration)
.attrTween("transform", function(){
// get our two points
// slope between them
// and intercetp
var p0 = transData.shift(),
p1 = transData[0];
m = (p0[1] - p1[1]) / (p0[0] - p1[0]),
b = p0[1] - (m * p0[0]),
i = d3.interpolateNumber(p0[0], p1[0]);
// move the point along the line
return function(t){
var x = i(t),
y = m*x + b;
return "translate(" + x + "," + y + ")";
}
})
// one line segment is complete
.on("end", function(){
// if no more movements, stop
if (transData.length <= 1) return;
iter++;
// determine if this is a "pause"
setTimeout(transition, pausePoints.indexOf(iter) !== -1 ? pauseTime : 0);
});
Running code, click a dot to start you can pause a multiple points:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>basic_animateBetweenCircles</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
path {
stroke: #848484;
fill: none;
}
circle {
fill: steelblue;
stroke: steelblue;
stroke-width: 3px;
}
.line {
fill: none;
stroke: #FE642E;
stroke-width: 4;
stroke-dasharray: 4px, 8px;
}
.point {
fill: #DF013A;
}
</style>
</head>
<body>
<script>
var width = 960,
height = 500;
var data = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
var duration = 20000/data.length,
pauseTime = 2000;
var line = d3.line()
.x(function(d) {
return (d)[0];
})
.y(function(d) {
return (d)[1];
});
var voronoi = d3.voronoi()
.extent([
[0, 0],
[width, height]
]);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//path to animate - marker transitions along this path
var path = svg.append("path")
.data([data])
.attr("d", line)
.attr('class', 'line')
.attr("d", function(d) {
return line(d)
});
//voronoi
var voronoiPath = svg.append("g")
.selectAll("path")
.data(voronoi.polygons(data))
.enter().append("path")
.attr("d", polygon);
//Want to activate circles when marker paused on them / in voronoi cell - intention is to have on click to href
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class", "point")
.attr("r", 10)
.attr("transform", function(d) {
return "translate(" + d + ")";
})
.on('click', function(d, i) {
d3.select(this)
.style("fill", "green");
pausePoints.push(i);
if (pausePoints.length === 1)
transition();
});
//marker to transition along path
var marker = svg.append("circle")
.attr("r", 19)
.attr("transform", "translate(" + (data[0]) + ")");
var pausePoints = [],
iter = 0,
transData = data.slice();
function transition() {
marker.transition()
.ease(d3.easeLinear)
.duration(duration)
.attrTween("transform", function(){
var p0 = transData.shift(),
p1 = transData[0];
m = (p0[1] - p1[1]) / (p0[0] - p1[0]),
b = p0[1] - (m * p0[0]),
i = d3.interpolateNumber(p0[0], p1[0]);
return function(t){
var x = i(t),
y = m*x + b;
return "translate(" + x + "," + y + ")";
}
})
.on("end", function(){
if (transData.length <= 1) return;
iter++;
setTimeout(transition, pausePoints.indexOf(iter) !== -1 ? pauseTime : 0);
});
}
function polygon(d) {
return "M" + d.join("L") + "Z";
}
</script>
</body>

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 + ")";
}
});
}

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>

Reference error in d3.js code

I am new to javascript as well as d3. I am running one of the graph codes from the website but I am getting the following error:
Uncaught TypeError: Cannot read property 'children' of null d3.v3.min.js:2
gu d3.v3.min.js:2
n d3.v3.min.js:4
e d3.v3.min.js:4
e d3.v3.min.js:4
(anonymous function) index.html:44
(anonymous function) d3.v3.min.js:1
t d3.v3.min.js:1
u d3.v3.min.js:1
Here's the whole code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke: #fff;
fill-rule: evenodd;
}
</style>
<body>
<script src="http://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()
.value(function(d) { return d.size; });
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)); });
d3.json("http://bl.ocks.org/d/4063550/flare.json", function(root) {
var path = svg.selectAll("path")
.data(partition.nodes(root))
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", click);
function click(d) {
path.transition()
.duration(750)
.attrTween("d", arcTween(d));
}
});
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(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>
Around line 44 of index.html you can see a possible source of the problem:
d3.json("http://bl.ocks.org/d/4063550/flare.json", function(root) {
var path = svg.selectAll("path")
.data(partition.nodes(root))
The problem is that the file http://bl.ocks.org/d/4063550/flare.json doesn't exist on your domain (which, I am guessing, is localhost).
In this case, the data is null and the error is non-null.
As suggested in the comments, try hosting the file locally (or where you are hosting your Javascript code) and it should work.
To start a local server
If you have python, then you can start a local webserver which serves static files from the current folder as:
python -mSimpleHTTPServer
This will start a local webserver serving the files in the current folder at localhost:8000. You can then point your browser to http://localhost:8000/the-dowloaded-file.html to load your webpage which contains this code.
Be sure to change the reference to the file from http://.../flare.json to just flare.json as well.

D3.JS - how do I add gridlines to my pie chart

I have extended the pie-chart example at:
with pies that vary in radius depending on a percentage. I would like to add gridlines (circles) every 20 percent, but I can't figure out how.
here is the updated csv:
age,population,percent
<5,2704659,67
5-13,4499890,38
14-17,2159981,91
18-24,3853788,49
25-44,14106543,71
45-64,8819342,88
=65,612463,64
and here is the updated code with pie-parts of different radius:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
background: #333;
}
.arc path {
stroke: #fff;
stroke-width: 2px;
}
.arc grid {
stroke: #fff;
stroke-width: 1;
stroke-dasharray: 5,5;
}
.arc text {
fill:#fff;
font-size:12px;
font-weight:bold;
}
.arc line {
stroke: #fff;
}
</style>
<body>
<script src="d3.js"></script>
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2 - 10;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(function(d) { return 50 + (radius - 50) * d.data.percent / 100; })
.innerRadius(20);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
var grid = d3.svg.area.radial()
.radius(150);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.population = +d.population;
d.percent = d.percent;
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.data.age; });
});
</script>
First set the number of ticks:
var numTicks = 5; // Each tick is 20%
Then create the data to create the gridlines:
var sdat = [];
for (i=0; i<=numTicks; i++) {
sdat[i] = (radius/numTicks) * i;
}
And then you can use a function to create the radial gridlines, and you can call it from within the d3.csv block:
addCircleAxes = function() {
var circleAxes, i;
svg.selectAll('.circle-ticks').remove();
circleAxes = svg.selectAll('.circle-ticks')
.data(sdat)
.enter().append('svg:g')
.attr("class", "circle-ticks");
// radial tick lines
circleAxes.append("svg:circle")
.attr("r", String)
.attr("class", "circle")
.style("stroke", "#CCC")
.style("opacity", 0.5)
.style("fill", "none");
// Labels for each circle
circleAxes.append("svg:text")
.attr("text-anchor", "center")
.attr("dy", function(d) { return d - 5 })
.style("fill", "#fff")
.text(function(d,i) { return i * (100/numTicks) });
};
An example is here: http://bl.ocks.org/3994129
(Borrowed from: http://kreese.net/blog/2012/08/26/d3-js-creating-a-polar-area-diagram-radial-bar-chart/)

Resources