Javascript summing arrays with using d3.nest() - javascript

I would like to create a pie chart by grouping "age" and summing population. How could I do that?
Data.csv
age,population
<5,2704659
5-13,4499890
5-13,4
14-17,2159981
18-24,3853788
18-24,385
25-44,14106543
45-64,8819342
45-64,8142000
5-13,4499000
=65,612463
... should be so:
age,population
<5,2704659
5-13,8998894
14-17,2159981
18-24,3854173
25-44,14106543
45-64,16961342
=65,612463
index.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.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("data.csv", function(error, data) {
var data = d3.nest()
.key(function (d) { return d.age; })
.sortKeys(d3.ascending)
.rollup(function (d) {
return d3.sum(d, function (g) { return g.population; });
}).entries(data);
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>
Can you see a way to modify this function so that it returns the desired result?

The summing you are doing is correct, there is no problem with nesting.
The problem is with the values you are setting
Your code:
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
Should have been
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.values;
});
Similarly in the rendering part for the path and text
g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.key);///Not 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.key;///Not d.data.age as returned by data(pie(data))
});
Full working code here
Hope this helps!

Related

How to force the gravity of bubbles in D3.js

In the code below, I need to make the bubbles with the highest values ​​float to the left of the screen, but I have no deep knowledge of D3.js and I can't find a way to do this.
My code
<script type="text/javascript">
dataset = {
"children": [{"Name":"Olives","Count":10},
{"Name":"Tea","Count":8},
{"Name":"Mashed Potatoes","Count":6},
{"Name":"Boiled Potatoes","Count":5},
{"Name":"Milk","Count":4},
{"Name":"Chicken Salad","Count":4},
{"Name":"Vanilla Ice Cream","Count":2},
{"Name":"Cocoa","Count":7}];
var diameter = 600;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var bubble = d3.pack(dataset)
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select("body")
.append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
var nodes = d3.hierarchy(dataset)
.sum(function(d) { return d.Count; });
var node = svg.selectAll(".node")
.data(bubble(nodes).descendants())
.enter()
.filter(function(d){
return !d.children
})
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title")
.text(function(d) {
return d.Name + ": " + d.Count;
});
node.append("circle")
.attr("r", function(d) {
return d.r;
})
.style("fill", function(d,i) {
return color(i);
});
node.append("text")
.attr("dy", ".2em")
.style("text-anchor", "middle")
.text(function(d) {
return d.data.Name.substring(0, d.r / 3);
})
.attr("font-family", "sans-serif")
.attr("font-size", function(d){
return d.r/5;
})
.attr("fill", "white");
node.append("text")
.attr("dy", "1.3em")
.style("text-anchor", "middle")
.text(function(d) {
return d.data.Count;
})
.attr("font-family", "Gill Sans", "Gill Sans MT")
.attr("font-size", function(d){
return d.r/5;
})
.attr("fill", "white");
d3.select(self.frameElement)
.style("height", diameter + "px");
</script>
Edit in JS Fiddle
The code produces this result
I need the bubbles with the highest values ​​to be on the left, as in the image below.
What property or function of D3.js can I use to control the severity of the bubbles as I need them?
Thanks!
There's not a function specifically in d3.pack for this. d3.force allows you specify x and y positions based on the data's value, and could achieve the result you are looking for.
The force simulation has an .x and .y function that is based on the data's count, and then to avoid overlaps, the .collide function adjusts the circles positions based on their radius (plus a small paddding of 3px).
var simulation = d3.forceSimulation(nodes)
.force("forceX", d3.forceX().strength(.051).x(d => xScale(d.Count)))
.force("forceY", d3.forceY().strength(.051).y(d => yScale(d.Count)))
.force('collision', d3.forceCollide().radius(d => rScale(d.Count) + 3))
dataset = {
"children": [{"Name":"Olives","Count":10},
{"Name":"Tea","Count":8},
{"Name":"Mashed Potatoes","Count":6},
{"Name":"Boiled Potatoes","Count":5},
{"Name":"Milk","Count":4},
{"Name":"Chicken Salad","Count":4},
{"Name":"Vanilla Ice Cream","Count":2},
{"Name":"Cocoa","Count":7}]
}
let nodes = dataset.children
var width = 600;
var height = 600;
var margin = 50
var color = d3.scaleOrdinal(d3.schemeCategory20);
let extentCount = d3.extent(nodes, d => d.Count)
let maxRadius = 100
let yScale = d3.scaleLinear()
.domain(extentCount)
.range([height - maxRadius, maxRadius])
let xScale = d3.scaleLinear()
.domain(extentCount)
.range([(width - maxRadius), maxRadius])
let rScale = d3.scaleSqrt()
.domain(extentCount)
.range([5, maxRadius])
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin + margin)
.attr("height", height + margin + margin)
.attr("class", "bubble");
var g = svg.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")")
var simulation = d3.forceSimulation(nodes)
.force("forceX", d3.forceX().strength(.051).x(d => xScale(d.Count)))
.force("forceY", d3.forceY().strength(.051).y(d => yScale(d.Count)))
.force('collision', d3.forceCollide().radius(d => rScale(d.Count) + 3))
.on("tick", function(d){
node
.attr("cx", function(d){ return d.x; })
.attr("cy", function(d){ return d.y; })
})
.stop()
for (var i = 0; i < 120; i++) {
simulation.tick()
}
var node = g.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title")
.text(function(d) {
return d.Name + ": " + d.Count;
});
node.append("circle")
.attr("r", d => rScale(d.Count))
.style("fill", function(d,i) {
return color(i);
});
node.append("text")
.attr("dy", ".2em")
.style("text-anchor", "middle")
.text(function(d) {
return d.Name.substring(0, rScale(d.Count) / 3);
})
.attr("font-family", "sans-serif")
.attr("font-size", function(d){
return rScale(d.Count)/5;
})
.attr("fill", "white");
node.append("text")
.attr("dy", "1.3em")
.style("text-anchor", "middle")
.text(function(d) {
return d.Count;
})
.attr("font-family", "Gill Sans", "Gill Sans MT")
.attr("font-size", function(d){
return d.r/5;
})
.attr("fill", "white");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

