D3 Legend not updating - javascript

hoping you can help point out my mistake here...
I can't get the second row of the legend to update on mouseover of the histogram:
I don't believe it's the selector because you can add an id attribute to both no problem, and the data seems to be coming through ok on a console.log() ...little bit baffled.
http://jsfiddle.net/2sgLjbvu/3/
var data = [
{Supplier:"Supplier A",val: {WIP:"500",Conv:"400"}},
{Supplier:"Supplier B",val: {WIP:"1400",Conv:"400"}},
{Supplier:"Supplier C",val: {WIP:"300",Conv:"800"}},
{Supplier:"Supplier D",val: {WIP:"1000",Conv:"200"}}
];
dashboard("#chartArea",data);
function dashboard(id,fData){
var barColor='steelblue';
function segColor(c){return {WIP:"#807dba",Conv:"#41ab5d"}[c];}
//compute total for each supplier
fData.forEach(function (d){d.total = parseFloat(d.val.WIP) + parseFloat(d.val.Conv);});
//func to handle histogram
function histoGram(fD){
//Dimensions
var hG={}, hGDim = {t:60,r:0,b:30,l:0};
hGDim.w = 500 - hGDim.l - hGDim.r,
hGDim.h = 300 - hGDim.t - hGDim.b;
//create svg for histogram.
var hGsvg = d3.select(id).append("svg")
.attr("width",hGDim.w +hGDim.l + hGDim.r)
.attr("height",hGDim.h + hGDim.t + hGDim.b)
.append("g")
.attr("transform","translate(" + hGDim.l + "," + hGDim.t + ")");
//create function for x-axis mapping
var x = d3.scale.ordinal().rangeRoundBands([0,hGDim.w],0.1)
.domain(fD.map(function(d){return d[0];}));
//Add x-axis to histogram
hGsvg.append("g")
.attr("class","x axis")
.attr("transform","translate(0," + hGDim.h + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
//create function for y-axis mapping
var y = d3.scale.linear().range([hGDim.h,0])
.domain([0,d3.max(fD,function(d){
return d[1];
})]);
//create bars for the histogram to contain recs and val labels
var bars = hGsvg.selectAll(".bar")
.data(fD)
.enter()
.append("g")
.attr("class","bar");
//create the recs
bars.append("rect")
.attr("x",function(d){return x(d[0]);})
.attr("y",function(d){return y(d[1]);})
.attr("width",x.rangeBand())
.attr("height",function(d){return hGDim.h - y(d[1]);})
.attr("fill",barColor)
.on("mouseover",mouseover) //defined below
.on("mouseout",mouseout); //defined below
function mouseover(d){
//filter for selected supplier
var st = fData.filter(function(s){return s.Supplier==d[0];})[0],
nD = d3.keys(st.val).map(function(s){return {type:s,val:st.val[s]};});
pC.update(nD);
leg.update(nD);
}
function mouseout(d){
//reset the pie-chart and legend
pC.update(tF);
leg.update(tF);
}
//func to update the bars - this will be used by the pie-chart
hG.update = function(nD,color){
//update domain of the y-axis to reflect change in supp
y.domain([0,d3.max(nD,function(d){return d[1];})]);
//attach the new data to the bars
var bars = hGsvg.selectAll(".bar")
.data(nD);
//transition of the height and color of rectangles
bars.select("rect")
.transition()
.duration(500)
.attr("y",function(d){return y(d[1]);})
.attr("height",function(d){return hGDim.h - y(d[1]);})
.attr("fill",color);
//transition the frequency labels loc
bars.select("text")
.transition()
.duration(500)
.text(function(d){ return d3.format(",")(d[1]);})
.attr("y",function(d){return y(d[1])-5;});
};
return hG;
}
function pieChart(pD){
var pC={},pieDim={w:250,h:250};
pieDim.r = Math.min(pieDim.w,pieDim.h)/2;
//create svg for pie chart
var piesvg = d3.select(id).append("svg")
.attr("width",pieDim.w)
.attr("height",pieDim.h)
.append("g")
.attr("transform","translate(" + pieDim.w/2 + "," + pieDim.h/2 + ")");
//create func to draw arcs of the slices
var arc = d3.svg.arc()
.outerRadius(pieDim.r-10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d){return d.val;});
//Draw the pie slices
piesvg.selectAll("path")
.data(pie(pD))
.enter()
.append("path")
.attr("d",arc)
.each(function(d){this._current=d;})
.style("fill",function(d){return segColor(d.data.type);})
.on("mouseover",mouseover)
.on("mouseout",mouseout);
//create func to update pie-chart, this will be used by the histogram
pC.update = function(nD){
piesvg.selectAll("path")
.data(pie(nD))
.transition()
.duration(500)
.attrTween("d",arcTween);
};
//Utility func to be called on mouseover a pie slice
function mouseover(d){
//call the update function of the histogram with new data
hG.update(fData.map(function(v){
return[v.Supplier,v.val[d.data.type]];}),segColor(d.data.type));
}
//Utility func to be called on mouseout of a pie slice
function mouseout(d){
//call the update func of histogram with all data
hG.update(fData.map(function(v){
return[v.Supplier,v.total];}),barColor);
}
//Animate the pie-slice requiring a custom function which specifies
//how the intermeidate paths should be draw
function arcTween(a){
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t){return arc(i(t));};
}
return pC;
}
//func to handle legend
function legend(lD){
leg={};
//create table for legend
var lgend = d3.select(id)
.append("table")
.attr("class","legend");
//create one row per segment
var tr = lgend.append("tbody")
.selectAll("tr")
.data(lD)
.enter()
.append("tr");
//create the first column for each segment
tr.append("td")
.append("svg")
.attr("width","16")
.attr("height","16")
.append("rect")
.attr("width","16")
.attr("height","16")
.attr("fill",function(d){return segColor(d.type);});
//create the second column for each segment
tr.append("td")
.text(function(d){return d.type;});
//create the third col
tr.append("td")
.attr("class","legendFreq")
.text(function(d){return d3.format(",")(d.val);});
//create the perc col
tr.append("tr")
.attr("class","legendPerc")
.text(function(d){return getLegend(d,lD);});
//utility func to be used to update the legend
leg.update = function(nD){
var l = lgend.select("tbody")
.selectAll("tr")
.data(nD);
l.select(".legendFreq")
.text(function(d){return d3.format(",")(d.val);});
l.select(".legendPerc")
.text(function(d){return getLegend(d,nD);});
};
function getLegend(d,aD){//utility func to compute perc
return d3.format("%")(d.val/d3.sum(aD.map(function(v){return v.val;})));
}
return leg;
}
var sF = fData.map(function(d){
return [d.Supplier,d.total];
});
var tF = ['WIP','Conv'].map(function(d){
return {type:d,val:d3.sum(fData.map(function(t){return t.val[d];}))};
});
var hG = histoGram(sF),
pC=pieChart(tF),
leg = legend(tF);
}

