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 matplotlib.lines import Line2D
from svgpathtools import svg2paths
from svgpath2mpl import parse_path
import pandas as pd
import geopandas as gpd
color_dict = { 2022: "#A54836", 2004: "#5375D4"}
xy_ticklabel_color, grand_totals_color, grid_color, datalabels_color, color_map ='#757C85',"#101628", "#C8C9C9", "#FFFFFF", "#D3D3D3"
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)
#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))
#map the colors of a dict to a dataframe
df['color']= df.year.map(color_dict)
df
| year | countries | sites | color | |
|---|---|---|---|---|
| 3 | 2022 | Norway | 8 | #A54836 |
| 1 | 2022 | Denmark | 10 | #A54836 |
| 5 | 2022 | Sweden | 15 | #A54836 |
| 2 | 2004 | Norway | 5 | #5375D4 |
| 0 | 2004 | Denmark | 4 | #5375D4 |
| 4 | 2004 | Sweden | 13 | #5375D4 |
Get the map¶
map_df = gpd.read_file("https://raw.githubusercontent.com/eurostat/Nuts2json/master/pub/v2/2021/3035/20M/0.json")
map_df['country'] = map_df['id'].astype(str).str[:2]
map_df = map_df[map_df.country.isin(['NO','SE', 'DK']) ]
map_df
c:\Users\Ruth Pozuelo\Documents\SynologyDrive\100-matplotlib\.venv\Lib\site-packages\pyogrio\geopandas.py:275: UserWarning: More than one layer found in '0.json': 'nutsrg' (default), 'nutsbn', 'cntrg', 'cntbn', 'gra'. Specify layer parameter to avoid this warning. result = read_func(
| id | na | geometry | country | |
|---|---|---|---|---|
| 33 | DK | Danmark | MULTIPOLYGON (((4649929.995 3564341.094, 46459... | DK |
| 34 | SE | Sverige | MULTIPOLYGON (((4968534.919 4802763.317, 49724... | SE |
| 36 | NO | Norge | MULTIPOLYGON (((5121937.289 5303632.941, 51295... | NO |
Plot the map¶
Plot the map on its own axes: ax_map
fig = plt.figure(figsize=(15,10))
ax_map = fig.add_axes([0, 0, 1, 1])
map_df.plot(color=color_map,ax=ax_map)
ax_map.set_axis_off()
Plot the bar charts on the map¶
First define the coordinates of the bars:
lat= [0.42,0.48,0.54]
lon =[0.24,0.14,0.28]
Define the marker:
icon_path, attributes = svg2paths('../flags/cylinder-svgrepo-com.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))
Plot the markers on its own axes: ax_bar:
for i, (country, group) in enumerate(df.groupby("countries", sort = False)):
axes_height = 0.2
axes_width = 0.03
#add the axes at lat and lon
ax_bar = fig.add_axes([lat[i] ,lon[i] , axes_width, axes_height])
#styling
ax_bar.set(xlim = (-1,2), ylim=(-2,17))
ax_bar.grid(False)
ax_bar.set_frame_on(False)
ax_bar.tick_params(
axis='both',
which='both',
length = 0,
labelleft = False,
labelbottom = False)
for idx, row in enumerate(group.itertuples()):
count = row.sites
base_list = list(range(count)) #create sequence to plot
#offset the bars for the first group
if idx == 0 and count > 0:
base_list = base_list[1:] + [base_list[-1] + 1]
ax_bar.plot(
[idx] * count ,
base_list,
marker = icon_marker,
ms=20,
mec = "w",
linestyle='',
color=row.color
)
#add the data labels
offset = 0.3 if idx == 0 else -0.8
ax_bar.text(
idx ,
count + offset,
count,
size = 8,
ha= "center",
color = "w"
)
fig
Add legend¶
years = df.year.unique()
print(years)
colors = df.color.unique()
lines = [Line2D([0], [0], color=c, marker=icon_marker, mec = "w", linestyle='', markersize=20,) for c in colors]
fig.legend(
lines,
years,
labelcolor=xy_ticklabel_color,
bbox_to_anchor=(0.75, 0.1),
loc="lower center",
frameon=False,
labelspacing = 1.5,
fontsize= 10
)
fig
[2022 2004]