Unable to append path to svg

I am trying to add a regression line to a scatter plot. I am using the below code as an example for scatter plot.
http://bl.ocks.org/majetisiri/57da501b3182bd08d17402261c7187f7
I am appending the path to svg as explained here:
Plot regression line on a scatter plot from regression coefficients
But the regression line is not visible.
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<!-- Example based on http://bl.ocks.org/mbostock/3887118 -->
<!-- Tooltip example from http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html -->
<style>
body {
font: 11px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
}
.tooltip {
position: absolute;
width: 200px;
height: 28px;
pointer-events: none;
}
h1 {
text-align: center;
}
h2 {
text-align: left;
}
</style>
<body>
<p><span><label for="y-axis">Select y-axis</label></span>
<select id="y-value">
<option value="FLFPR">Female LFPR</option>
<option value="lnGDP">Log GDP per capita</option>
<option value="Fertility">Fertility rate</option>
</select>
<p><span><label for="x-axis">Select x-axis</label></span>
<select id="x-value">
<option value="FLFPR">Female LFPR</option>
<option value="lnGDP">Log GDP per capita</option>
<option value="Fertility">Fertility rate</option>
</select>
<button onclick="setGraph()">submit</button>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://unpkg.com/d3-regression#1.2.3/dist/d3-regression.min.js"></script>
<script>
function drawGraph(xText, yText) {
$('svg').remove();
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
/*
* value accessor - returns the value to encode for a given data object.
* scale - maps value to a visual display encoding, such as a pixel position.
* map function - maps from data value to display value
* axis - sets up axis
*/
// setup x
var xValue = function(d) { return d[xText];}, // data -> value
xScale = d3.scale.linear().range([0, width]), // value -> display
xMap = function(d) { return xScale(xValue(d));}, // data -> display
xAxis = d3.svg.axis().scale(xScale).orient("bottom");
// setup y
var yValue = function(d) { return d[yText];}, // data -> value
yScale = d3.scale.linear().range([height, 0]), // value -> display
yMap = function(d) { return yScale(yValue(d));}, // data -> display
yAxis = d3.svg.axis().scale(yScale).orient("left");
// setup fill color
var cValue = function(d) { return d.IG;},
color = d3.scale.category20();
// add the graph canvas to the body of the webpage
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 + ")");
// add the tooltip area to the webpage
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// load data
d3.csv("scatter2.csv", function(error, data) {
// change string (from CSV) into number format
data.forEach(function(d) {
d[yText] = +d[yText];
d[xText] = +d[xText];
//console.log (d.School);
//console.dir (d);
});
// don't want dots overlapping axis, so add in buffer to data domain
xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]);
yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]);
// x-axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text(xText);
// y-axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yText);
// draw dots
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 6.6)
.attr("opacity", 0.9)
.style("stroke", function(d) { return color(cValue(d));})
.attr("cx", xMap)
.attr("cy", yMap)
.style("fill", function(d) { return color(cValue(d));})
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d["Player"] + "<br/> " + d.School + "<br/>(" + xValue(d)
+ ", " + yValue(d) + ")")
.style("left", (d3.event.pageX + 10) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
// draw legend
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(10," + (i+7) * 20 + ")"; });
// draw legend colored rectangles
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
// draw legend text
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d;})
// get regression coefficients
regData = data.map(item => ({x: item[xText], y: item[yText]}));
res = drawRegressionLine(regData)
console.log("regression results")
console.log(res)
var line = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
// var line = d3.svg.line()
// .x(function(d) { return xScale(d['x']); })
// .y(function(d) { return yScale(d['y']); });
// var lineFunction = d3.svg.line()
// .x(function(d) { return d.x; })
// .y(function(d) { return d.y; })
// .interpolate("linear");
var regLine = svg.append("path")
.datum(res)
.attr("d", line)
.style("stroke", "steelblue")
.style("stroke-width", "6px");
// var lineGraph = svg.append("path")
// .attr("d", line(res))
// .attr("stroke", "blue")
// .attr("stroke-width", 2)
// .attr("fill", "black");
});
}
// draw regression line
function drawRegressionLine(regData) {
console.log("beginning")
console.log("inside draw regression lilne")
linearRegression = d3.regressionLinear()
.x(d => d.x)
.y(d => d.y);
res = linearRegression(regData)
return res;
}
// drawGraph('Passing TD', 'Rushing TD');
function setGraph() {
console.log("inside set graph")
console.log($('#x-value').val())
drawGraph($('#x-value').val(), $('#y-value').val());
}
</script>
</body>
</html>
Please help me find what is wrong with the code.
It looks like you are not passing the your linear regression into your x and y scale.
Try:
var line = d3.svg.line()
.x(function(d) { return xScale(d[0]); })
.y(function(d) { return yScale(d[1]); })
.interpolate("linear");