Got it...
//create the perc col
tr.append("tr")
.attr("class","legendPerc")
.text(function(d){return getLegend(d,lD);});
should have been...
//create the perc col
tr.append("td")
.attr("class","legendPerc")
.text(function(d){return getLegend(d,lD);});

Related

showing data in tool tip of a PieChart

I'm accessing a GITHUB raw file and using the d3.pie() function making the start and end angles of the pie, at that point the data is showing on console but when I access it in tooltip it gives UNDEFINED.
Do run the code if you can, the link to my github is given where I'm loading my file d3.csv() also FUNCTION TEST is running only once I need to run it till my data runs out.
//CALCULATING RADIUS OF CHART
var radius = Math.min(width, height) / 2 - margin
//APPENDING SVG IN DIV HAVING ID pieChart
var svg = d3.select("#pieChart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// DATA
d3.csv
("https://raw.githubusercontent.com/Dehya/django/master/pkpopulation.csv?
token=AHXLL23PHQSJGYIYCLA6YX25I7IJA",function(error, data){
// GETTING VALUES AS POPULATION FROM DATA AND CALCULATING THE START AND
END
ANGLE:
var pie = d3.pie()
.value(function(d) {return d.population; })
console.log(pie(data));
//SETTING COLOR SCALE
var color = d3.scaleOrdinal()
.domain(data)
.range(["red", "yellow", "green", "blue", "orange"])
function Test(d){
for( i ; i<data.length ; i++)
{
console.log(data[i].name + " : " + data[i].population);
return data[i].name + " : " + data[i].population;
}
}
//MAKING TOOPTIP
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(Test(data));
svg.call(tip);
//MAKING SLICES OF PIE CHART
svg
.selectAll("mySlices")
.data(pie(data))
.enter()
.append("path")
.attr('d',d3.arc()
.innerRadius(0)
.outerRadius(radius)
)
.attr("fill", function(d){ return color(d.data.key) })
.attr("stroke","black")
.style("stroke-width","1px")
.style("opacity",0.7)
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
});

D3 Charts Aligning the Titles and chart positions

