donut chart using json array - javascript

I am learning d3 and trying to make use d3 library in my application for showing some visualization chart .i am getting data through web api in the form of json here.
My script:
var data= "rows":[
{
"STATUS" : "Active",
"count" : "246"
},
{
"STATUS" : "Not Proceeded With",
"count" : "40"
}
]
var width = 800,
height = 250,
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(radius - 70);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return d.count;
});
var svg = d3.select("#chart").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.rows))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d) {
return color(d.data.rows.STATUS);
});
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.rows.STATUS;
});
Now i want to use that data set for creating the donut chart.i have tried but not getting success.can any one plz suggest me any idea how i can do

Couple problems:
1.) Your JSON isn't valid:
var data = { //<- missing bracket
"rows": [
{
"STATUS": "Active",
"count": "246"
}, {
"STATUS": "Not Proceeded With",
"count": "40"
}
]
} //<- missing bracket
2.) You are not accessing the STATUS attribute correctly for your fill and text label:
return color(d.data.STATUS); //<-- don't need "rows", you only passed in data.rows
Here is is working nicely:
var data= { "rows":[
{
"STATUS" : "Active",
"count" : "246"
}
,
{
"STATUS" : "Not Proceeded With",
"count" : "40"
}
]};
var width = 800,
height = 250,
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(radius - 70);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return d.count;
});
var svg = d3.select("body").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.rows))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d) {
return color(d.data.STATUS);
});
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.STATUS;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Related

JSON object not returning pie slices

I have been working off of this basic pie example to learn about writing pie charts in D3, but while I got the example to work when mimicking their data structure, I wanted to try it out with a JSON data structure that would be more native to how I would structure data for the visualizations. When switching the same data to this new structure I noticed that the black stroke appears and the annotations, but the slices aren't present and the annotation labels are referencing an index and object value.
I believe this is due to the .entries() method that converts it to a key-value data structure, but I'm curious if that is a necessary method to use in order to visualize the data points or if there is a simpler method to utilize the structure I have in place.
Working data structure:
var data = {
deep: 22.37484390963787,
light: 62.65183335225337,
rem: 14.973322738108752
}
JSON data structure:
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
// var data = {
// deep: 22.37484390963787,
// light: 62.65183335225337,
// rem: 14.973322738108752
// }
console.log(data)
var width = 480;
var height = 480;
var margin = 40;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var pie = d3.pie()
.value(function(d) { return d.value; });
var data_ready = pie(d3.entries(data));
console.log(data_ready);
var arcGenerator = d3.arc()
.innerRadius(0)
.outerRadius(radius);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('path')
.attr('d', arcGenerator)
.attr('fill', function(d){ return color(d.data.key)})
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('text')
.text(function(d){ return d.data.key + ', ' + d.data.value})
.attr("transform", function(d) { return "translate(" + arcGenerator.centroid(d) + ")"; })
.style("text-anchor", "middle")
.style("font-size", 17);
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
The other way to achieve this is to not use d3.entries and pass your data directly. A couple of other tweaks are required where you get the color and label text (ie use d.data.label in place of d.data.key).
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
// var data = {
// deep: 22.37484390963787,
// light: 62.65183335225337,
// rem: 14.973322738108752
// }
console.log(data)
var width = 480;
var height = 480;
var margin = 40;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var pie = d3.pie()
.value(function(d) { return d.value; });
var data_ready = pie(data);
console.log(data_ready);
var arcGenerator = d3.arc()
.innerRadius(0)
.outerRadius(radius);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('path')
.attr('d', arcGenerator)
.attr('fill', function(d){ return color(d.data.label)})
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('text')
.text(function(d){ return d.data.label + ', ' + d.data.value})
.attr("transform", function(d) { return "translate(" + arcGenerator.centroid(d) + ")"; })
.style("text-anchor", "middle")
.style("font-size", 17);
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
You can't just change the format of the data without changing something else too. The simplest solution is to reformat your structure into the structure that d3 expected in the first place:
var formatted_data = data.reduce((acc,i) => {acc[i.label] = i.value; return acc;},{});
And then pass that to entries:
var data = [
{ "label": "deep", "value": 22.37484390963787 },
{ "label": "light", "value": 62.65183335225337 },
{ "label": "rem", "value": 14.973322738108752 }
]
// var data = {
// deep: 22.37484390963787,
// light: 62.65183335225337,
// rem: 14.973322738108752
// }
var formatted_data = data.reduce((acc,i) => {acc[i.label] = i.value; return acc;},{});
console.log(formatted_data)
var width = 480;
var height = 480;
var margin = 40;
var radius = Math.min(width, height) / 2 - margin;
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888"]);
var pie = d3.pie()
.value(function(d) { return d.value; });
var data_ready = pie(d3.entries(formatted_data));
console.log(data_ready);
var arcGenerator = d3.arc()
.innerRadius(0)
.outerRadius(radius);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('path')
.attr('d', arcGenerator)
.attr('fill', function(d){ return color(d.data.key)})
.attr("stroke", "black")
.style("stroke-width", "2px")
.style("opacity", 0.7);
svg.selectAll('viz')
.data(data_ready)
.enter()
.append('text')
.text(function(d){ return d.data.key + ', ' + d.data.value})
.attr("transform", function(d) { return "translate(" + arcGenerator.centroid(d) + ")"; })
.style("text-anchor", "middle")
.style("font-size", 17);
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

