Index de l'article

Pie Chart

Simple pie

If you have a data-frame with fields Categories and Total, you can create a pie chart.

import matplotlib.pyplot as plt
 
chartLabel = df_Categories_count['Categories'].tolist()
chartValue = df_Categories_count['Total'].tolist()
 
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
 
fig1 = plt.figure()
plt.pie(chartValue, labels=chartLabel, colors=colors, autopct=None, shadow=False, startangle=90)
plt.axis('equal')
plt.title('Categories', pad=20, fontsize=15)
 
plt.show()
plt.clf()

Display percentages in the chart

Use autopct.

plt.pie(chartValue, labels=chartLabel, colors=colors, autopct='%1.1f%%', shadow=False, startangle=90)

Change the labels font size

plt.rcParams['font.size'] = 5

Hide a label in chart

Just replace the value with an empty string.

chartLabel[-1] = ''

Add a legend in your chart

plt.legend(chartLabel, loc='best', fontsize=8)

Explode

To explode your chart, you need to pass values in explode, example if you have 4 values to plot:

plt.pie(myValue, labels=myLabels, colors=colors, explode=[0.05, 0.05, 0.05, 0.05], autopct=None, shadow=False, startangle=90)

If you want explode all part by default, just create a list before:

explodeValues = []
for i in myValue:
    explodeValues.append(0.05)
 
plt.pie(myValue, labels=myLabels, colors=colors, explode=explodeValues, autopct=None, shadow=False, startangle=90)

Add a legend with several fields

For example you want display labels and percentages in the legend. First calculate percentages in another field in your data-frame, then:

import matplotlib.pyplot as plt
 
chartLabel = df_Categories_count['Categories'].tolist()
chartLegendLabel = df_Categories_count['Categories'].tolist()
chartValue = df_Categories_count['Total'].tolist()
chartLegendPercent = df_Categories_count['Percent'].tolist()
 
legendLabels = []
for i, j in zip(chartLegendLabel, map(str, chartLegendPercent)):
    legendLabels.append(i + ' (' + j + ' %)')
 
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
 
fig1 = plt.figure()
plt.pie(chartValue, labels=chartLabel, colors=colors, autopct=None, shadow=False, startangle=90)
plt.axis('equal')
 
plt.title('Categories', pad=20, fontsize=15)
plt.legend(legendLabels, loc='best', fontsize=8)
 
plt.show()
plt.clf()

Display only first labels around the plot

...
# Display only first indices in legend
def autopct_masque(index_mask):
    def format_pct(pct, allvals):
        index = format_pct.index
        format_pct.index += 1
        if index in index_mask:
            return '' # Masquer ce pourcentage
        return f'{pct:.1f}%'
    format_pct.index = 0
    return lambda pct: format_pct(pct, chartLegendPercent)
 
...
 
# Create plot
# Sort a DF previously calculating percentage
df_sorted = myDf.sort_values(by='Pourcentage', ascending=False).reset_index(drop=True)
 
chartLabel = df_sorted['fieldPreviouslyGroupedForPercentage'].tolist()
chartLegendLabel = df_sorted['fieldPreviouslyGroupedForPercentage'].tolist()
chartValue = df_sorted['Total'].tolist()
chartLegendPercent = df_sorted['Pourcentage'].tolist()
 
# Display only first indices
displayOnlyFirst = 4
calculHowManyToHide = len(chartLegendPercent) - displayOnlyFirst
hiddenIndices = list(range(len(chartLegendPercent) - calculHowManyToHide, len(chartLegendPercent)))
 
# Hide last indices
for i in hiddenIndices:
    chartLabel[i] = ''
 
explodeValues = [0.05] * len(chartValue)
 
legendLabels = []
for i, j in zip(chartLegendLabel, map(str, chartLegendPercent)):
    legendLabels.append(i + ' (' + j + ' %)')
 
# Colors
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
 
myFig = plt.figure()
 
# Get objects to hide indices and format plot
wedges, texts, autotexts = plt.pie(
    chartValue,
    labels=chartLabel,
    colors=colors,
    explode=explodeValues,
    autopct=autopct_masque(hiddenIndices),
    shadow=False,
    startangle=90,
    labeldistance=1
)
 
...

Customize text labels around the plot

# Customize labels around the plot
wordToDelete = 'Specialty'
 
for text in texts:
    ancien_texte = text.get_text()
    nouveau_texte = ancien_texte.replace(wordToDelete, '').strip()
    text.set_text(nouveau_texte)
 
for i, text in enumerate(texts):
    label = chartLabel[i]
    if label == 'Value1... blablabla':
        # text.set_color('blue')
        text.set_fontsize(9)
        # text.set_fontweight('bold')
        text.set_text('Value1\nblablabla')
 
    elif label == 'Value2... blablabla':
        text.set_text('Value2\nblablabla\nblablabla')
        text.set_fontsize(9)
 
    elif label == 'Value3... blablabla':
        text.set_text('Value3\nblablabla\nblablabla')
        text.set_fontsize(9)
 
    else:
        text.set_fontsize(9)
 
# Reduce percentage size font
for autotext in autotexts:
    autotext.set_fontsize(8)
 
plt.axis('equal')
plt.title('EDS Terminale 2', pad=20, fontsize=15)
 
myFig.savefig(downloadsDir+'myPlot.png', dpi=100)
plt.clf()
 
im = Image.open(downloadsDir+'myPlot.png')
bordered = ImageOps.expand(im, border=1, fill=(0, 0, 0))
bordered.save(downloadsDir+'myPlot.png')
 
# Insert in Excel
img = openpyxl.drawing.image.Image(downloadsDir+'myPlot.png')
img.anchor = 'E4'
 
workbook['An Excel tab'].add_image(img)
workbook.save(statsFile)
 
...
 
os.remove(downloadsDir + 'myPlot.png')

 

Liens ou pièces jointes
Télécharger ce fichier (France-Departements-Deformation.zip)France-Departements-Deformation.zip[France-Departements-Deformation]335 Ko
Télécharger ce fichier (simple_countries.zip)simple_countries.zip[simple_countries]1880 Ko