I'm using D3 to draw a pie chart in my applicatio. I have created a pie chart with some sample data. But this chart is having alignment issues and adding a title didn't woked as expected,I added x, y attributes to place the chart but it didn't worked. I think I'm adding those to incorrect places.Can someone point out what's wrong here. Following is a sample code. My exact requirement is adding a title to the chart and getting the chart to center.
https://jsfiddle.net/yasirunilan/r8hkpx49/7/
var w = 400;
var h = 400;
var r = h/2;
var color = d3.scale.category20c();
var data = [{"label":"Category A", "value":20},
{"label":"Category B", "value":50},
{"label":"Category C", "value":30}];
var vis = d3.select('#container').append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")");
var pie = d3.layout.pie().value(function(d){return d.value;});
// declare an arc generator function
var arc = d3.svg.arc().outerRadius(r);
// select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice");
arcs.append("svg:path")
.attr("fill", function(d, i){
return color(i);
})
.attr("d", function (d) {
// log the result of the arc generator to show how cool it is :)
console.log(arc(d));
return arc(d);
});
// add the text
arcs.append("svg:text").attr("transform", function(d){
d.innerRadius = 0;
d.outerRadius = r;
return "translate(" + arc.centroid(d) + ")";}).attr("text-anchor", "middle").text( function(d, i) {
return data[i].label;}
);

D3JS graph donuts not showing some wedges when 2 donuts plotted

We are displaying donut pie chart using d3js in asp.net. We are using d3.json for passing json data to display wheel level1. Wheel level1 is display as per the data. We are using another d3.json for passing json data to display wheel level2. But starting wedges of wheel level2 are not display in pie chart.
I observed that if I plot the DoNut of Level1 and Level2 independently it shows all wedges of both Level 1, Level2 respectively.
When I changed the inner , out radius of Level1 and Level2 and displayed Level2 donut outside wiht Level1 donut inside, getting same problem of some wedges not displayed.
The data of angles is stored in MySQL database, using the same the graph is plotted. I checked the sum of angles of all wedges for the Level 2 is 360.
here is the graph
Sample code that is being used to plot Level1 DoNut
d3.json("http://localhost:50025/SportsWheelServices.asmx/WheelLevel1", function (error, data) {
data.forEach(function (d) {
d.SectionId = d.SectionId;
d.SectionLevel1 = d.SectionLevel1;
d.GroupName = d.GroupName;
d.SectionUpColor = d.SectionUpColor;
d.Rotation = d.Rotation;
});
var label = d3.arc()
.outerRadius(radius - 20)
.innerRadius(400);
var pie = d3.pie()
.sort(null)
.value(function (d) { return d.SectionLevel1; });
var arc = d3.arc()
.outerRadius(radius - 20)
.innerRadius(400);
var arcs = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.attr("fill", function (d, i) { return colors(data[i].SectionUpColor); });
arcs.append("text")
.attr("transform", function (d) {
var rotation = d.endAngle < Math.PI ? (d.startAngle / 2 + d.endAngle / 2) * 180 / Math.PI : (d.startAngle / 2 + d.endAngle / 2 + Math.PI) * 180 / Math.PI;
return "translate(" + label.centroid(d) + ") rotate("+ d.data.Rotation+") rotate(" + rotation + ")";
})
.attr("dy", "0.35em")
.text(function (d) { return d.data.GroupName; });
});
Code for Level2 DoNut
d3.json("http://localhost:50025/SportsWheelServices.asmx/WheelLevel2", function (error, data) {
data.forEach(function(d)
{
d.SectionId = d.SectionId;
d.SectionLevel2 = d.SectionLevel2;
});
var label = d3.arc()
.outerRadius(radius - 20)
.innerRadius(300);
var pie = d3.pie()
.sort(null)
.value(function (d) { return d.SectionLevel2; });
var arc = d3.arc()
.outerRadius(radius - 20)
.innerRadius(300);
var arcs = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.attr("fill", function (d, i) { return colors(i); });
});
instead of var arcs = g.selectAll(".arc") I added the following code var arcs = g.selectAll(".arc" + index) this solved my problem

Adding clock points to d3 pie chart