Updating pie chart with labels (d3)

I'm just trying to append the labels of mbostocks pie chart example, but for some reason I can't get it to work.
I'm essentially just trying to combine two of his examples (pie update, pie labels), so I'm trying to implement this code;
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.apples); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.data.apples; });
});
into this variable in his pie chart update example;
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
here is the plnk of my attempt, hopefully someone can clear up the issue I'm having.
http://plnkr.co/edit/e05kKjB8KWGqRteh8OdS?p=preview
Code for my attempt;
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*/
var g = svg.datum(data).selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc")
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.apples); })
.each(function(d) { this._current = d; }); // store the initial angles
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.data.apples; });
d3.selectAll("input")
.on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"oranges\"]").property("checked", true).each(change);
});
function change() {
var value = this.value;
clearTimeout(timeout);
pie.value(function(d) { return d[value]; }); // change the value function
path = g.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));
};
}
When you moved from a collection of path to a collection of g containing a path and text, you didn't update your transition to operate on the paths. It's attempting to apply the transition on the g. Corrected code:
function change() {
var value = this.value;
pie.value(function(d) { return d[value]; });
g = g.data(pie);
g.select("path") //<-- operate on the paths in the g
.transition()
.duration(750)
.attrTween("d", arcTween);
}
Running code:
var width = 500,
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 + ")");
var data = [{
"apples": 53245,
"oranges": 200
}, {
"apples": 28479,
"oranges": 200
}, {
"apples": 19697,
"oranges": 200
}, {
"apples": 24037,
"oranges": 200
}, {
"apples": 40245,
"oranges": 200
}];
var g = svg.datum(data).selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var path = g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.apples);
})
.each(function(d) {
this._current = d;
}); // store the initial angles
var text = g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.text(function(d) {
return d.data.apples;
});
d3.selectAll("input")
.on("change", change);
function change() {
var value = this.value;
pie.value(function(d) {
return d[value];
}); // change the value function
g = g.data(pie); // compute the new angles
g.select("path")
.transition()
.duration(750)
.attrTween("d", arcTween); // redraw the arcs
g.select("text")
.style("opacity", 0)
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.text(function(d) {
return d.data[value];
})
.transition()
.duration(1000)
.style("opacity", 1);
}
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));
};
}
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script data-require="d3#*" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<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="script.js"></script>
</body>
</html>

