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.
#tutorial
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import numpy as np
import pandas as pd
color_dict = {(2004,"Norway"): "#9194A3", (2022,"Norway"): "#2B314D",
(2004,"Denmark"): "#E2AFA5", (2022,"Denmark"): "#A54836",
(2004,"Sweden"): "#C4D6F8", (2022,"Sweden"): "#5375D4",
}
xy_ticklabel_color, ="#101628",
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('countries')['sites'].transform('sum')
#custom sort
sort_order_dict = {"Denmark":2, "Sweden":3, "Norway":1, 2004:5, 2022:4}
df = df.sort_values(by=['year','countries',], key=lambda x: x.map(sort_order_dict))
#Add the color based on the color dictionary
df['color'] = df.set_index(['year', 'countries']).index.map(color_dict.get)
df
| year | countries | sites | sub_total | color | |
|---|---|---|---|---|---|
| 3 | 2022 | Norway | 8 | 13 | #2B314D |
| 1 | 2022 | Denmark | 10 | 14 | #A54836 |
| 5 | 2022 | Sweden | 15 | 28 | #5375D4 |
| 2 | 2004 | Norway | 5 | 13 | #9194A3 |
| 0 | 2004 | Denmark | 4 | 14 | #E2AFA5 |
| 4 | 2004 | Sweden | 13 | 28 | #C4D6F8 |
Get the flags:
img = [
plt.imread("../flags/no-sq.png"),
plt.imread("../flags/de-sq.png"),
plt.imread("../flags/sw-sq.png")
]
Plot the chart¶
fig, ax = plt.subplots(figsize=(5,5),facecolor = "#FFFFFF")
fig.tight_layout(pad=3.0)
country = df.countries.nunique()
for year, group in df.groupby("year", sort = False):
#print(group['sites'])
ax.bar(
range(country),
group['sites'],
width = 0.2
)
for j, (bar, row) in enumerate(zip(ax.patches, df.itertuples())):
#print( j)
bar.set_facecolor(row.color)
ax.text(
bar.get_x() + bar.get_width() / 2 -0.3,
bar.get_height()+ bar.get_y()+0.2, #height
row.year,
ha="center",
va="top",
color = xy_ticklabel_color,
weight= "light"
)
if j >= 3:
print(j, row.sites)
ax.hlines(
y=row.sites,
xmin=bar.get_x(),
xmax=bar.get_x() + bar.get_width(),
color='w',
linewidth=2
)
fig
3 5 4 4 5 13
#set flags
ax.xaxis.set_ticks(range(country), ['', '', ''])
tick_labels = ax.xaxis.get_ticklabels()
for i,im in enumerate(img):
ib = OffsetImage(im, zoom=.04)
ib.image.axes = ax
ab = AnnotationBbox(
ib,
tick_labels[i].get_position(),
frameon=False,
box_alignment=(0.4, 2)
)
ax.add_artist(ab)
fig
ax.tick_params(axis='both', which='major', length=0, labelsize=14,colors= '#757C85',pad =15, labelleft = False)
max_sites = df.sites.max()
ax.set_ylim(0, max_sites + 1)
major_ticks = np.arange(0, max_sites + 1, 1)
ax.set_yticks(major_ticks)
ax.grid(True, axis='y', linestyle='solid', linewidth=1, color = "w")
ax.set_frame_on(False) #remove box
fig