0
votes

I've encountered an error while coding my chart on my "card" bootstrap. The thing is I only want the label to show on my pie chart but the problem is console on google chrome says "Uncaught TypeError: d3.arc(...).outerRadius(...).innerRadius(...).text is not a function" In which i don't get why.

Below is my code for the pie-chart:

var data = [
    {"platform": "Android", "percentage": 40.11},
    {"platform": "Windows", "percentage": 36.69},
    {"platform": "iOS", "percentage": 13.06}
];


var svgCirWidth = 600, svgCirHeight = 300, radius = Math.min(svgCirWidth, svgCirHeight) / 2;

const pieContainer = d3.select("#pieChart")
.append("svg")
.attr("width", svgCirWidth)
.attr("height", svgCirHeight);

//create group element to hold pie chart

var g = pieContainer.append("g")
.attr("transform", "translate(" + 170 + "," + radius + ")");

var color = d3.scaleOrdinal(d3.schemeCategory10);

var pie = d3.pie().value(function(d){
    return d.percentage;
});

var path = d3.arc()
.outerRadius(radius)
.innerRadius(0);

var arc = g.selectAll("arc")
.data(pie(data))
.enter() //means keeps looping in the data
.append("g");

arc.append("path")
.attr("d", path)
.attr("fill", function(d){
    return color(d.data.percentage);
})

var label = d3.arc()
.outerRadius(radius)
.innerRadius(0)
.text(function(d){
    return d;
});
1

1 Answers

0
votes

d3.arc returns a path's d attribute. This cannot contain text.

In SVG, text must be enclosed inside <text>.

Since your variable arc is a selection of a g element, you could append <text> to it:

arc.append('text')
     .text(/* ... */)

Edit after receiving a comment that "it still won't work"

Please be specific whenever reporting problems, in order to receive proper help: is there any error message? What is the observed behaviour, and what was the expected one?

Using arc.append('text') seems to work just fine.

Debugging tip

It is often helpful to use console.log as shown below to see what is going on:

arc.append('text')
  .text(function(d){
    console.log('text', d)
    return d;
  })

The code above will show that d is an object, this is why the labels are shown in the page as [object object].

I assume that the desired behaviour is rather to show the platform and percentage values.

Then instead of return d, we know thanks to the console.log output that we should rather use d.data.platform and d.data.percentage:

return d.data.platform + ': ' + d.data.percentage;

Labels placement

Another issue observed is that all labels are overlapping. This is normal, no position has been defined for them.

A quick use of search engine shows us this example, where arc.centroid is used together with text-anchor: middle to position each label in a suitable location.

Solution is illustrated in the snipped below.

var data = [
    {"platform": "Android", "percentage": 40.11},
    {"platform": "Windows", "percentage": 36.69},
    {"platform": "iOS", "percentage": 13.06}
];


var svgCirWidth = 600, svgCirHeight = 300, radius = Math.min(svgCirWidth, svgCirHeight) / 2;

const pieContainer = d3.select("#pieChart")
.append("svg")
.attr("width", svgCirWidth)
.attr("height", svgCirHeight);

//create group element to hold pie chart

var g = pieContainer.append("g")
.attr("transform", "translate(" + 170 + "," + radius + ")");

var color = d3.scaleOrdinal(d3.schemeCategory10);

var pie = d3.pie().value(function(d){
    return d.percentage;
});

var path = d3.arc()
.outerRadius(radius)
.innerRadius(0);

var arc = g.selectAll("arc")
.data(pie(data))
.enter() //means keeps looping in the data
.append("g")

arc.append("path")
.attr("d", path)
.attr("fill", function(d){
    return color(d.data.percentage);
})

arc.append('text')
  .text(function(d){
    return d.data.platform + ': ' + d.data.percentage;
  })
  .attr('transform', function(d){
    return 'translate(' + path.centroid(d) + ')'
  })
  .attr('text-anchor', 'middle')
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.min.js"></script>
<div id="pieChart"></div>