How to add legend to a pie chart D3.js?

I've looked through similar questions but still can't implement code correctly.
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 percentageFormat = d3.format("%");
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.values;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.json("staff.json", function(error, json_data) {
var data = d3.nest()
.key(function(d) {
return d.Position;
})
.rollup(function(d) {
return d.length;
}).entries(json_data);
data.forEach(function(d) {
d.percentage = d.values / json_data.length;
});
console.log("data variable", data);
console.log("pie(data)", pie(data));
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
.on('mouseover', function() {
var current = this;
var others = svg.selectAll(".arc").filter(function(el) {
return this != current
});
others.selectAll("path").style('opacity', 0.8);
})
.on('mouseout', function() {
var current = this;
d3.select(this)
.style('opacity', 1);
var others = svg.selectAll(".arc").filter(function(el) {
return this != current
});
others.selectAll("path").style('opacity', 1);
});
g.append("path")
.attr("d", arc)
.style("fill", function(d, i) {
return color(i);
});
g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) {
console.log("d is", d);
return percentageFormat(d.data.percentage);
});
Here's a JSON-file:
[{
"Position" : "Programmer",
"Name" : "Giacomo Gulizzoni",
"Age" : 37,
"Sex" : "Male",
"Project" : "SmartFactory"
}, {
"Position" : "Tester",
"Name" : "Marko Botton",
"Age" : 34,
"Sex" : "Male",
"Project" : "SmartFactory"
}, {
"Position" : "Tester",
"Name" : "Mariah Maclachian",
"Age" : 37,
"Sex" : "Female",
"Project" : "SmartFactory"
}, {
"Position" : "Tester",
"Name" : "Valerie Liberty",
"Age" : 25,
"Sex" : "Female",
"Project" : "SmartProject"
}, {
"Position" : "Programmer",
"Name " : "Guido Jack Gulizzoni",
"Age" : 22,
"Sex" : "Male",
"Project" : "SmartProject"
}]
Actually, legends are just rectangles that are bound to data if I'm not mistaken. But in my case items in JSON file are not numerical values. Have look at my plunk for the results of my experiments.
In your code:
You are setting the data in the legend selection wrong
var legend = ...
.data(pie(data))//this is wrong
.enter().append("g")
You need to do like this
var legend = d3.select("body").append("svg")
.attr("class", "legend")
.selectAll("g")
.data(data)//setting the data as we know there are only two set of data[programmar/tester] as per the nest function you have written
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return color(d.key);
});
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d.key; });
Working code here
Hope this helps!
Actually it was in your code,
var legend = svg.selectAll('.legend') // NEW
.data(pie(data)) // NEW
.enter() // NEW
.append('g') // NEW
.attr('class', 'legend') // NEW
.attr('transform', function(d, i) { // NEW
var height = legendRectSize + legendSpacing; // NEW
var offset = height * pie(data).length / 2; // NEW
var horz = -2 * legendRectSize; // NEW
var vert = i * height - offset; // NEW
return 'translate(' + horz + ',' + vert + ')'; // NEW
});
legend.append('rect') // NEW
.attr('width', legendRectSize) // NEW
.attr('height', legendRectSize) // NEW
.style('fill', function(d,i){return color(i);}) // NEW
.style('stroke', function(d,i){return color(i);}); // NEW
legend.append('text') // NEW
.attr('x', legendRectSize + legendSpacing) // NEW
.attr('y', legendRectSize - legendSpacing) // NEW
.text(function(d) { console.log("text: ");console.log(d);return d.data.key; });
I've un commented and did little changes.
You can observe the code.

