PieChart - labels are overlapping when distance between them is really small
For some big numbers in pair with rather small ones, labels are overlapping other as there's no sufficient space for all of them.
Here is the demo: http://jsfiddle.net/qzk61f5h/
And this is how it looks like:

I think that library should handle this case properly - maybe by showing them stacked up at the top of another?
Same issue here

Is there any progress on fixing this issue?
Seems like a pretty big bug.
I have also run into this issue and I'm trying to find a way around it, but with no success.
Very big issue for me using this library.
Would be nice to have an automated solution, but in the mean time I worked around by using Legend instead and had coloured pie slices, added some paddingAngle to make small slices obvious and added minAngle to also make the slice visible. You an tweak the angles, but it gives an idea.
Not bothering to create jsfiddle because they always seem broken by the time I view ... the relevant code snippets below ...
// Static data, or you could have a list of available colours and map your data to contain different fill colours
const myData = [
{
name: 'Name A',
value: 9999,
fill: '#908ce2',
},
{
name: 'Name B',
value: 5000,
fill: '#2fe18a',
},
{
name: 'Name C',
value: 2,
fill: '#ef8a88',
},
{
name: 'Name D',
value: 1,
fill: '#8fcddd',
},
];
...
<ResponsiveContainer width="60%" minHeight={400}>
<PieChart>
<Pie data={myData} dataKey="value" nameKey="name" fill="#8884d8" legendType="circle" paddingAngle={1} minAngle={1} />
<Tooltip/>
<Legend/>
</PieChart>
</ResponsiveContainer>
Has anyone been able find a workaround to this problem?
I have a problem with this too. I tried to use custom label, but i can't create algorithm to calc positions for labels...=(
Highcharts handle this smoothly... It should be great to have a workaround for this issue. https://www.highcharts.com/demo/pie-basic
I'm having the same problem.
Does anyone have a solution?
I also had issues placing custom label text, but I am using the following solution for that as well as some logic for translating the labels because the built in locations were not working:
const offsetLabel = (name, x, y) => {
let offsetX
let offsetY
if (name === '100%') return [22, 5]
if (x <= 145) {
offsetX = 14
} else {
offsetX = 22
}
if (y <= 105) {
offsetY = 11
} else {
offsetY = 5
}
return [offsetX, offsetY]
}
const renderLabelContent = props => {
const { name, x, y, midAngle } = props
const [offsetX, offsetY] = offsetLabel(name, x, y)
return (
<g transform={`translate(${x}, ${y})`} textAnchor={(midAngle < -90 || midAngle >= 90) ? 'end' : 'start'}>
<text x={offsetX} y={offsetY}>{name}</text>
</g>
)
}
I am passing the function renderLabelContent to the attribute label below:
<ReactPieChart width={200} height={220}>
<Pie
startAngle={90}
endAngle={450}
innerRadius={innerRadius || 0}
data={data}
paddingAngle={paddingAngle}
stroke={stroke}
label={renderLabelContent}
labelLine={false}
dataKey='value'
/>
</ReactPieChart>
We ended up creating a custom label function that just returns NULL for values that are less than a configured percent of the total. Since the value is shown in a tooltip on hover, this was the cleanest solution we could think of without trying to calculate positions. What also helped was being sure to sort the values such that the smallest always appear at "3 'o clock" to minimize the possibility of horizontal overlap.

That being said, this is certainly not ideal and would love to know if there's actual interest in getting a real fix for the library.
+1 for the issue, any update?
Thanks to @zgallagher08 initial comment, I came with following code, which pretty much provides the same output as @rmkpatchaa shown :
renderCustomizedLabel({
cx, cy, midAngle, innerRadius, outerRadius, value, color, startAngle, endAngle}) {
const RADIAN = Math.PI / 180;
const diffAngle = endAngle - startAngle;
const delta = ((360-diffAngle)/15)-1;
const radius = innerRadius + (outerRadius - innerRadius);
const x = cx + (radius+delta) * Math.cos(-midAngle * RADIAN);
const y = cy + (radius+(delta*delta)) * Math.sin(-midAngle * RADIAN);
return (
<text x={x} y={y} fill={color} textAnchor={x > cx ? 'start' : 'end'} dominantBaseline="central" fontWeight="normal">
{value}
</text>
);
};
renderCustomizedLabelLine(props){
let { cx, cy, midAngle, innerRadius, outerRadius, color, startAngle, endAngle } = props;
const RADIAN = Math.PI / 180;
const diffAngle = endAngle - startAngle;
const radius = innerRadius + (outerRadius - innerRadius);
let path='';
for(let i=0;i<((360-diffAngle)/15);i++){
path += `${(cx + (radius+i) * Math.cos(-midAngle * RADIAN))},${(cy + (radius+i*i) * Math.sin(-midAngle * RADIAN))} `
}
return (
<polyline points={path} stroke={color} fill="none" />
);
}

Any update? Currently can't use this lib with this bug and @abishek28007 solution doesn't render correctly for us.
@abishek28007 After doing some changes to your customized label function it's working fine for me. I'm a bit confused about where to set the customized line function to the pie chart ??
@SenelithPerera
<Pie labelLine={renderCustomizedLabelLine}
label={renderCustomizedLabel}
>
@abishek28007 Thanks for getting back to me, but unfortunately your solution didn't fix my problem 100% so I moved to temporary solution, which is showing the labels like this (custom active Index) , as specified in this

