ipenguin67
ipenguin67

Reputation: 1649

Getting TypeError: d is undefined for d3 pie chart in React

I have a method in React, drawChart(), which should generate a pie chart SVG. However React is throwing a TypeError of "d is undefined" and highlighting my "svg" line (see below)

const drawChart = () => {
    const data = {'protein': 16, 'fat': 36, 'carbs':45} // sample data

    const width = 80;
    const height = 80;

    const colorScale = d3.scaleOrdinal()
                          .domain(data)
                          .range(d3.schemeCategory10);

    const svg = d3.select("#graph")
      .append("svg")
        .attr("width", width)
        .attr("height", height)
      .append("g")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


    const arcs = d3.pie()
                    .value(d => d.value)(data);
    const path = d3.arc()
                    .innerRadius(0)
                    .outerRadius(width / 2);

    svg  // this is getting highlighted in the React error output
      .selectAll('.arc')
      .data(arcs)
      .enter()
      .append('path')
        .classed('arc', true)
        .attr('fill', d => {
          if (d.properties) {
            colorScale(d.data.key)
          }
        })
        .attr('stroke', 'black')
        .attr('d', path);
  }

Upvotes: 0

Views: 565

Answers (1)

wentjun
wentjun

Reputation: 42526

That is because of the following issues:

1) The data structure of the data object you have provided do not match the format on your data joins. I would recommend you to use an array of objects, instead of a dictionary.

2) You are filling the colours wrongly. This is your original code.

.attr('fill', d => {
  if (d.properties) {
    colorScale(d.data.key)
  }
});

properties is not a valid key of d. If you want to check for the presence of a valid key and value, you should be using the data property instead(d.data). In addition, you are not returning any colour values from thecolourScale` anonymous function.

To fix it, this is what you should be doing instead:

.attr('fill', d => {
  if (d.data) {
    return colorScale(d.data.value);
  }
})

The full code is available below:

const data = [{
    name: 'protein',
    value: 16,
  },
  {
    name: 'fat',
    value: 36,
  },
  {
    name: 'carbs',
    value: 45,
  }
];

const width = 80;
const height = 80;

const colorScale = d3.scaleOrdinal()
  .domain(data)
  .range(d3.schemeCategory10);

const svg = d3.select("#graph")
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


const arcs = d3.pie()
  .value(d => d.value)(data);
const path = d3.arc()
  .innerRadius(0)
  .outerRadius(width / 2);

svg
  .selectAll("path")
  .data(arcs)
  .enter()
  .append('path')
  .classed('arc', true)
  .attr('fill', d => {
    if (d.data) {
      return colorScale(d.data.value);
    }
  })
  .attr('stroke', 'black')
  .attr('d', path);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.min.js"></script>

<div id="graph"></div>

Upvotes: 1

Related Questions