Print

Proportion plots in matplotlib

In this tutorial I will show you how to create Proprtion plots using Python and Matplotlib. For more matplotlib charts, check out the gallery:

1 dataset 100 matplotlib visualizations
Python dataviz gallery, matplotlib viz gallery

Important notes:

1. This are my personal notes, so apologies if some explanations and notations are missing.

Proportion plots in matplotlib

This is what we will be creating:

21 of 100: Semicircular stacked bar chart in matplotlib

The notebook

Import the libraries

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.lines import Line2D

Add the necessary columns

color_dict ={"Norway": "#2B314D", "Denmark": "#A54836", "Sweden": "#5375D4", }

xy_ticklabel_color, label_color, grid_color, datalabels_color ='#757C85',"#101628", "#C8C9C9", "#FFFFFF"

data = {
    "year": [2004, 2022, 2004, 2022, 2004, 2022],
    "countries" : [ "Denmark", "Denmark", "Norway", "Norway","Sweden", "Sweden",],
    "sites": [4,10,5,8,13,15]
}
df= pd.DataFrame(data)

df['sub_total'] = df.groupby('year')['sites'].transform('sum')
df['pct_group'] = 100 * df['sites'] / df.sub_total

df['cumsum_pct'] = df.groupby('year')['pct_group'].transform(lambda x: x.cumsum())
df = df.sort_values(['year','cumsum_pct'], ascending=False ).reset_index(drop=True)

#map the colors of a dict to a dataframe
df['color']= df.countries.map(color_dict)
df
yearcountriessitessub_totalpct_groupcumsum_pctcolor
02022Sweden153345.454545100.000000#5375D4
12022Norway83324.24242454.545455#2B314D
22022Denmark103330.30303030.303030#A54836
32004Sweden132259.090909100.000000#5375D4
42004Norway52222.72727340.909091#2B314D
52004Denmark42218.18181818.181818#A54836

Define the variables

countries = df.countries.unique()
colors = df.color.unique()

Plot the chart

fig, ax = plt.subplots(figsize=(8,6), )

for color, country in zip(colors,countries):
    temp_df= df[df.countries ==country]
    x=temp_df.year
    y= temp_df.cumsum_pct
    ax.stackplot(x, y, ec = "k", color = color)
    
    direction = ["left","right"]*3
    offset = [0.5, -0.5]*3
    for x,y, dir, offset in zip(x, y, direction, offset):
        ax.annotate(f'{int(y)}%', xy=(x+offset, y),  ha= dir, va="center", color= color,annotation_clip=False)

ax.set_axis_off()


#add legend
lines = [Line2D([0], [0], color=c,  marker='s',linestyle='', markersize=10,) for c in reversed(colors)]

plt.legend(lines, reversed(countries), labelcolor = label_color,
           prop=dict(weight='light', size=10), 
           bbox_to_anchor=(0.5, -0.15), loc="lower center",
            ncols = 3,frameon=False, fontsize= 14)
21 of 100: Proportional stacked bar chart in matplotlib
Was this helpful?

Reader Interactions

Leave a Reply

Your email address will not be published. Required fields are marked *

Table of Contents