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.
from math import sqrt, sin, cos, pi
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
color_dict = {"Norway": "#2B314D", "Denmark": "#A54836", "Sweden": "#5375D4" }
xy_ticklabel_color, grand_totals_color, grid_color, datalabels_color ='#929EA7',"#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)
#custom sort
sort_order_dict = {"Denmark":2, "Sweden":1, "Norway":3}
df = df.sort_values(by=['countries',], key=lambda x: x.map(sort_order_dict))
#map the colors of a dict to a dataframe
df['color']= df.countries.map(color_dict)
df
| year | countries | sites | color | |
|---|---|---|---|---|
| 5 | 2022 | Sweden | 15 | #5375D4 |
| 4 | 2004 | Sweden | 13 | #5375D4 |
| 0 | 2004 | Denmark | 4 | #A54836 |
| 1 | 2022 | Denmark | 10 | #A54836 |
| 3 | 2022 | Norway | 8 | #2B314D |
| 2 | 2004 | Norway | 5 | #2B314D |
Function to create a sunflower effect and uniformly distribute points inside a circle:
phi = (1 + sqrt(5)) / 2 # golden ratio
def sunflower(n, alpha=0, geodesic=False):
points = []
angle_stride = 360 * phi if geodesic else 2 * pi / phi ** 2
b = round(alpha * sqrt(n)) # number of boundary points
for k in range(1, n + 1):
r = radius(k, n, b)
theta = k * angle_stride
points.append((r * cos(theta), r * sin(theta)))
return points
def radius(k, n, b):
if k > n - b:
return 1.0
else:
return sqrt(k - 0.5) / sqrt(n - (b + 1) / 2)
fig, axes = plt.subplots(ncols= 2, nrows = 3, figsize=(5,5),facecolor = "#FFFFFF")
fig.tight_layout(h_pad=5.0, w_pad = 1.0) #distance between plots
for ax, row in zip(axes.ravel(), df.itertuples()):
points = sunflower(row.sites, alpha = 2, geodesic= False)
xs = [point[0] for point in points]
ys = [point[1] for point in points]
ax.scatter(xs, ys, s= 60, color = row.color, clip_on= False)
ax.set_aspect('equal') # display as square plot with equal axes
ax.set_frame_on(False)
ax.tick_params(axis='both', which='major', length=0, labelbottom = False, labelleft = False)
Add the labels:
#add the country labels
for ax, country in zip(axes[:,0], countries):
ax.set_ylabel(country, rotation=0,size= 12, va= "top", color = xy_ticklabel_color, labelpad =63)
for ax, year in zip(axes[0], years):
ax.set_title(year, x=0.5, y=1.5, color = xy_ticklabel_color)
fig