I have a large number of legends, but I want to display only 5 legends at a time. I want to have a button that displays the next 5 legends. Can anyone help me in implementing this?
I have implemented the pagination but in the end I am having two repeating legends.
My working code is here js fiddle.
var data=[
{
"age":"<5",
"population":2704659
},
{
"age":"5-10",
"population":4499890
},
{
"age":"10-13",
"population":6736433
},
{
"age":"14-16",
"population":2159981
},
{
"age":"16-18",
"population":3853788
},
{
"age":"18-22",
"population":8848383
},
{
"age":"22-30",
"population":8384390
},
{
"age":"30-44",
"population":14106543
},
{
"age":"45-64",
"population":8819342
},
{
"age":"≥65",
"population":800000
}
]
var width = 1060,
height = 600,
radius = 175,
color = d3.scale.category10(),
legendNo=4, // number of legends to display at a time
legendCount=0; //To store number of legends
//creating svg element and appending to body
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); //transform it to center of body
//creating start and end angle for each arc
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
//creating the arcs based on pie layout
var arc = d3.svg.arc() //inner arc with color
.outerRadius(radius)
.innerRadius(radius-70);
//calculate the total to display in hole
var total=0;
data.forEach(function(d) {
d.population;
total +=parseInt(d.population);
legendCount++;
});
//creating svg element for center text
var center_group = svg.append("svg:g")
.attr("class", "center_group")
.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")");
//selecting all inner arcs and appending data
var g = svg.selectAll("arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
//giving colour to each inner arc and execute onClick function
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); })
//display text in the inner arcs
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.style("font-size", "14px")
.text(function(d) { return d.data.age; });
count = 0;
var p=0;
var viewdata = data.slice(p,p+legendNo);
var hidedata;
var temp;
//selecting all legend elements
var legend = svg.selectAll(".legend")
.data(viewdata).enter()
.append("g").attr("class", "legend")
//.attr("width", )
.attr("id", function() {
return count++;
})
.attr("transform", function(d, i) {
return "translate("+(-(width/2-30)+ i * 50)+"," + (height/2-50)+ ")";
})
//appending coloured rectangles to legend
svg.selectAll("rect")
.data(viewdata)
.enter().append("rect")
.attr("x", width/2-150)
.attr("y",5)
.attr("dy", "3.00em")
.attr("dx", "1.75em")
.attr("width", 23).attr("height", 23)
.attr("transform", function(d, i) {
return "translate("+(-(width/2-30)+ i * 50)+"," + (height/2-50)+ ")";
})
.style("fill", function(d) {
return color(d.age);
});
var prev=svg.append("svg:text")
.attr("id","prev")
.attr("x", width-1260)
.attr("y",height-385)
.attr("dy", "2.90em")
.attr("dx", "1.75em")
//.attr("stroke", "black")
//.style("fill","white")
// .style("text-anchor", "middle")
.style("font-size", "20px")
//.attr("width", 45).attr("height", 25)
.text("<|")
.on("click",onPrevClick)
var next=svg.append("svg:text")
.attr("id","next")
.attr("x", width-950)
.attr("y",height-385)
.attr("dy", "2.90em")
.attr("dx", "1.75em")
.style("font-size", "20px")
//.attr("stroke", "black")
//.style("fill","white")
//.attr("width", 45).attr("height", 25)
.text("|>")
.on("click",onNextClick)
function onNextClick()
{p+=legendNo;
if(p>=legendCount){
p-=legendNo;
viewdata = data.slice(p,legendCount);
//temp=legendNo-(legendCount-p);
//hidedata =data.slice(p-temp-2,p-2);
}
else{
viewdata = data.slice(p,p+legendNo);
//hidedata =data.slice(0,0);
}
svg.selectAll("rect")
.data(viewdata)
.attr("x", width/2-150)
.attr("y",5)
.attr("dy", "3.00em")
.attr("dx", "1.75em")
.attr("width", 23).attr("height", 23)
.attr("transform", function(d, i) {
return "translate("+(-(width/2-30)+ i * 50)+"," + (height/2-50)+ ")";
})
.style("fill", function(d) {
return color(d.age);
});
legend.select("text").attr("x", width/2-150)
.data(viewdata)
.attr("y", 15)
.attr("dy", "3.00em")
.attr("dx", "1.75em")
//.attr("transform", function(d, i) {return "rotate("+45*i+","+d.age+",200)";})
.attr("text-anchor", "middle").text(function(d) {
return d.age;
});
}
function onPrevClick(){
p-=legendNo;
if(p<=0){
p=0;
}
viewdata = data.slice(p,p+legendNo);
svg.selectAll("rect")
.data(viewdata)
.attr("x", width/2-150)
.attr("y",5)
.attr("dy", "3.00em")
.attr("dx", "1.75em")
.attr("width", 23).attr("height", 23)
.attr("transform", function(d, i) {
return "translate("+(-(width/2-30)+ i * 50)+"," + (height/2-50)+ ")";
})
.style("fill", function(d) {
return color(d.age);
});
legend.select("text").attr("x", width/2-150)
.data(viewdata)
.attr("y", 15)
.attr("dy", "3.00em")
.attr("dx", "1.75em")
//.attr("transform", function(d, i) {return "rotate("+45*i+","+d.age+",200)";})
.attr("text-anchor", "middle").text(function(d) {
return d.age;
});
}
// giving text to legends
legend.append("text").attr("x", width/2-150)
.data(viewdata)
.attr("y", 15)
.attr("dy", "3.00em")
.attr("dx", "1.75em")
//.attr("transform", function(d, i) {return "rotate("+45*i+","+d.age+",200)";})
.attr("text-anchor", "middle").text(function(d) {
return d.age;
});
//displaying legend title
var legendTitle = svg.append("svg:text")
.attr("x", -(width/2-200))
.attr("y", height/2-25)
.style("font-size", "14px")
.style("text-decoration", "underline")
.text("Age Group");
Related
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>
I have this bubble chart and want to zoom in to be able to see the very small bubbles. I tried this code by Mike Bostock but I have not succeeded getting good zooming functions, I think it because I have another chart concept.
Other examples online apply zoom on charts that have axes but my chart has no axes.
Here is my Code:
d3.json("Data/New/Treemap_source.json", function (error, data) {
if (error) throw error;
var diameter = 693;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var format = function (d){ return "BTC " + d3.format(",.2f")(d); }
var bubble = d3.pack(data)
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select("#bubblediv")
.append("svg")
.attr("width", diameter + margin.left + margin.right)
.attr("height", diameter + margin.top + margin.bottom)
.attr("class", "bubble");
var nodes = d3.hierarchy(data)
.sum(function(d) { return d.VolumeBTC; });
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 + margin.left)+ "," + (d.y + margin.top+20) + ")";
});
node.on("click", function (d) {
alert("This bubble contains: " + d.data.Symbol);
// var sel = d.data.Symbol;
d3.select('#my-select').property('value', d.data.Symbol);
// print_filter(d3.select('#my-select').property('value', d.data.Symbol));
// d3.select('#my-select').property('value', d.data.Symbol);
});
node.append("title")
.text(function(d) {
return d.data.Symbol + ": " + format(d.value);
});
d3.select("svg").append("text")
.attr("transform", "translate(" + (diameter / 2 -20) + " ,30)")
.attr('class','chartlabel')
.style("text-anchor", "middle")
.text("Altcoins Trading in BTC");
node.append("circle")
.attr("r", function(d) {
return d.r;
})
.style('stroke', '#263432')
.style('stroke-width', '1.5')
.style("fill", function(d,i) {
return color(i);
});
node.append("text")
.attr("dy", ".2em")
.style("text-anchor", "middle")
.text(function(d) {
return d.data.Symbol.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 format(d.data.VolumeBTC);
})
.attr("font-family", "Gill Sans", "Gill Sans MT")
.attr("font-size", function(d){
return d.r/6;
})
.attr("fill", "white");
d3.select(self.frameElement)
.style("height", diameter + "px");
});
As of d3 v4, you can zoom on any svg with the following:
function zoomed() {
svg.attr("transform", d3.event.transform);
}
var zoom = d3.zoom().on("zoom", zoomed);
svg.call(zoom);
To get it to work exactly as you want, you'll need to use d3-zoom:
https://github.com/d3/d3-zoom
Lasly, you'll probably want to have a button to reset the zoom, which can be done like this:
d3.select('#zoom-reset-button').on("click", function() {
zoom.transform(svg, d3.zoomIdentity);
});
I am looking to animate this chart.
http://jsfiddle.net/NYEaX/1554/
var invisiblebubble = mask.append("circle")
.data(data);
invisiblebubble
.attr("cx", 550)
.attr("cy", 250)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
I've animated the mask circle - looking to implement other animations/suggestions for the labels. If they tween like a pie chart, tween in an arc, fade in etc..
I did create a transition on the radius of the circle - kind of looked like the warner bros ending.
var invisiblebubble = mask.append("circle")
.data(data);
invisiblebubble
.attr("cx", 550)
.attr("cy", 250)
.transition()
.duration(2000)
.attr("r", 10)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
How do I animate other features like the labels/pointers
I've managed to improve the inverse bubble chart with this code.
Where I have to set a fixed size for the circle first, mask it, then animate it - for the purpose of the labels.
function maskMaker(el){
var backcolor = $(el).data("color");
var backopacity = $(el).data("opacity");
var height = $(el).data("height");
var width = $(el).data("width");
var labelName = $(el).data("label-name");
var bubbleValue = $(el).data("bubble-value");
var displaceLeft = $(el).data("displace-left");
var displaceTop = $(el).data("displace-top");
var data = [{
"label": labelName,
"x": displaceLeft,
"y": displaceTop,
"value": bubbleValue
}];
console.log("MASK data", data);
// Set the main elements for the series chart
var svgroot = d3.select($(el)[0]).append("svg");
// filters go in defs element
var defs = svgroot.append("defs");
var mask = defs.append("mask")
.attr("id", "myMask");
mask.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.style("fill", "white")
.style("opacity", backopacity);
var invisiblebubble = mask.append("circle")
.data(data);
//create a fixed bubble first
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", function(d) {
return d.value-20;
});
//now mask the fixed circle
var masker = defs.append(function() {
return mask.node().cloneNode(true)
})
.attr("id", "myMaskForPointer")
.select("rect")
.style("opacity", 0.8);
//animate this circle
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", 10)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
//apply the rest of the chart elements
var svg = svgroot
.attr("class", "series")
.attr("width", "1120px")
.attr("height", "500px")
.append("g")
.attr("transform", "translate(0,0)")
var rect = svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.attr("mask", "url(#myMask)")
.style("fill", backcolor);
/*
//__labels
var centrallabel = svgroot.append("g")
.attr("class", "centrallabel")
.data(data);
centrallabel
.append("text")
.attr("text-anchor", "middle")
.attr("x", 550)
.attr("y", 250 + 10)
.text(function(d) {
return "200";
})
*/
function addLabel(){
//__labels
var labels = svgroot.append("g")
.attr("class", "labels")
//__ enter
var labels = labels.selectAll("text")
.data(data);
labels.enter()
.append("text")
.attr("text-anchor", "middle")
//__ update
//labels
.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y-10;
})
.text(function(d) {
return d.label;
})
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
d.cx = 550;
d.cy = 250;
})
.transition()
.duration(300)
labels
.transition()
.duration(300)
//__ exit
labels.exit().remove();
//__labels
}
function addPointer(){
//__pointers
var pointers = svgroot.append("g")
.attr("class", "pointers");
var dots = defs.append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3);
var pointers = pointers.selectAll("path.pointer")
.data(data);
//__ enter
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.attr("marker-end", "url(#circ)")
.attr("mask", "url(#myMaskForPointer)")
//__ update
//pointers
.attr("d", function(d) {
if (d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
})
.transition()
.duration(300)
pointers
.transition()
.duration(300)
//__ exit
pointers.exit().remove();
//__pointers
}
//delay for the mask
setTimeout(function(){
addLabel();
addPointer();
}, 1000);
}
Fade in could be implementing like :
centrallabel
.append("text")
.attr("text-anchor", "middle")
.attr("x", 550)
.style("opacity",0)
.attr("y", 250 + 10)
.text(function(d) {
return "200";
})
.transition()
.duration(2000)
.style("opacity", 1)
As far as other animations you could start the pointer line off screen then transition it to it's endpoint. Or start with its length at 0 and transition it to full size. Transform/Translate would probably be useful - see (https://bl.ocks.org/mbostock/1345853)
So I have created a D3 Stacked Bar Chart, but I can't seem to figure out how to make the values of the bars show up on the chart. I can display Text "Sample" to each bar, but I can't figure out how to retrieve the data. I tried using this... .text(function(d) {return d.total; }) but with no luck.
jfiddle here.... http://jsfiddle.net/rasweat/D3ErQ/1/
<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript">
var margin = {top: 60, right: 20, bottom: 100, left: 100},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width-100], .1); //width-100 to make room for the legend.
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
//.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
.range(["#1f77b4", "#ff7f0e","d62728"]); //blue, orange, red
//color code for Progress Report
//.range(["#00FFFF","#00FF00","#990099","#FF0000","#FFFF00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("#area_progress_report").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 + ")");
// Get the data
//var data = [{"Commodity":"Base","num_complete_print":"3","num_incomplete_print":15},{"Commodity":"Blade","num_complete_print":"1","num_incomplete_print":53},{"Commodity":"DTE","num_complete_print":"1","num_incomplete_print":17},{"Commodity":"HUB","num_complete_print":"0","num_incomplete_print":"18"},{"Commodity":"MH","num_complete_print":"0","num_incomplete_print":"18"},{"Commodity":"Mid","num_complete_print":"0","num_incomplete_print":18},{"Commodity":"Top","num_complete_print":"0","num_incomplete_print":18}];
var data = <?php echo json_encode($dataset_progress001); ?>;
//alert(data);
//d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Commodity"; }));
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
//use this to sort the bars from largest to smallest
//data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.Commodity; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text") //added this line through rotate to change orientation of x axis
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-1em")
.attr("transform", function(d) {
return "rotate(-90)"
});
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end");
// .text("Population");
//grid lines y.ticks controls the number of lines
svg.selectAll("line.horizontalGrid").data(y.ticks(10)).enter()
.append("line")
.attr(
{
"class":"horizontalGrid",
"x1" : 0,
"x2" : width-60,
"y1" : function(d){ return y(d);},
"y2" : function(d){ return y(d);},
"fill" : "none",
"shape-rendering" : "crispEdges",
"stroke" : "grey",
"stroke-width" : "1px"
});
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.Commodity) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
//Added y label 10/28
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", -60)
.attr("x",-70)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Number Of Components");
//Add Title
svg.append("text")
.attr("x", (width/2) )//(width / 2))
.attr("y", -20) //0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("text-decoration", "underline")
.text("Inspection Progress Report");
state.selectAll("text")
.data(function(d) { return d.ages; })
.enter()
.append("text")
.attr("x", x.rangeBand()/2)
.attr("y", function(d, i) { return y(d.y1) + (y(d.y0) - y(d.y1))/2; })
.style("text-anchor", "middle")
//.text(function(d) {return d.total; })
.text("sample")
</script>
You have to change this line
.data(function(d) { return d.ages; })
to actually give data() your data. If you have an array with all the ages named ages, then it would be:
.data(ages)
The d argument in function(d) references nothing since data() is actually the method where you input your data.
I am unable to add a segment to a D3.js pie chart. I know I need to use .enter() and .append() to stage the new data -- but I am not sure how to apply that when I have the arcs grouped (which I need for the labels).
Here is my update function:
var updateChart = function(dataset) {
arcs.data(donut(dataset));
arcs.transition()
.duration(duration)
.attrTween("d", arcTween);
sliceLabel.data(donut(dataset));
sliceLabel.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (arc.centroid(d)) + ")"; })
.style("fill-opacity", function(d) {
if (d.value === 0) { return 1e-6; }
else { return 1; }
});
};
How I setup the initial graph:
var arc = d3.svg.arc()
.innerRadius(radius * .4)
.outerRadius(radius);
var svg = d3.select("body")
.append("svg")
.append("svg")
.attr("width", width)
.attr("height", height);
var arc_grp = svg.append("g")
.attr("class", "arcGrp")
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
var label_group = svg.append("g")
.attr("class", "lblGroup")
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
var arcs = arc_grp.selectAll("path")
.data(donut(data));
arcs.enter()
.append("path")
.attr("stroke", "white")
.attr("stroke-width", 0.8)
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) { return this.current = d; });
var sliceLabel = label_group.selectAll("text")
.data(donut(data));
sliceLabel.enter()
.append("text")
.attr("class", "arcLabel")
.attr("transform", function(d) { return "translate(" + (arc.centroid(d)) + ")"; })
.attr("text-anchor", "middle")
.style("fill-opacity", function(d) {
if (d.value === 0) { return 1e-6; }
else { return 1; }
})
.text(function(d) { return d.data.label; });
Complete jsfiddle: http://jsfiddle.net/kPM5L/
What is a clean way to add the new data to the chart?
To get the transition to work smoothly, you need to add the code that you're using initially to your update function as well. Working jsfiddle here.
And some code to make SO happy -- this is what needs to be in the update function as well:
.enter()
.append("path")
.attr("stroke", "white")
.attr("stroke-width", 0.8)
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) { return this.current = d; });
.enter()
.append("text")
.attr("class", "arcLabel")
.attr("transform", function(d) { return "translate(" + (arc.centroid(d)) + ")"; })
.attr("text-anchor", "middle")
.style("fill-opacity", function(d) {
if (d.value === 0) { return 1e-6; }
else { return 1; }
})
.text(function(d) { return d.data.label; });