Generate the data and import packagesΒΆ
First, we need to create the data. I'll start by defining it as a dictionary and then convert it into a pandas DataFrame, since pandas is commonly used in many projects for data manipulation.
import matplotlib.pyplot as plt
import matplotlib as mpl
from svgpathtools import svg2paths
from svgpath2mpl import parse_path
from matplotlib.lines import Line2D
import numpy as np
import pandas as pd
import math
color_dict = { 2022: "#A54836", 2004: "#5375D4"}
xy_ticklabel_color, legend_color, grid_color, datalabels_color ='#101628',"#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['diff']=df.groupby('countries')['sites'].diff().fillna(df.sites).astype(int)
df['sub_total'] = df.groupby('countries')['diff'].transform('sum')
#custom sort
sort_order_dict = {"Denmark":2, "Sweden":1, "Norway":3, 2004:5, 2022:4}
df = df.sort_values(by=['countries','year',], key=lambda x: x.map(sort_order_dict))
#map the colors of a dict to a dataframe
df['color']= df.year.map(color_dict)
df
| year | countries | sites | diff | sub_total | color | |
|---|---|---|---|---|---|---|
| 5 | 2022 | Sweden | 15 | 2 | 15 | #A54836 |
| 4 | 2004 | Sweden | 13 | 13 | 15 | #5375D4 |
| 1 | 2022 | Denmark | 10 | 6 | 10 | #A54836 |
| 0 | 2004 | Denmark | 4 | 4 | 10 | #5375D4 |
| 3 | 2022 | Norway | 8 | 3 | 8 | #A54836 |
| 2 | 2004 | Norway | 5 | 5 | 8 | #5375D4 |
icon_path, attributes = svg2paths('../flags/Unesco_World_Heritage_logo_notext_transparent.svg')
#matplotlib path object of the icon
icon_marker = parse_path(attributes[0]['d'])
icon_marker.vertices -= icon_marker.vertices.mean(axis=0)
icon_marker = icon_marker.transformed(mpl.transforms.Affine2D().rotate_deg(180))
icon_marker = icon_marker.transformed(mpl.transforms.Affine2D().scale(-1,1))
max_sites = df.sub_total.max()
matrix_rows = 3
matrix_columns = math.ceil(max_sites/ matrix_rows)
#create the matrix
x = np.repeat(np.arange(1, matrix_columns + 1), matrix_rows)
y = np.tile(np.arange(1, matrix_rows + 1), matrix_columns)
fig, axes = plt.subplots(nrows=1, ncols=3,figsize=(8,4))
for ax, (country, group) in zip(axes.ravel(), df.groupby("countries")):
ax.invert_xaxis()
symbol_color = np.insert( np.repeat(group.color, group['diff']), 0, ["#FFFFFF"] * (max_sites - group.sub_total.iloc[0]))
ax.scatter(
y,
x,
marker=icon_marker,
s=800,
color= symbol_color
)
ax.set(xlim = (0,4), ylim = (0,6))
ax.set_title(
country,
weight= "bold",
color= xy_ticklabel_color
)
ax.axis('off')
#add legend
text_legends = ["Before", "After"]
years = df.year.unique()
lines = [Line2D([0], [0], color=c, marker=icon_marker,linestyle='', markersize=20,) for c in df.color.unique()]
labels = [f'{text_legend} 2004' for year, text_legend in zip(years, text_legends)]
for year in years:
fig.legend(
lines,labels,
labelcolor=legend_color,
bbox_to_anchor=(0.5, -0.05),
loc="lower center",
ncols = 2,
frameon=False,
fontsize= 12
)
fig