Home > Blockchain >  Plotting many pie charts using a loop to create a single figure using matplotlib
Plotting many pie charts using a loop to create a single figure using matplotlib

Time:01-26

I'm having trouble converting a script I wrote to create and save 15 pie charts separately which I would like to save as a single figure with 15 subplots instead. I have tried taking fig, ax = plt.subplots(5, 3, figsize=(7, 7)) out of the loop and specifying the number of rows and columns for the plot but I get this error AttributeError: 'numpy.ndarray' object has no attribute 'pie'. This error doesn't occur if I leave that bit of code in the script as is seen below. Any help with tweaking the code below to create a single figure with 15 subplots (one for each site) would be enormously appreciated.

import pandas as pd
import matplotlib.pyplot as plt


df = pd.read_excel(path)
df_1 = df.groupby(['Site', 'group'])['Abundance'].sum().reset_index(name='site_count')

site = ['Ireland', 'England', 'France', 'Scotland', 'Italy', 'Spain',
'Croatia', 'Sweden', 'Denmark', 'Germany', 'Belgium', 'Austria', 'Poland', 'Stearman', 'Hungary']


for i in site:
    df_1b = df_1.loc[df_1['Site'] == i]
    colors = {'Dog': 'orange', 'Cat': 'cyan', 'Pig': 'darkred', 'Horse': 'lightcoral', 'Bird': 
    'grey', 'Rat': 'lightsteelblue', 'Whale': 'teal', 'Fish': 'plum', 'Shark': 'darkgreen'}

    wp = {'linewidth': 1, 'edgecolor': "black"}
    fig, ax = plt.subplots(figsize=(7, 7))
    texts, autotexts = ax.pie(df_1b['site_count'],
                                      labels=None,
                                      shadow=False,
                                      colors=[colors[key] for key in labels],
                                      startangle=90,
                                      wedgeprops=wp,
                                      textprops=dict(color="black"))

    plt.setp(autotexts, size=16)
    ax.set_title(site, size=16, weight="bold", y=0)
    plt.savefig('%s_group_diversity.png' % i, bbox_inches='tight', pad_inches=0.05, dpi=600)

CodePudding user response:

It's hard to guess how exactly you'd like the plot to look like.

The main changes the code below makes, are:

  • adding fig, axs = plt.subplots(nrows=5, ncols=3, figsize=(12, 18)). Here axs is a 2d array of subplots. figsize should be large enough to fit the 15 subplots.
  • df_1b['group'] is used for the labels that decide the color (it's not clear where the labels themselves should be shown, maybe in a common legend)
  • autopct='%.1f%%' is added to ax.pie(...). This shows the percentages with one decimal.
  • With autopct, ax.pie(...) now returns 3 lists: texts, autotexts, wedges. The texts are the text objects for the labels (currently empty texts), autotexts are the percentages (that are calculated "automatically"), wedges are the triangular wedges.
  • ax.set_title now uses the site name, and puts it at a negative y-value (y=0 would overlap with the pie)
  • plt.tight_layout() at the end tries to optimize the surrounding white space
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

site = ['Ireland', 'England', 'France', 'Scotland', 'Italy', 'Spain',
        'Croatia', 'Sweden', 'Denmark', 'Germany', 'Belgium', 'Austria', 'Poland', 'Stearman', 'Hungary']
colors = {'Dog': 'orange', 'Cat': 'cyan', 'Pig': 'darkred', 'Horse': 'lightcoral', 'Bird': 'grey',
          'Rat': 'lightsteelblue', 'Whale': 'teal', 'Fish': 'plum', 'Shark': 'darkgreen'}
wedge_properties = {'linewidth': 1, 'edgecolor': "black"}

# create some dummy test data
df = pd.DataFrame({'Site': np.random.choice(site, 1000),
                   'group': np.random.choice(list(colors.keys()), 1000),
                   'Abundance': np.random.randint(1, 11, 1000)})
df_1 = df.groupby(['Site', 'group'])['Abundance'].sum().reset_index(name='site_count')

fig, axs = plt.subplots(nrows=5, ncols=3, figsize=(12, 18))
for site_i, ax in zip(site, axs.flat):
    df_1b = df_1[df_1['Site'] == site_i]
    labels = df_1b['group']
    texts, autotexts, wedges = ax.pie(df_1b['site_count'],
                                      labels=None,
                                      shadow=False,
                                      colors=[colors[key] for key in labels],
                                      startangle=90,
                                      wedgeprops=wedge_properties,
                                      textprops=dict(color="black"),
                                      autopct='%.1f%%')
    plt.setp(autotexts, size=10)
    ax.set_title(site_i, size=16, weight="bold", y=-0.05)

plt.tight_layout()
plt.savefig('group_diversity.png', bbox_inches='tight', pad_inches=0.05, dpi=600)
plt.show()

grid of pie charts

  • Related