I have a pie chart produced by the following code that crowds labels towards the top. Is there a better way to add labels and arrows so that there is no overlapping? I can't use a legend; I need the labels to be next to each slice.
I know in excel there is a "best fit" option that solves issues like this (
CodePudding user response:
We will not discuss whether it is suitable for visualization or not. Assuming that the order of the annotations can be different, we can reorder the numbers into the order of large and small, and change the order of the labels accordingly. This approach depends on the data and may be limited to this task. There may be a smarter way to reorder the data.
import matplotlib.pyplot as plt
import numpy as np
bbox_props=dict(boxstyle='square,pad=0.3',fc ='w',ec='k',lw=0.72)
kw=dict(xycoords='data',textcoords='data',arrowprops=dict(arrowstyle='-'),zorder=0,va='center')
fig1,ax1=plt.subplots()
labels=["first\n1.8%","second\n1.3%","third\n10.5%","fourth\n13.8%","fifth\n7.8%","sixth\n6.7%","seventh\n9.9%","eighth\n12.2%","ninth\n12.7%","tenth\n10.9%","eleventh\n7.6%","twelfth\n4.8%"]
values=[1.8,1.3,10.5,13.8,7.8,6.7,9.9,12.2,12.7,10.9,7.6,4.8]
# Add code
annotate_dict = {k:v for k,v in zip(labels, values)}
val = [[x,y] for x,y in zip(sorted(values, reverse=True),sorted(values))]
values1 = sum(val, [])
new_labels = []
for v in values1[:len(values)]:
for key, value in annotate_dict.items():
if v == value:
new_labels.append(key)
wedges,texts=ax1.pie(values1[:len(values)],explode=[0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01],labeldistance=1.2,startangle=90)
for i,p in enumerate(wedges):
ang=(p.theta2-p.theta1)/2. p.theta1
y=np.sin(np.deg2rad(ang))
x=np.cos(np.deg2rad(ang))
horizontalalignment={-1:"right",1:"left"}[int(np.sign(x))]
connectionstyle="angle,angleA=0,angleB={}".format(ang)
kw["arrowprops"].update({"connectionstyle":connectionstyle})
ax1.annotate(new_labels[i],xy=(x, y),xytext=(1.35*np.sign(x),1.4*y),
horizontalalignment=horizontalalignment,**kw)
plt.show()