0

The code below requires the JSON object to specify "value" and "label". I want to make this so that a pie chart can be created with any key names.

//Regular pie chart example
nv.addGraph(function() {
  var chart = nv.models.pieChart()
      .x(function(d) { return d.label })
      .y(function(d) { return d.value })
      .showLabels(true);

d3.select("#chart svg")
    .datum(exampleData())
    .transition().duration(350)
    .call(chart);

  return chart;
});

The above function can be modified to return d.fruit and d.number to create a pie chart of a JSON object [{"fruit": "apple", "number": 1}], but I would like this to work for any JSON object, regardless of the key names.

#chart svg {
  height: 400px;
}

</style>


<div id="chart">
  <svg></svg>
</div>
</head>

<body>
<script>
//Regular pie chart example
nv.addGraph(function() {
  var chart = nv.models.pieChart()
      .x(function(d) { return d.label })
      .y(function(d) { return d.value })
      .showLabels(true);

    d3.select("#chart svg")
        .datum(exampleData())
        .transition().duration(350)
        .call(chart);

  return chart;
});

//Donut chart example
nv.addGraph(function() {
  var chart = nv.models.pieChart()
      .x(function(d) { return d.label })
      .y(function(d) { return d.value })
      .showLabels(true)     //Display pie labels
      .labelThreshold(.05)  //Configure the minimum slice size for labels to show up
      .labelType("percent") //Configure what type of data to show in the label. Can be "key", "value" or "percent"
      .donut(true)          //Turn on Donut mode. Makes pie chart look tasty!
      .donutRatio(0.35)     //Configure how big you want the donut hole size to be.
      ;

    d3.select("#chart2 svg")
        .datum(exampleData())
        .transition().duration(350)
        .call(chart);

  return chart;
});

//Pie chart example data. Note how there is only a single array of key-value pairs.
function exampleData() {
  return  [
      {"value":"1","label":"apples"},{"value":"2","label":"bananas"}
    ];
}
</script>
</body>


</html>
Brandon Tiqui
  • 1,429
  • 3
  • 17
  • 35

2 Answers2

1

The following lines define what properties should be used by the chart:

var chart = nv.models.pieChart()
  .x(function(d) { return d.label })
  .y(function(d) { return d.value })

So, you can change d.label to d.whatever, and if you have a whatever property, it will use that for x.


You could run your data through something before you pass it into the chart. Something along the lines of:

d3.map(data, function(item) {
   return {
     label: item.car,
     value: item.speed
   };
}).values();

You could easily wrap that in a function something like:

function transform(data, x, y) {
  x = x || "label";
  y = y || "value";
  return d3.map(data, function(item) {
    return {
      label: item[x],
      value: item[y]
    };
  }).values();
}

d3.select("#chart2 svg")
  .datum(transform(exampleData(), "car", "speed"));

There is no reliable way other than transforming your data or changing your x and y accessors to guarantee you will see the data you're expecting to see. The chart has no way to understand your data without you expressing what it means.

kalley
  • 18,072
  • 2
  • 39
  • 36
  • I understand that. What if I have a "fruit" and "number" JSON object; or a "car" and "speed" JSON object? I don't want to keep changing d.label and d.value to d.fruit/d.number, d.car/d.speed, etc. – Brandon Tiqui May 20 '14 at 16:01
  • Updated my answer with a method you could use to transform your data to a common format. – kalley May 20 '14 at 16:06
1
var chart = nv.models.pieChart()
        .x(function(d) { //always spits out first memeber of object
            var val, x;
            val = 0;
            x = 0;
            for (i in d) {
                if (x++ === val)
                {
                    return d[i];
                }
            }
        })
        .y(function(d) { //always spits out second member of object
            var val, x;
            val = 1;
            x = 0;
            for (i in d) {
                if (x++ === val)
                {
                    return d[i];
                }
            }
        })
chiliNUT
  • 18,989
  • 14
  • 66
  • 106
  • This is dangerous since there is no guarantee of the order of properties: http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order – kalley May 20 '14 at 16:14
  • [{"number":"1","fruit":"apples"}] The code returns the actual value of the JSON; in this case, "1". How can I get the key ("number", "fruit")? – Brandon Tiqui May 20 '14 at 16:27
  • Return `i` instead of `d[i]` to get the key. – chiliNUT May 20 '14 at 16:39
  • @kalley is right, you might need to do something like type checking to say, decide the numerical quantity is the value, and the string value is the label. – chiliNUT May 20 '14 at 16:42
  • 1
    This worked. Had to put parentheses around d[i] in the return statements. – Brandon Tiqui May 20 '14 at 18:35