How to use forEach in d3 using Javascript

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

Donut chart d3.js

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]); });

Implementation of pie chart in d3.js

I have implemented bar chart and line chart in d3.js but now I am trying to implement pie chart as you can see but it is not working so I need your suggestions. Bar chart and line chart are working fine ... Thank you in advance ... here is my code:
var margin = {
top: 20,
right: 0,
bottom: 80,
left: 40
};
var width = 700 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var xScale = d3.scale.ordinal().rangeRoundBands([0, width], .1);
var yScale = d3.scale.linear().range([height, 0]);
var hAxis = d3.svg.axis().scale(xScale).orient('bottom').tickFormat(d3.time.format("%Y-%m-%d"));
var vAxis = d3.svg.axis().scale(yScale).orient('left');
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('background', '#f4f4f4')
.style('padding', '5 15px')
.style('border', '1px #333 solid')
.style('border-radius', '5px')
.style('opacity', 'o');
var line = d3.svg.line()
.x(function(d) {
return xScale(d.date);
})
.y(function(d) {
return yScale(selectValue(d));
})
.interpolate("linear")
.tension(0.9);
//Pie chart implementationion
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.date; });
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
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 labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//till here
function render(filterByDates) {
d3.select('svg').remove();
if (filterByDates) {
selectDate = true;
tempData = fliterdata;
console.log("before date fliter data", tempData);
var date1 = new Date(document.getElementById('field1').value);
var date2 = new Date(document.getElementById('field2').value);
tempData = tempData.filter(function(d) {
return d.date >= date1 && d.date <= date2;
});
console.log("After date fliter data", tempData);
}
xScale.domain(tempData.map(function(d) {
return d.date;
}).sort(function(a, b) {
return a - b;
}));
yScale.domain([0, d3.max(tempData, function(d) {
return +selectValue(d);
})]);
var svg = d3.select('#chart').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 + ")");
svg
.append('g')
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(hAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg
.append('g')
.attr("class", "yaxis")
.call(vAxis)
if (chartType == 'bar') {
svg
.selectAll(".bar") //makes bar
.data(tempData)
.enter().append("rect")
.attr("class", "bar")
.style("fill", "teal")
.attr("x", function(d) {
return xScale(d.date);
}).attr("width", xScale.rangeBand())
.attr("y", function(d) {
return yScale(selectValue(d));
}).attr("height", function(d) {
console.log("as", d.value);
return height - yScale(selectValue(d));
}).on('mouseover', function(d) {
tooltip.transition()
.style('opacity', 1)
tooltip.html(d.value)
.style('left', (d3.event.pageX) + 'px')
.style('top', (d3.event.pagey) + 'px')
d3.select(this).style('opacity', 0.5)
}).on('mouseout', function(d) {
tooltip.transition()
.style('opacity', 0)
d3.select(this).style('opacity', 1)
});
}
if (chartType == 'line') {
svg.append("path") // Add the line path.
.data(tempData)
.attr("class", "line")
.attr("d", line(tempData));
}
//Implementation of pie chart
if (chartType == 'pie') {
svg.append("path") // Add the line path.
.data(tempData)
.attr("class", "pie")
.attr("d", Pie(tempData));
}
}
d3.json(jsonURL, function(data) {
myData = data; //data from json in mydata
myData.forEach(function(d) {
d.val003.replace(",",".")
d.date = new Date(d.date);
//d.value="";
//d.name = +d.name;
console.log(d.date, "Gt date");
d.date = new Date(d.date + " UTC");
console.log(d.date, "localtimezone date");
});
$("#listbox").on("click", function() {
var key = $(this).val();
console.log("key:", key);
var value = $('#listbox option:selected').text();
selectop = String(key);
selectop = selectop.slice(-2);
fliterdata = filterJSON(myData, key, value); //selected value from user and picks the whole element that contains that attribute
tempData = fliterdata; //graph made by temp data
if (selectDate)
render(true);
});
});
function selectChartType(type) {
chartType = type;
render(true);
}
</script>

Categories