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
import pandas as pd
color_dict = {
(2022, "Norway"): "#9194A3",
(2004, "Norway"): "#2B314D",
(2022, "Denmark"): "#E2AFA5",
(2004, "Denmark"): "#A54836",
(2022, "Sweden"): "#C4D6F8",
(2004, "Sweden"): "#5375D4",
}
xy_ticklabel_color, xlabel_color, grand_totals_color, grid_color, datalabels_color = (
"#7E8293",
"#7C8091",
"#101628",
"#B5B7C1",
"#2B314D",
)
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["year_lbl"] = "'" + df["year"].astype(str).str[-2:].astype(str)
df["sub_total"] = df.groupby("countries")["sites"].transform("sum")
# custom sort
sort_order_dict = {"Denmark": 1, "Sweden": 3, "Norway": 2, 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 | year_lbl | sub_total | color | |
|---|---|---|---|---|---|---|
| 1 | 2022 | Denmark | 10 | '22 | 14 | #E2AFA5 |
| 3 | 2022 | Norway | 8 | '22 | 13 | #9194A3 |
| 5 | 2022 | Sweden | 15 | '22 | 28 | #C4D6F8 |
| 0 | 2004 | Denmark | 4 | '04 | 14 | #A54836 |
| 2 | 2004 | Norway | 5 | '04 | 13 | #2B314D |
| 4 | 2004 | Sweden | 13 | '04 | 28 | #5375D4 |
groups = df.groupby("year", sort = False)
fig, ax = plt.subplots(figsize=(5, 5), facecolor="#FFFFFF")
fig.tight_layout(pad=3.0)
for year, group in groups:
ax.bar(
group.countries,
group.sites,
width=0.5
)
for bar, row in zip(ax.patches, df.itertuples()):
bar.set_facecolor(row.color)
ax.text(
bar.get_x() + bar.get_width() / 2,
bar.get_height() - 0.2 + bar.get_y(), # height
row.year_lbl,
ha="center",
va="top",
color="w",
weight="light",
)
fig
ax.axhline(
y = 0,
xmin = 0,
xmax = 1,
color = xy_ticklabel_color
)
common_tick_params = {
"which": "major",
"labelsize": 11,
"colors": xy_ticklabel_color,
"pad": 15
}
# hide ticks
ax.tick_params(axis = "x", length = 0, **common_tick_params)
ax.tick_params(axis = "y", **common_tick_params)
ax.set_ylim(0, 16)
ax.set_axisbelow(True) # set the grid lines in the BACK
ax.set_frame_on(False)
fig