69 of 100: Bar chart in a map 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!
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 matplotlib as mpl
from matplotlib.lines import Line2D
from svgpathtools import svg2paths
from svgpath2mpl import parse_path
import pandas as pd
import geopandas as gpdGenerate 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 = { 2022: "#A54836", 2004: "#5375D4", }
xy_ticklabel_color, grand_totals_color, grid_color, datalabels_color ='#757C85',"#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)| 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 create the colors for each year and then sort the data.
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))
df['ctry_code'] = df.countries.astype(str).str[:2].astype(str).str.upper()
#map the colors of a dict to a dataframe
df['color']= df.year.map(color_dict)| 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 |
Add 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']) ]Create the marker for the cylinder
icon_path, attributes = svg2paths('flags/cylinder-svgrepo-com2.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))Add the variables
years = df.year.unique()
countries = df.countries.unique()
colors = df.color.unique()
lat= [0.42,0.48,0.54]
lon =[0.24,0.14,0.28]Plot the chart
fig = plt.figure(figsize=(15,10))
ax_map = fig.add_axes([0, 0, 1, 1])
map_df.plot(color='#D3D3D3',ax=ax_map)
ax_map.set_axis_off()
for lt,ln,country, in zip(lat,lon,countries, ):
print(lat, lon)
ax_bar = fig.add_axes([lt ,ln , 0.03, 0.2])
temp_df = df[df.countries == country]
x = list(range(2))
y = temp_df.sites
for value, color, count in zip(x, colors, y):
ax_bar.plot([value]*count, list(range(count)), marker = icon_marker, ms=20, linestyle='', color=color)
#add data labels
ax_bar.text(value, count+1, count, ha= "center", color = "white",
bbox=dict(facecolor='black', edgecolor='black', boxstyle='round,pad=0.3'))
ax_bar.set(xlim = (-1,2), ylim=(-2,16))
ax_bar.set_yticklabels([])
ax_bar.set_xticklabels([])
ax_bar.grid(False)
ax_bar.set_frame_on(False)
ax_bar.tick_params(axis='both', which='both',length = 0)
#add legend
text_legends = ["Before", "After"]
colors = colors
lines = [Line2D([0], [0], color=c, marker=icon_marker,linestyle='', markersize=20,) for c in colors]
labels = [f'{text_legend} 2004' for text_legend in text_legends]
for year in years:
plt.figlegend( lines,labels,
labelcolor=xy_ticklabel_color,
bbox_to_anchor=(0.5, -0.05), loc="lower center",
ncols = 2,frameon=False, fontsize= 12)The result:

Reader Interactions