I have tried to search but cannot find a solution.
My data look like this :
var data = [
{ "hour":"10",
"percentage":"50"
},
{ "hour":"11",
"percentage":"20"
},
{ "hour":"3",
"percentage":"90"
},
{ "hour":"55",
"percentage":"40"
},
{ "hour":"6",
"percentage":"70"
},
{ "hour":"8",
"percentage":"40"
}
];
I draw donut chart according to this data. I need :
To divide chart into 12 equal parts like clock.
I have color range to describe percentage, but what if there is no data in my hour attribute ?
I am new to D3JS and I cannot figure out the logic. Below is my donut chart.
Thanks in advanced.
var data = [
{ "hour":"10",
"percentage":"50"
},
{ "hour":"11",
"percentage":"20"
},
{ "hour":"3",
"percentage":"90"
},
{ "hour":"55",
"percentage":"40"
},
{ "hour":"6",
"percentage":"70"
},
{ "hour":"8",
"percentage":"40"
}
];
var can = d3.select("body").append("svg").attr("height",1000).attr("width",1000);
//var svg = d3.select(can[0]);
var r =100;
var p = Math.PI*2;
var color = d3.scale.linear()
.domain([0,100])
.range(["white","red"]);
var group = can.append("g")
.attr("transform","translate(100,100)");
var arc = d3.svg.arc()
.innerRadius(r - 30)
.outerRadius(r)
//.startAngle(0)
.endAngle(p-1);
var pie = d3.layout.pie()
.sort(null)
.value(function (d){return d.percentage;});
var arcs = group.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
.attr('fill',function(d){return color(d.data.percentage)})
.on("mouseover", function(d){
div.style("display", "inline")
.text(d.data.percentage + ", " + d.data.hour)
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
})
.on("mouseout", mouseout);
arcs.append("path")
.attr("d", arc)
.style("fill", function (d) {
return color(d.data.percentage);
});
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("display", "none");
function mouseout() {
div.style("display", "none");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
If you want them in equal parts then how come your using percentage in the pie.value()
?
Pie.value()
is how you split the pie chart up.
So what I would do is create a dummy value to create equal parts :
for(i=0;i<data.length;i++){
data[i].value = 1;
}
Now you pass the value to the pie.value() instead of the percentage:
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value
//return d.percentage
});
And the reason your chart doesnt go the whole way round is because of this line :
.endAngle(p-1);
Math.PI is in radians thus this is what you are setting as the angle :
p = 6.28319 radians;
p-1 = 5.28319 radians;
Thus
p-1 = 302.7044894 degrees;
Take the -1 away and you have a full circle.
Here is it with the current data :
var data = [{
"hour": "10",
"percentage": "50"
}, {
"hour": "11",
"percentage": "20"
}, {
"hour": "3",
"percentage": "90"
}, {
"hour": "55",
"percentage": "40"
}, {
"hour": "6",
"percentage": "70"
}, {
"hour": "8",
"percentage": "40"
}];
for (i = 0; i < data.length; i++) {
data[i].value = 1;
}
var can = d3.select("body").append("svg").attr("height", 1000).attr("width", 1000);
//var svg = d3.select(can[0]);
var r = 100;
var p = Math.PI * 2;
var color = d3.scale.linear()
.domain([0, 100])
.range(["white", "red"]);
var group = can.append("g")
.attr("transform", "translate(100,100)");
var arc = d3.svg.arc()
.innerRadius(r - 30)
.outerRadius(r)
//.startAngle(0)
.endAngle(p );
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value
//return d.percentage
});
var arcs = group.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
.attr('fill', function(d) {
//console.log(d)
return color(d.data.percentage)
})
.on("mouseover", function(d) {
div.style("display", "inline")
.text(d.data.percentage + ", " + d.data.hour)
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
})
.on("mouseout", mouseout);
arcs.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.percentage);
});
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("display", "none");
function mouseout() {
div.style("display", "none");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Now the problem you have where you want it in 12 equal parts. I think you need to expand on what you want here. Do you want the missing parts to be shown ? Shown in a different colour ? What do you want ?
To solve each of these youre going to have to create the data and add it to your existing data like so :
var newData = [];
for (i = 1; i <= 12; i++) { //go through numbers 1-12 like a clock
var thisData;
var inData = false; //bool to check if data exists already
for (j = 0; j < data.length; j++) { //go through existing data
if (data[j].hour == i) { //check if data exists
inData = true; //data exists
thisData = {
"hour": data[j].hour, //add data at [i]
"percentage": data[j].percentage, //add data at [i]
"value": data[j].value //add data at [i]
}
newData.push(thisData) //push into new array
}
}
if (!inData) { //if data doesnt exist
thisData = {
"hour": i, //set hour to i
"percentage": 0,
"value": 1
}
newData.push(thisData) //push into new data
}
}
console.log(newData)
Here is the pie chart with new data, still with value as 1 so you get equal segment. They're coloured white as they have no percentage and I've added a stroke so you can tell which one is which :)
var data = [{
"hour": "10",
"percentage": "50"
}, {
"hour": "11",
"percentage": "20"
}, {
"hour": "3",
"percentage": "90"
}, {
"hour": "5",
"percentage": "40"
}, {
"hour": "6",
"percentage": "70"
}, {
"hour": "8",
"percentage": "40"
}];
for (i = 0; i < data.length; i++) {
data[i].value = 1;
}
var newData = [];
for (i = 1; i <= 12; i++) { //go through numbers 1-12 like a clock
var thisData;
var inData = false; //bool to check if data exists already
for (j = 0; j < data.length; j++) { //go through existing data
if (data[j].hour == i) { //check if data exists
inData = true; //data exists
thisData = {
"hour": data[j].hour, //add data at [i]
"percentage": data[j].percentage, //add data at [i]
"value": data[j].value //add data at [i]
}
newData.push(thisData) //push into new array
}
}
if (!inData) { //if data doesnt exist
thisData = {
"hour": i, //set hour to i
"percentage": 0,
"value": 1
}
newData.push(thisData) //push into new data
}
}
console.log(newData)
var can = d3.select("body").append("svg").attr("height", 1000).attr("width", 1000);
//var svg = d3.select(can[0]);
var r = 100;
var p = Math.PI * 2;
var color = d3.scale.linear()
.domain([0, 100])
.range(["white", "red"]);
var group = can.append("g")
.attr("transform", "translate(100,100)");
var arc = d3.svg.arc()
.innerRadius(r - 30)
.outerRadius(r)
//.startAngle(0)
.endAngle(p);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value
//return d.percentage
});
var arcs = group.selectAll(".arc")
.data(pie(newData))
.enter().append("g")
.attr("class", "arc")
.attr('fill', function(d) {
//console.log(d)
return color(d.data.percentage)
})
.style('stroke','black')
.on("mouseover", function(d) {
div.style("display", "inline")
.text(d.data.percentage + ", " + d.data.hour)
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
})
.on("mouseout", mouseout);
arcs.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.percentage);
});
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("display", "none");
function mouseout() {
div.style("display", "none");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>