I'm trying to make a pie chart using d3. To do this I am send my data in a JSON format to my view and then I'd like to try and total up three of the parameters and then use these in the pie chart. So far I have managed to get the data to the view but now I need to use a foreach to total up the parameters. I'm only working on one at the moment.
Script:
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.Query; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var data = #Html.Raw(#Model.output);
var QueryTotal = data.forEach(function(d) {
d.Query = +d.Query;
});
console.log(QueryTotal);
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("Query"); });
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function (d) { return "Query"; });
How do I use a for each to total up the values, I've given it an attempt which you can see above. It just returns undefined.
To sum the values, use reduce()
var QueryTotal = data.reduce(function(prev, d) {
return prev + d.Query;
}, 0);
Or, using your existing structure:
var QueryTotal = 0;
data.forEach(function(d) {
QueryTotal += d.Query;
});
The D3 way to do this is to use d3.sum():
var QueryTotal = d3.sum(data, function(d) { return d.Query; });
Related
My code is like this. Can you say what is the error? My color is not showing properly although the section text is showing. the data set is the death rate of the US over time.
function clicked(d,i) {
var dataset = [d.females, d.males];
var pcolor = ["green", "pink"];
var outerRadius = 60;
var innerRadius = 0;
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.pie();
//Easy colors accessible via a 10-step ordinal scale
//var color = d3.scaleOrdinal(d3.schemeCategory10);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arcs")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("d", arc)
.attr("fill", function(d, i) {
console.log(d);
return pcolor(i);
});
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
}
I create a multi ring donut chart following some examples on the web and everything was ok till i try to display text into the ring and got stuck with different errors.
I think at this point i can access data but i when comes to create rings, i got NaN values for my path and text.
Here is my code:
var dataset = {
ringOne: [{"label":"70%", "value":70},
{"label":"10%", "value":10},
{"label":"20%", "value":20}],
ringTwo: [{"label":"70%", "value":70},
{"label":"10%", "value":10},
{"label":"20%", "value":20}],
};
var width = 460,
height = 300,
cwidth = 45,
outerR = 100,
color = d3.scale.ordinal().range(["#07e", "#00aced", "#e32"]);
var svgDonut = d3.select("#donut")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")" );
var arc = d3.svg.arc();
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.value; });
var rings = svgDonut.selectAll("g.slice")
.data(pie([dataset]))
.enter()
.append("g")
.attr("class", "slice");
rings.append("path")
.attr("fill", function(d, i){ return color(i); })
.attr("d", function(d, i, j){ return arc.innerRadius( 80 + cwidth * j )
.outerRadius( outerR * (j) )(d); });
rings.append("text")
.attr("transform", function(d) {
d.innerRadius = 0;
d.outerRadius = outerR;
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d, i) { return dataset.ringOne[i].label; });
The error i get is:
Error: Invalid value for <path> attribute d="M4.898587196589413e-15,-80A80,80 0 1,1 NaN,NaNL0,0Z"
Error: Invalid value for <text> attribute transform="translate(NaN,NaN)"
fiddle here: https://jsfiddle.net/anaketa/8u7gejjc/
Any ideas?
I'm using d3 to try to recreate a pie chart. Whenever I pass my data in (3 values), I get the aforementioned error. I believe I know the problem, the problem is that the 3 values are not mapped to anything. For example, when I tried this previously I mapped the values to SupplierID's and therefore it split into multiple different segments which was correct. However the values were wrong. I have now remedied the values, however they now are not mapped to anything and therefore will not display. Is there a way to get around this?
For example could I manually assign them an ID to map to? Or is there another way to get around this?
D3:
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.QueryTotal; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var data = #Html.Raw(#Model.output);
console.log(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("QueryTotal"); });
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function (d) { return "QueryTotal"; });
</script>
Data:
NormalTotal: 0
QueryTotal: 131058.34
StrongTotal: 0
LINQ:
public TotalValueBySupplierAndClaimTypeModel GetTotalValueBySupplierAndClaimType(int ClientID, int ReviewPeriodID, int StatusCategoryID) {
var rt =
this.GetValueBySupplierAndClaimType(ClientID, ReviewPeriodID, StatusCategoryID);
TotalValueBySupplierAndClaimTypeModel x = new TotalValueBySupplierAndClaimTypeModel() {
NormalTotal = rt.Sum(c=>c.Normal) ?? 0,
QueryTotal = rt.Sum( c => c.Query) ?? 0,
StrongTotal = rt.Sum( c => c.Strong) ?? 0
};
return x;
}
UPDATE:
I need to assign an ID to each one of my values in my LINQ statement. I have the values in my viewModel. However, I'm not sure how to do this. Does anyone else?
I try to modify this example. I would like to create two data arrays and merge them using special mergingAr() function instead of data.csv. But it does not work. There is one-colour chart without any data. I can`t find the problem place in the code. So, here it is:
var width = 250,
height = 250,
radius = 230;
var arr1 = [44, 64]; //age
var arr2 = [14106543, 8819342]; //population
function type(d) {
d[1] = +d[1];
return d;
}
function mergingAr(array1, array2)
{
var i, out = [];
for(i=0;i<array1.length;i++)
{
out.push([array1[i],array2[i]]);
}
return out;
}
var data = mergingAr(arr1, arr2);
var color = d3.scale.ordinal()
.range(["#EB7221", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius - 100)
.innerRadius(radius - 180);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d[1]; });
var svg = d3.select("#pie").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
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[0]); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d[0]; });
var legend = svg.selectAll(".legend")
.data(color.domain())
.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; });
Thanks all for help!
Your data is there, but your color is wrong. Right now, you have this line setting path color:
.style("fill", function(d) { return color(d[0]); });
The problem is that your data is an object, not an array. (It's transformed by the pie function), so you need to reference the data attribute on the object, and then get the zero index of that array, like so:
.style("fill", function(d) { return color(d.data[0]); });
i have donut chart with legend specification. I have 2 values in dataset. But here with this code i'm getting only the first value, "Unresolved".
var dataset = {
Unresolved: [3],
Resolved:[7]
};
var keyValue=[];
for(key in dataset){
keyValue.push(key);
}
var width = 260,
height = 300,
radius = Math.min(width, height) / 2;
var color = ["#9F134C", "#ccc"];
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 90)
.outerRadius(radius - 80);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g");
var path = gs.selectAll("path")
.data(function(d,i) { return pie(d); })
.enter().append("path")
.attr("fill", function(d, i) { console.log("log", keyValue[i]);return color[i]; }) //Here i'm getting only the 1st value "unresolved".
.attr("d", arc);
var legendCircle = d3.select("body").append("svg").selectAll("g").data(keyValue).enter().append("g")
.attr("class","legend")
.attr("width", radius)
.attr("height", radius * 2)
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legendCircle.append("rect")
.attr("width", 18)
.attr("height", 10)
.style("fill", function(d, i) { return color[i];});
legendCircle.append("text")
.attr("x", 24)
.attr("y", 5)
.attr("dy", ".35em")
.text(function(d) { return d; });
The output i'm getting is,
Can anyone help on this? Thanks.
It looks like you're doing a nested selection in your code, which you would usually only need for nested data. Your data is not nested however -- there's a single level with 2 values. What's happening is that, by using a nested selection, you're descending into the value arrays, each of which contains only a single value.
It works fine if you do away with the nested selection and pass your original data to the pie layout.
var gs = svg.selectAll("g").data(pie(d3.values(dataset))).enter().append("g");
var path = gs.append("path")
.attr("fill", function(d, i) { return color[i]; })
.attr("d", arc);
Complete example here.