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:

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:

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
year | countries | sites | sub_total | pct_group | cumsum_pct | color | |
---|---|---|---|---|---|---|---|
0 | 2022 | Sweden | 15 | 33 | 45.454545 | 100.000000 | #5375D4 |
1 | 2022 | Norway | 8 | 33 | 24.242424 | 54.545455 | #2B314D |
2 | 2022 | Denmark | 10 | 33 | 30.303030 | 30.303030 | #A54836 |
3 | 2004 | Sweden | 13 | 22 | 59.090909 | 100.000000 | #5375D4 |
4 | 2004 | Norway | 5 | 22 | 22.727273 | 40.909091 | #2B314D |
5 | 2004 | Denmark | 4 | 22 | 18.181818 | 18.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)

Was this helpful?
Reader Interactions