Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pie chart labels are overlapping for same values.

Here I'm trying to create a pie chart using matplotlib python library. But the dates are overlapping if the values are same "0.0" multiple times.
My question is how I can display them separately.

Thanks.

enter image description here

This is what I tried:

from pylab import *

labels = [ "05-02-2014", "23-02-2014","07-02-2014","08-02-2014"]
values = [0, 0, 2, 10]
fig = plt.figure(figsize=(9.0, 6.10)) 
plt.pie(values, labels=labels, autopct='%1.1f%%', shadow=True)
plt.axis('equal')
show()
like image 439
Tanveer Alam Avatar asked Feb 14 '23 05:02

Tanveer Alam


1 Answers

You can adjust the label positions manually, although that results in a bit more code you would want to for such a simple request. You can detect groups of duplicate labels by examining the positions at which there are placed.

Here is an example with some random data replicating the occurrence of overlapping labels:

import matplotlib.pyplot as plt
import numpy as np
from collections import Counter
import datetime

# number slices of pie
num = 10

# generate some labels
dates = [datetime.datetime(2014,1,1) + datetime.timedelta(days=np.random.randint(1,20)) for i in range(num)]
labels = [d.strftime('%d-%m-%Y') for d in dates]

# generate some values
values = np.random.randint(2,10, num)

# force half of them to be zero
mask = np.random.choice(num, num // 2, replace=False)
values[mask] = 0

# pick some colors
colors = plt.cm.Blues(np.linspace(0,1,num))

fig, ax = plt.subplots(figsize=(9.0, 6.10), subplot_kw={'aspect': 1})
wedges, labels, pcts = ax.pie(values, colors=colors, labels=labels, autopct='%1.1f%%')


# find duplicate labels and the amount of duplicates
c = Counter([l.get_position() for l in labels])
dups = {key: val for key, val in c.items() if val > 1}

# degrees of spacing between duplicate labels
offset = np.deg2rad(3.)


# loop over any duplicate 'position'
for pos, n in dups.items():

    # select all labels with that position
    dup_labels = [l for l in labels if l.get_position() == pos]

    # calculate the angle with respect to the center of the pie
    theta = np.arctan2(pos[1], pos[0])

    # get the offsets
    offsets = np.linspace(-(n-1) * offset, (n-1) * offset, n)

    # loop over the duplicate labels
    for l, off in zip(dup_labels, offsets):

        lbl_radius = 1.3

        # calculate the new label positions
        newx = lbl_radius * np.cos(theta + off)
        newy = lbl_radius * np.sin(theta + off)

        l.set_position((newx, newy))

        # rotate the label
        rot = np.rad2deg(theta + off)

        # adjust the rotation so its
        # never upside-down
        if rot > 90:
            rot += 180
        elif rot < -90:
            rot += 180

        # rotate and highlight the adjusted labels
        l.set_rotation(rot)
        l.set_ha('center')
        l.set_color('#aa0000')

I purposely only modified the overlapping labels to highlight the effect, but you could alter all labels in a similar way to create a uniform styling. The rotation makes it easier to automatically space them, but you could try alternate ways of placement.

Note that it only detect truly equal placements, if you would have values of [0, 0.00001, 2, 10], they would probably still overlap.

enter image description here

like image 80
Rutger Kassies Avatar answered Feb 23 '23 03:02

Rutger Kassies