Search code examples
d3.jsupdatespie-chart

D3.js Applying update pattern to pie chart


I am trying to get an update pattern to work on a pie chart using d3.js v4. The data changes when selected from a dropdown menu.

Mainly I would like to be able to use the correct update pattern so that I can .exit() .enter() and update the data. Also I would like to be able to use the arcTween() function he uses from one of Bostock's examples.

I am trying to implement this example by HarryStevens on b.locks.

Currently I am getting the following error,

pie is not a function

from line 140, which reads,

  .data(pie(category_count),

and is marked in the code below with asterixs.

This is part of the code,

// Generate an array object on categories as a category
        var category_count = d3.nest()
          .key(function(d) {
            return d.category;
          })
          .rollup(function(leaves) {
            return leaves.length;
          })
          .entries(data);
        // console.log(category_count);

        var pie = d3.pie()
          .padAngle(.02)
          .sort(null)
          .value(function(d) {
            return d.value;
          })
          (category_count);

        function arcTween(a) {
          console.log(this._current);
          var i = d3.interpolate(this._current, a);
          this._current = i(0);
          return function(t) {
            return arc(i(t));
          };
        }

        var arc = d3.arc()
          .outerRadius(radius - 10)
          .innerRadius(radius / 2);

        var labelArc = d3.arc()
          .outerRadius(radius - 10)
          .innerRadius(radius - 100);

        var svgPie = d3.select("#pie")
          .append("svg")
          .attr("width", width)
          .attr("height", height)
          .append("g")
          .attr("transform", "translate(" + (margin.left + radius) + "," + (margin.top + radius) + ")"); //center of pie

        var arcs = svgPie.selectAll("arc")
   ******** .data(pie(category_count), ******** 
            function(d) {
              return d.data.key
            });

        arcs
          .transition()
          .duration(4000)
          .attrTween("d", arcTween);

        // EXIT old elements not present in new data
        arcs.enter()
          .append("path")
          .attr("class", "arc exit")
          .style("fill", function(d, i) {
            return color[i];
          })
          .attr("d", arc)
          .each(function(d) {
            this._current = d;
          });

The full code is here on github.

Any help would be greatly appreciated.


Solution

  • You are currently setting pie to the return of the function d3.pie()(category_count). d3.pie() itself returns a function. So what you would want to do is this:

    var pie = d3.pie()
          .padAngle(.02)
          .sort(null)
          .value(function(d) {
            return d.value;
          });
    

    Then when you call it like this:

    var arcs = svgPie.selectAll("arc")
       .data(pie(category_count),
            function(d) {
              return d.data.key
            });
    

    This is now invoking the function pie with the arguments category_count.