0
votes

I'm working on a personal budget visualization project to build my python competency and have hit a snag in how I want the pie chart to show data. Right now, I have a pie chart with the per-category spending and per-category budgeted spending that has category labels outside the pie chart. The labels are rotated to align with a ray from the center of the pie through the center of the wedge, using "rotatelabels = True" in plt.pie. This works great, but I want the percentage label that displays inside the wedge to also be rotated, so that both the category label and the percentage are parallel to the aforementioned ray. I've been able to rotate all the percentages by a given amount as in the post here: How can I improve the rotation of fraction labels in a pyplot pie chart , but I'd like to refine it to my goal. Any tips on working with text.set_rotation or other functions or parameters to achieve this?

Code snippet revised to function as standalone from project at large:

import pandas as pd
cat = ['Utilities', 'Home', 'Bike', 'Medical', 'Personal', 'Food', 'Groceries', 'Student Loans', 'Transit', 'Rent']
dict = {8:54.99,14:59.91,3:69.03,10:79.00,9:119.40,1:193.65,0:205.22,4:350.00,7:396.51,2:500.00}
nonzero_spending = pd.DataFrame(list(dict.items()), columns = ['index_col', 'Sum'])
plt.pie(nonzero_spending['Sum'],labels=cat,radius = 2,startangle = 160,autopct=lambda p : '{:.2f}%  ({:,.0f})'.format(p,p * sum(nonzero_spending['Sum'])/100), rotatelabels = True, pctdistance=0.8)
plt.title('Spending')
plt.axis('equal')
plt.show()
1

1 Answers

1
votes

You could extract the rotation of the outer label and apply it to the percentage text:

import matplotlib.pyplot as plt
import pandas as pd

cat = ['Utilities', 'Home', 'Bike', 'Medical', 'Personal', 'Food', 'Groceries', 'Student Loans', 'Transit', 'Rent']
dict = {8: 54.99, 14: 59.91, 3: 69.03, 10: 79.00, 9: 119.40, 1: 193.65, 0: 205.22, 4: 350.00, 7: 396.51, 2: 500.00}
nonzero_spending = pd.DataFrame(list(dict.items()), columns=['index_col', 'Sum'])
patches, labels, pct_texts = plt.pie(nonzero_spending['Sum'], labels=cat, radius=2, startangle=160,
                                     autopct=lambda p: f"{p:.2f}%  ({p * sum(nonzero_spending['Sum']) / 100:,.0f})",
                                     rotatelabels=True, pctdistance=0.5)
for label, pct_text in zip(labels, pct_texts):
    pct_text.set_rotation(label.get_rotation())
plt.title('Spending')
plt.axis('equal')
plt.tight_layout()
plt.show()

example plot

plt.pie() returns 3 lists (or 2 when there are no percentage texts):

  • A list of "Wedge patches" (the rounded triangular shapes)
  • A list of the text labels, as matplotlib Text objects
  • (Optionally) a list of the percentage texts (also Text objects)

for label, pct_text in zip(labels, pct_texts): is Python's way to loop through the two lists simultaneously.

pct_text.set_rotation(label.get_rotation()) fetches the rotation of each label Text object and sets this value as the rotation of the corresponding percentage text object.