1

I want to build a pie chart, however my labels keep overlapping (I have one large and ten small wedges). After some research I came across the answer to a similar question, however it does not work for me, this is the output: enter image description here

Is there a way to reliably annotate my pie chart such that the labels do not overlap or partly cross into the pie itself?

This is my code:

import matplotlib.pyplot as plt
import math

labels = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven"]
fig, ax = plt.subplots()
values = [574.51,
 272.3333,
 250.0,
 221.0,
 164.0,
 135.0,
 114.10000000000001,
 112.31708,
 100.0,
 91.8,
 2209.0827639999993]

l = ax.pie(values, startangle=-90)

for label, t in zip(labels, l[1]):
    x, y = t.get_position()
    angle = int(math.degrees(math.atan2(y, x)))
    ha = "left"
    va = "bottom"

    if angle > 90:
        angle -= 180

    if angle < 0:
        va = "top"

    if -45 <= angle <= 0:
        ha = "right"
        va = "bottom"

    plt.annotate(label, xy=(x,y), rotation=angle, ha=ha, va=va, size=8)
Till B
  • 1,248
  • 2
  • 15
  • 19
  • Just delete the line `ha = 'right`? Because it weirdly moves your 'three' and 'two' label. – JohanC Apr 08 '20 at 14:32
  • also pushes my 'eleven' label to the inside – Till B Apr 08 '20 at 14:35
  • also I have several more pie charts, where the labels are all over the place. I do not find a reliable way to label the chart with this pointing outwards style – Till B Apr 08 '20 at 14:35
  • For 'eleven', you could add `ha = 'right'`to the `if angle > 90:` case. This playing around with `angle` is rather weird. Atan2 gives angles between -180 and 180. So, setting `ha = 'left'`for angles between -90 and 90, and `ha = 'right'` otherwise seems to be enough? – JohanC Apr 08 '20 at 14:44

1 Answers1

3

Making a few changes will help this (and it ends up being easier than what you have): 1) use x to decide whether it's to the left or right around the chart, which isn't necessary, but it's less confusing than the angles; 2) use rotation_mode = "anchor" so the alignment occurs before the rotation; 3) rotate with va = "center".

Here's what the output looks like for me (where I've changed the data values so I can demo the alignment in all of the quadrants).

enter image description here

And the code:

labels = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven"]
fig, ax = plt.subplots()
values = [574.51,
 272.3333,
 1050.0,
 221.0,
 164.0,
 935.0,
 114.10000000000001,
 112.31708,
 100.0,
 91.8,
 2209.0827639999993]

l = ax.pie(values, startangle=-90)

for label, t in zip(labels, l[1]):
    x, y = t.get_position()
    angle = int(math.degrees(math.atan2(y, x)))
    ha = "left"

    if x<0:
        angle -= 180
        ha = "right"

    plt.annotate(label, xy=(x,y), rotation=angle, ha=ha, va="center", rotation_mode="anchor", size=8)
tom10
  • 67,082
  • 10
  • 127
  • 137