We need a concrete solution for showing labels in pie charts without having the overlapping issue !!
@SenelithPerera , can you post the modification that you made in my code, would help me to come up with a fix for this.
Any update on this? It's a pretty serious issue for quite an ordinary and common use case and hasn't been solved for a while now. Is it being worked on?
<Pie isAnimationActive={false} isUpdateAnimationActive={true} data={props.data} dataKey="value" nameKey="name" labelLine={({ cx, cy, midAngle, innerRadius, outerRadius, value, index }) => { const RADIAN = Math.PI / 180;
// eslint-disable-next-line
let radius1 = 20 + innerRadius + (outerRadius - innerRadius);
let radius2 = innerRadius + (outerRadius - innerRadius);
// eslint-disable-next-line
let x2 = cx + radius1 * Math.cos(-midAngle * RADIAN);
// eslint-disable-next-line
let y2 = cy + radius1 * Math.sin(-midAngle * RADIAN);
let x1 = cx + radius2 * Math.cos(-midAngle * RADIAN);
// eslint-disable-next-line
let y1 = cy + radius2 * Math.sin(-midAngle * RADIAN);
if (value<30){
return null;
}
return(
<line x1={x1} y1={y1} x2={x2} y2={y2} stroke="#ccc" strokeWidth={1}>
</line>
)
}}
label={({
cx,
cy,
midAngle,
innerRadius,
outerRadius,
value,
index
}) => {
const RADIAN = Math.PI / 180;
// eslint-disable-next-line
let radius = 20 + innerRadius + (outerRadius - innerRadius);
// eslint-disable-next-line
let x = cx + radius * Math.cos(-midAngle * RADIAN);
// eslint-disable-next-line
let y = cy + radius * Math.sin(-midAngle * RADIAN);
if (value<30){
return null;
}
return (
<text
x={x}
y={y}
fill="#000"
fontWeight="300"
fontSize="13px"
fontFamily="'Source Sans Pro', 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'"
textAnchor={x > cx ? "start" : "end"}
dominantBaseline="central"
>
{props.data[index].name} {value}
</text>
);
}}
cx="50%"
cy="50%"
outerRadius="84%"
innerRadius="40%"
fill="#8884d8" >
{/* <LabelList dataKey="name" position="outside" /> */}
<Label value={100} position="center" fontSize={24} fontWeight={400}></Label>
</Pie>
Any update on this? It's a pretty serious issue for quite an ordinary and common use case and hasn't been solved for a while now. Is it being worked on?
Use This <Pie isAnimationActive={false} isUpdateAnimationActive={true} data={props.data} dataKey="value" nameKey="name" labelLine={({ cx, cy, midAngle, innerRadius, outerRadius, value, index }) => { const RADIAN = Math.PI / 180;
// eslint-disable-next-line
let radius1 = 20 + innerRadius + (outerRadius - innerRadius);
let radius2 = innerRadius + (outerRadius - innerRadius);
// eslint-disable-next-line
let x2 = cx + radius1 * Math.cos(-midAngle * RADIAN);
// eslint-disable-next-line
let y2 = cy + radius1 * Math.sin(-midAngle * RADIAN);
let x1 = cx + radius2 * Math.cos(-midAngle * RADIAN);
// eslint-disable-next-line
let y1 = cy + radius2 * Math.sin(-midAngle * RADIAN);
if (value<30){
return null;
}
return(
<line x1={x1} y1={y1} x2={x2} y2={y2} stroke="#ccc" strokeWidth={1}>
</line>
)
}}
label={({
cx,
cy,
midAngle,
innerRadius,
outerRadius,
value,
index
}) => {
const RADIAN = Math.PI / 180;
// eslint-disable-next-line
let radius = 20 + innerRadius + (outerRadius - innerRadius);
// eslint-disable-next-line
let x = cx + radius * Math.cos(-midAngle * RADIAN);
// eslint-disable-next-line
let y = cy + radius * Math.sin(-midAngle * RADIAN);
if (value<30){
return null;
}
return (
<text
x={x}
y={y}
fill="#000"
fontWeight="300"
fontSize="13px"
fontFamily="'Source Sans Pro', 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'"
textAnchor={x > cx ? "start" : "end"}
dominantBaseline="central"
>
{props.data[index].name} {value}
</text>
);
}}
cx="50%"
cy="50%"
outerRadius="84%"
innerRadius="40%"
fill="#8884d8" >
{/* <LabelList dataKey="name" position="outside" /> */}
<Label value={100} position="center" fontSize={24} fontWeight={400}></Label>
</Pie>
@avinashsingh953 I assume your solution won't render label for value < 30
@avinashsingh953 I assume your solution won't render label for value < 30
Yes But you can adjust the value or calculate the angle for which labels can be hidden
@abishek28007 - what is the significance or reason for the number 15 in working out the delta variable in your solution? Thanks
@lxm7 15 and -1 are some arbitrary value which worked my use case, depending upon the use case they may change. I am trying to generalise it, any suggestion is appreciated.
I think this not only affects pie charts but also stacked bar charts and line charts.
I’d like to bump this issue. Any solid solution would be appreciated
Hi. We are facing the same issue as well where the labels are getting overlapped. Any fix for this? Thanks.

We've been looking for a solution for some time; even considered implementing something ourselves, possibly using things like d3-labeler. All for naught; we finally changed the UI and implemented the information via a legend. Seems to me like the only reasonable solution at this point.
any update on this?
Automatically placing an arbitrary amount of labels for arbitrarily thin slices of a Pie is not reasonable.
Instead we could extend the label feature:
- to not show the label for slices smaller than X percent (possibly configurable) https://github.com/recharts/recharts/issues/490#issuecomment-469865402
- to add an option to only show the label on hover https://github.com/recharts/recharts/issues/490#issuecomment-543007483
Seems reasonable, @nikolasrieble ... and maybe a combination of the two: show the labels that can fit, and then add hover for the others. Because for our use case, we definitely want the users to see the percentage. Using a legend as we did turned out to work great: see it all at a glance, no matter how small.