I'm very new to D3 - in fact I only started yesterday - have a donut pie chart here:
var dataset = new Array();
dataset[0] = {"value":"50","color":"red"};
dataset[1] = {"value":"20","color":"blue"};
var pie = d3.layout.pie().sort(null).value(function(d){return d.value;});
var h = w = 500;
var center = w / 2;
var outerRadius = ((h/2)-5);
var innerRadius = outerRadius-10;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var arcOutter = d3.svg.arc()
.innerRadius(outerRadius)
.outerRadius(outerRadius + 1);
var arcInner = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(innerRadius - 1);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Set up outter arc groups
var outterArcs = svg.selectAll("g.outter-arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "outter-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Set up outter arc groups
var innerArcs = svg.selectAll("g.inner-arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "inner-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function (d, i)
{
return d.data.color;
}).attr("d", arc);
//Draw outter arc paths
outterArcs.append("path")
.attr("fill", 'green')
.attr("d", arcOutter).style('stroke', 'white')
.style('stroke-width', 0);
//Draw inner arc paths
innerArcs.append("path")
.attr("fill", 'green')
.attr("d", arcInner).style('stroke', 'white')
.style('stroke-width', 0);
jsFiddle chart
But I'm struggling to add 4 clock points and their time tables to it, (12am, 3pm, 6pm, 9pm), I've tried searching clock examples but they're all working clocks, not just the points.
I want it to look pretty much like this:
Any help would be greatly appreciated.
I don't know how aestheticaly correct it is, but here it goes. What you could do, is add 4 line segments in your chart at these locations:
[w/2, 0],[w/2,h],[0,h/2],[w,h/2]
You can achieve that if you add the following lines:
var x=d3.scale.linear().domain([0,outerRadius]).range([0,w])
var y=d3.scale.linear().domain([0,outerRadius]).range([h,0])
svg.append('line').attr("x1",x(outerRadius/2)).attr("y1",0).attr("x2",x(outerRadius/2)).attr("y2",20)
svg.append('line').attr("x1",x(outerRadius/2)).attr("y1",y(outerRadius)).attr("x2",x(outerRadius/2)).attr("y2",y(outerRadius)-20)
svg.append('line').attr("x1",0).attr("y1",y(outerRadius/2)).attr("x2",20).attr("y2",y(outerRadius/2))
svg.append('line').attr("x1",x(outerRadius)).attr("y1",y(outerRadius/2)).attr("x2",x(outerRadius)-20).attr("y2",y(outerRadius/2))
Please note that you have to create a css entry, so that the line is shown:
line{
display:block;
stroke:black;
}
JSFiddle here
Hope this helps
Following the lovely example here.
var radians = 0.0174532925;
var hourScale = d3.scale.linear()
.range([0,330])
.domain([0,11]);
var labelGroup = svg.append('g')
.attr('transform','translate(' + (center + margin) + ',' + (center + margin) + ')');
labelGroup.selectAll('.hour-label')
.data([12,3,6,9])
.enter()
.append('text')
.attr('class', 'hour-label')
.attr('text-anchor','middle')
.style('font-size','16pt')
.attr('x',function(d){
return outerRadius * Math.sin(hourScale(d)*radians);
})
.attr('y',function(d){
return -outerRadius * Math.cos(hourScale(d)*radians);
})
.text(function(d){
return d;
});
Updated fiddle.

arc.centroid returning (NaN, NaN) in D3

Fair warning: I'm a D3 rookie here. I'm building a donut chart using D3 and all is well so far, except that the labels on the slices aren't aligning with the slices. Using the code below, the labels for each slice are rendered in the middle of the chart, stacked on top of each other so they're unreadable. I've dropped the arc.centroid in my transform attribute, but it's returning "NaN,NaN" instead of actual coordinates, and I can't understand where it's reading from that it's not finding a number. My innerRadius and outerRadius are defined in the arc variable. Any help?
(pardon the lack of a jsfiddle but I'm pulling data from a .csv here)
var width = 300,
height = 300,
radius = Math.min(width, height) / 2;
var color = ["#f68b1f", "#39b54a", "#2772b2"];
var pie = d3.layout.pie()
.value(function(d) { return d.taskforce1; })
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 85)
.outerRadius(radius);
var svg = d3.select("#pieplate").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("data.csv", type, function(error, data) {
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 text = svg.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text( function (d) { return d.taskforce1; })
.attr("font-family", "sans-serif")
.attr("font-size", "20px")
.attr("fill", "black");
d3.selectAll("a")
.on("click", switcher);
function switcher() {
var value = this.id;
var j = value + 1;
pie.value(function(d) { return d[value]; }); // change the value function
path = path.data(pie); // compute the new angles
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
textLabels = text.text( function (d) { return d[value]; });
}
});
function type(d) {
d.taskforce1 = +d.taskforce1;
d.taskforce2 = +d.taskforce2;
d.taskforce3 = +d.taskforce3;
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));
};
}
Finally got it. The arc.centroid function expects data with precomputed startAngle and endAngle which is the result of pie(data). So the following helped me:
var text = svg.selectAll("text")
.data(pie(data))
followed by the rest of the calls. Note that you might have to change the way to access the text data that you want to display. You can always check it with
// while adding the text elements
.text(function(d){ console.log(d); return d.data.textAttribute })

Categories