Apply D3 tooltip to Donut Multiples

I have code like this that creates multiple D3 donut multiples.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
svg {
padding: 10px 0 0 10px;
}
.arc {
stroke: #fff;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var radius = 74,
padding = 10;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 30);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
data.forEach(function(d) {
d.ages = color.domain().map(function(name) {
return {name: name, population: +d[name]};
});
});
var legend = d3.select("body").append("svg")
.attr("class", "legend")
.attr("width", radius * 2)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d; });
var svg = d3.select("body").selectAll(".pie")
.data(data)
.enter().append("svg")
.attr("class", "pie")
.attr("width", radius * 2)
.attr("height", radius * 2)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
svg.selectAll(".arc")
.data(function(d) { return pie(d.ages); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); });
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.State; });
});
</script>
I am looking for a way to implement the D3 tooltip so that I can see the exact data of each chunk of the donut when I put my cursor over it. I understand that there are other examples of the tooltip on here but none of them have worked with the donut multiples example.
Here is some example data
State,Under 5 Years,5 to 13 Years,14 to 17 Years,18 to 24 Years,25 to 44 Years,45 to 64 Years,65 Years and Over
AL,310504,552339,259034,450818,1231572,1215966,641667
AK,52083,85640,42153,74257,198724,183159,50277
AZ,515910,828669,362642,601943,1804762,1523681,862573
AR,202070,343207,157204,264160,754420,727124,407205
CA,2704659,4499890,2159981,3853788,10604510,8819342,4114496
CO,358280,587154,261701,466194,1464939,1290094,511094
CT,211637,403658,196918,325110,916955,968967,478007
DE,59319,99496,47414,84464,230183,230528,121688
DC,36352,50439,25225,75569,193557,140043,70648
FL,1140516,1938695,925060,1607297,4782119,4746856,3187797
GA,740521,1250460,557860,919876,2846985,2389018,981024
HI,87207,134025,64011,124834,356237,331817,190067
ID,121746,201192,89702,147606,406247,375173,182150
IL,894368,1558919,725973,1311479,3596343,3239173,1575308
IN,443089,780199,361393,605863,1724528,1647881,813839
IA,201321,345409,165883,306398,750505,788485,444554
KS,202529,342134,155822,293114,728166,713663,366706
KY,284601,493536,229927,381394,1179637,1134283,565867
LA,310716,542341,254916,471275,1162463,1128771,540314
ME,71459,133656,69752,112682,331809,397911,199187
MD,371787,651923,316873,543470,1556225,1513754,679565
The D3 doc of this can be found at
http://bl.ocks.org/mbostock/3888852
I'm not sure what you're referring to when you say "the D3 tooltip", because d3 doesn't have any built-in tooltip functionality. That said, there are some good third-party plugins out there for doing tooltips in d3.
d3-tip is one that would work well for what you're trying to do.
You can create a tooltip function to display your population data for each arc like this:
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) { return d.data.population; })
.direction('s');
Then you can call the function on your svg selection:
svg.call(tip);
Finally, you can use mouse event listeners on your arcs to show and hide the tooltip:
svg.selectAll(".arc")
.data(function(d) { return pie(d.ages); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
Here's a PLUNK with a working example.
You can also check up on the d3-tip documentation here.
I too got the same TypeError while debugging my javascript code using d3js while adding tooltip for my barcharts.
bars.append('rect')
.attr('y', maxHeight)
.attr('height', 0)
.attr('width', function (d) { return x.rangeBand(d) - 1; })
.attr('class', 'bar')
.transition().duration(1500)
.attr('y', function (d, i) { return y(d.y); })
.attr('height', function (d, i) { return maxHeight - y(d.y); });
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
In the above code i used ".on('mouseover', tip.show)" on "bars.append()".This is wrong usage.
Later, i found that ".on('mouseover', tip.show)" should be applied on function ".select('rect') or .selectall('rect')".
Now below snippet is working correctly for my application.
bars.append('rect')
.attr('y', maxHeight)
.attr('height', 0)
.attr('width', function (d) { return x.rangeBand(d) - 1; })
.attr('class', 'bar')
.transition().duration(1500)
.attr('y', function (d, i) { return y(d.y); })
.attr('height', function (d, i) { return maxHeight - y(d.y); });
bars.select('rect')
.on('mouseover', tip.show)
.on('mouseout', tip.hide);

How to add tooltips in a D3 donut chart

I would like to add tooltips in a D3 donut chart. How can this be done? I would also like to add the percentages for each of the sections in pie chart.
This is my code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 14px sans-serif;
}
svg {
padding: 10px 0 0 10px;
}
.arc {
stroke: #000;
}
.arc:hover{
stroke: yellow;
}
.pie:hover {
fill: orangered ;
}
</style>
<body>
<div class = "InfoVis"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
var radius = 144,
padding = 20;
var color = d3.scale.ordinal()
.range(["#00ffff", "#00ff00", "#ffbf00", "#fe2ec8", "#bdbdbd", "#3104b4", "#5882fa"]);
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 40);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.nutrifacts; });
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Cereal"; }));
data.forEach(function(d) {
d.nutri = color.domain().map(function(name) {
return {name: name, nutrifacts: +d[name]};
});
});
var legend = d3.select("body").append("svg")
.attr("class", "legend")
.attr("width", radius * 2)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".55em")
.text(function(d) { return d; });
var svg = d3.select("body").selectAll(".pie")
.data(data)
.enter().append("svg")
.attr("class", "pie")
.attr("width", radius * 2)
.attr("height", radius * 2)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
svg.selectAll(".arc")
.data(function(d) { return pie(d.nutri); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); });
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.Cereal; });
});
</script>
Please help me in adding a tooltip to this code and, if possible, add color to the tooltip.
I got idea of your question, but you don't give data.csv file. So I took my own data for drawing donut chart with tooltip. But your are using predefined tooltip, which is given by D3.
var data = [{"age":"1-5","population":2000},
{"age":"6-10","population":1000},
{"age":"11-15","population":3000},
{"age":"16-20","population":1200},
{"age":"21-25","population":900},{"age":"26-30","population":1500},
{"age":"31-35","population":600},{"age":"36-40","population":1200},
{"age":"41-45","population":900}];
var margin = {top:40,left:40,right:40,bottom:40};
width = 650;
height = 650;
radius = Math.min(width-100,height-100)/2;
var color = d3.scale.ordinal()
.range(["#e53517","#6b486b","#ffbb78","#7ab51d","#6b486b",
"#e53517","#7ab51d","#ff7f0e","#ffc400"]);
var arc = d3.svg.arc()
.outerRadius(radius -130)
.innerRadius(radius - 10);
var arcOver = d3.svg.arc()
.outerRadius(radius +50)
.innerRadius(0);
var svg = d3.select("#svgContent").append("svg")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("transform","translate("+width/2+","+height/2+")");
div = d3.select("body")
.append("div")
.attr("class", "tooltip");
var pie = d3.layout.pie()
.sort(null)
.value(function(d){return d.population;});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class","arc")
.on("mousemove",function(d){
var mouseVal = d3.mouse(this);
div.style("display","none");
div
.html("age:"+d.data.age+"</br>"+"population:"+d.data.population)
.style("left", (d3.event.pageX+12) + "px")
.style("top", (d3.event.pageY-10) + "px")
.style("opacity", 1)
.style("display","block");
})
.on("mouseout",function(){div.html(" ").style("display","none");})
.on("click",function(d){
if(d3.select(this).attr("transform") == null){
d3.select(this).attr("transform","translate(42,0)");
}else{
d3.select(this).attr("transform",null);
}
});
g.append("path")
.attr("d",arc)
.style("fill",function(d){return color(d.data.age);});
svg.selectAll("text").data(pie(data)).enter()
.append("text")
.attr("class","label1")
.attr("transform", function(d) {
var dist=radius+15;
var winkel=(d.startAngle+d.endAngle)/2;
var x=dist*Math.sin(winkel)-4;
var y=-dist*Math.cos(winkel)-4;
return "translate(" + x + "," + y + ")";
})
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d){
return d.value;
});
For more clarity, see this link.
This is animated screenshot of this code in action:

Categories

Resources