-2

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 :

  1. To divide chart into 12 equal parts like clock.

  2. 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>
thatOneGuy
  • 9,977
  • 7
  • 48
  • 90
Mad Adh
  • 95
  • 9

1 Answers1

2

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>
thatOneGuy
  • 9,977
  • 7
  • 48
  • 90