Search code examples
pythonmatplotlibpie-chart

Adding labels within a pie chart in Python by optimising space


I have a dataframe such as :

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# Sample data
data = {
    'genus': ['SpeciesA', 'SpeciesB', 'SpeciesC', 'SpeciesD', 'SpeciesE', 'SpeciesF', 'SpeciesG', 'SpeciesH'],
    'count': [10, 2, 1, 1, 1, 1, 1, 1],
    'Type': ['Animal', 'Environment', 'Environment', 'Environment', 'Animal', 'Animal', 'Animal/Environment', 'Animal/Environment']
}

# Create DataFrame
df = pd.DataFrame(data)

>>> df

      genus  count                Type
0  SpeciesA     10              Animal
1  SpeciesB      2         Environment
2  SpeciesC      1         Environment
3  SpeciesD      1         Environment
4  SpeciesE      1              Animal
5  SpeciesF      1              Animal
6  SpeciesG      1  Animal/Environment
7  SpeciesH      1  Animal/Environment

And I would like using python to create a pie chart were the piechart is divided into each Type proportional to its total count

So far I can do that using :

# Group by 'Type' and sum up 'count' within each group
type_counts = df.groupby('Type')['count'].sum()

# Create pie chart
plt.figure(figsize=(8, 8))
plt.pie(type_counts, labels=type_counts.index, startangle=140)
plt.title('Distribution of Counts by Type')
plt.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
plt.show()

enter image description here

But I am now looking for a way to add the genus labels within the specific sub-pie chart part.

Such labels should be included in this way (A):

In such a way that the labels are placed randomly in the corresponding pie chart without overlapping by optimizing the space.

Or, if it is impossible to simply place them in this way (B):

enter image description here


Solution

  • import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    
    data = {
        'genus': ['SpeciesA', 'SpeciesB', 'SpeciesC', 'SpeciesD', 'SpeciesE', 'SpeciesF', 'SpeciesG', 'SpeciesH'],
        'count': [10, 2, 1, 1, 1, 1, 1, 1],
        'Type': ['Animal', 'Environment', 'Environment', 'Environment', 'Animal', 'Animal', 'Animal/Environment', 'Animal/Environment']
    }
    
    df = pd.DataFrame(data)
    plt.figure(figsize=(20, 20))
    fig, ax = plt.subplots()
    
    size = 0.45
    cmap = plt.get_cmap("tab20c")
    outer_colors = cmap(np.arange(3)*4)
    inner_colors = cmap(np.array([1, 2, 5, 6, 9, 10, 11, 12]))
    
    ax.pie(df.groupby('Type', sort=False)['count'].sum(), colors=outer_colors, radius=1,  labels=df['Type'].drop_duplicates(),  autopct='%.0f%%', textprops={'size': 'smaller'},        pctdistance = 1.1, 
            labeldistance = 1.2,)
    ax.pie(df['count'], radius=1-size, colors=inner_colors, labels=df['genus'],  autopct='%.0f%%', textprops={'size': 'smaller', 'color':"w"}, labeldistance=1, rotatelabels = 270)
    plt.show()
    

    Output:

    enter image description here