92 of 100: Stacked triangle chart in matplotlib
At the beginning of the year I challenged myself to create all 100 visualizations using python and matplotlib from the 1 dataset,100 visualizations project and I am sharing with you the code for all the visualizations.
Note: Data Viz Project is copyright Ferdio and available under a Creative Commons Attribution – Non Commercial – No Derivatives 4.0 International license. I asked Ferdio and they told me they used a Design tool to create all the plots.
Collaborate
There are a ton of improvements that can be made on the code, so let me know in the comments any improvements you make and I will update the post accordingly!
To be improved: Heavily hardcoded, need to automate.
This is the original viz that we are trying to recreate in matplotlib:

Import the packages
We will need the following packages:
import matplotlib.pyplot as plt
import pandas as pd
Generate the data
We could actually go from numpy to matplotlib, but most data projects use pandas to transform the data, so I am using a pandas dataframe as the starting point.
color_dict = {"Norway": "#2B314D", "Denmark": "#A54836", "Sweden": "#5375D4", }
code_dict = {"Norway": "NO", "Denmark": "DK", "Sweden": "SE", }
data = {
"year": [2004, 2022, 2004, 2022, 2004, 2022],
"countries" : ["Sweden", "Sweden", "Denmark", "Denmark", "Norway", "Norway"],
"sites": [13,15,4,10,5,8]
}
df= pd.DataFrame(data)
index | year | countries | sites |
---|---|---|---|
0 | 2004 | Sweden | 13 |
1 | 2022 | Sweden | 15 |
2 | 2004 | Denmark | 4 |
3 | 2022 | Denmark | 10 |
4 | 2004 | Norway | 5 |
5 | 2022 | Norway | 8 |
We need to add country codes and then sort the data.
df['ctry_code'] = df.countries.map(code_dict)
df = df.sort_values([ 'year', 'sites'], ascending=True ).reset_index(drop=True)
#map the colors of a dict to a dataframe
df['color']= df.countries.map(color_dict)
Define the variables
codes = df.ctry_code.unique()
sites =df.sites
years = df.year.unique()
colors = df.color.unique()
Plot the chart
fig, ax = plt.subplots(figsize=(7,7), facecolor = "#FFFFFF" )
ax.fill_betweenx(y=[17, 22], x1=[6,9], x2=[12,9], color=colors[0])
ax.fill_betweenx(y=[13, 17], x1=[3.5,6], x2=[14.5,12], color=colors[1])
ax.fill_betweenx(y=[0, 13], x1=[-4.5,3.5], x2=[22.5,14.5], color=colors[2])
distance = 50
ax.fill_betweenx(y=[25, 33], x1=[4+distance,9+distance], x2=[14+distance,9+distance], color=colors[0])
ax.fill_betweenx(y=[15, 25], x1=[-1.5+distance,4+distance], x2=[19.5 +distance,14+distance], color=colors[1])
ax.fill_betweenx(y=[0, 15], x1=[-9+distance,-1.5+distance], x2=[28.5 +distance,19.5+distance], color=colors[2])
y1= [(22-17)/2+16, (17-13)/2+13, 13/2,]
y2 = [ (33-25)/2+24, (25-15)/2+15,15/2,]
x1 = [3,1,-4]
x2 = [52, 47,41]
for site1, site2, y1, y2, x1 ,x2, code, color in zip(sites[:3],sites[-3:], y1, y2,x1,x2,codes, colors):
print(code, y1)
ax.text(9, y1, site1, fontsize=12, color="white", ha="center")
ax.text(59, y2, site2, fontsize=12, color="white", ha="center")
ax.text(x1, y1, code, fontsize=12, color=color, ha="center")
ax.text(x2, y2, code, fontsize=12, color=color, ha="center")
ax.xaxis.set_ticks([9,59], years)
ax.tick_params(length=0)
ax.set_yticks([])
ax.spines[['left', 'right', 'top','bottom']].set_visible(False)
The result:

Reader Interactions