Ben P
Ben P

Reputation: 31

Reliably avoiding legend overlapping other elements in matplotlib pie chart

I'm making a series of pie charts, and I'm looking for a way to automatically place the legend to avoid overlapping other elements (not just a manual intervention for each individual plot). For example:

fake_df = pd.DataFrame([70, 15, 15],
                   columns=['category'],
                   index=['Category Name 1', 'Category Name 2', 'Category Name 3'])
fake_df.plot.pie(y='category',
                 labels=None, 
                 autopct="%1.0f%%",
                 pctdistance=1.2,
)

enter image description here

I know that in this individual case I can explicitly assign the legend to 'upper left', or manually manipulate the placement of the legend or percentages in other ways to avoid the overlap, but that doesn't work for cases where the percentages show up in the upper left for example:

fake_df = pd.DataFrame([71, 15, 14],
                       columns=['category'],
                       index=['Category Name 1', 'Category Name 2', 'Category Name 3'])
fake_df.plot.pie(y='category',
                 labels=None, 
                 autopct="%1.0f%%",
                 pctdistance=1.2,
)
plt.legend(['Category Name 1', 'Category Name 2', 'Category Name 3'], loc='upper left')

enter image description here And since I'm automatically making a large amount of pie charts where there isn't a single legend placement that will always work and I can't know where the potential overlaps will be, I want a general solution that reliably places the legend such that it avoids the overlap. Is this possible?

Upvotes: 0

Views: 2218

Answers (2)

Cem Koçak
Cem Koçak

Reputation: 925

fake_df = pd.DataFrame([70, 15, 15],
                   columns=['category'],
                   index=['Category Name 1', 'Category Name 2', 'Category Name 3'])

ax = fake_df.plot.pie(y='category',
                 labels=None, 
                 autopct="%1.0f%%",
                 pctdistance=1.2,
)

plt.legend(labels=fake_df.index, bbox_to_anchor=(1.05, 1), loc='upper left')

EDIT AFTER YOU HAVE UPDATED YOUR ANSWER WITH PARTIAL OF THE ABOVE CODE:

You also need to use bbox_to_anchor parameter so that the legends placement does not overlap with the plot.

bbox_to_anchor : parameter tells matplotlib how to position the legend relative to the anchor point (bbox_to_anchor argument allows arbitrary placement of the legend).

loc : parameter tells matplotlib which corner of the legend should align with the anchor point

If you don't specify the loc argument it will take the default value of "best" which makes matplotlib determine the location itself. By assigning the value of "upper left" to that parameter you are telling matplotlib which corner of the legend box should align with the anchor point.

From documents https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.legend.html

enter image description here

Upvotes: 1

Ratislaus
Ratislaus

Reputation: 977

You could probably place each pandas pie chart in a matplotlib figure, setting the legend argument of the chart to None, while creating a figure legend like this:

import matplotlib.pyplot as plt
import pandas as pd

fig = plt.figure()
ax = fig.add_subplot()
fake_df = pd.DataFrame([71, 15, 14],
                       columns=['category'],
                       index=['Category Name 1', 'Category Name 2', 'Category Name 3'])
fake_df.plot.pie(y='category',
                 labels=None,
                 legend=None,
                 autopct="%1.0f%%",
                 pctdistance=1.2,
                 ax=ax
)
fig.legend(labels=fake_df.index)

plt.show()

The result:

enter image description here

Upvotes: 1

Related Questions