In [1]:
import pandas as pd

import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import matplotlib.patheffects as pe
from adjustText import adjust_text
In [2]:
df = pd.read_html("https://fbref.com/en/squads/e2befd26/Sassuolo-Stats", header=1)[0]
df["Min_pct"] = 100*df["90s"]/38 ##number of matches in a Serie A season
df = df.dropna(subset=["Age", "Min_pct"])
df = df.loc[:len(df)-1, :]
df[["Player", "Pos", "Age", "Min_pct"]].head()
Out[2]:
Player Pos Age Min_pct
0 Andrea Consigli GK 33.0 97.368421
1 Gian Marco Ferrari DF 28.0 88.157895
2 Manuel Locatelli MF 22.0 84.210526
3 Domenico Berardi FW,MF 25.0 72.368421
4 Filip Đuričić MF,FW 28.0 60.789474
In [3]:
line_color = "silver"
marker_color = "dodgerblue"

with plt.style.context("dark_background"):
    plt.rcParams['font.family'] = 'Palatino Linotype' ##set global font

    fig, ax = plt.subplots(figsize=(12, 8)) 
    
    ax.scatter(df["Age"], df["Min_pct"], s=220, zorder=10, 
               ec=line_color, fc=marker_color, alpha=0.8) ##scatter points
    ax.fill([24, 29, 29, 24], [-6, -6, 106, 106], color='limegreen',
            alpha=0.3, zorder=2) ##the peak age shaded region
    ax.text(26.5, 55, "PEAK", color=line_color, zorder=3, 
            alpha=0.2, fontsize=26, rotation=90, ha='center',
            va='center', fontweight='bold') ## `PEAK` age text
    
    texts = [] ##plot player names
    for row in df.itertuples():
        texts.append(ax.text(row.Age, row.Min_pct, row.Player, fontsize=8, ha='center', va='center', zorder=10))
    adjust_text(texts) ## to remove overlaps between labels
    
    ## update plot
    ax.set(xlabel="Age", ylabel="Share of Minutes Played", ylim=(-5, 105), xlim=(16, 40)) ## set labels and limits
    
    ##grids and spines
    ax.grid(color=line_color, linestyle='--', linewidth=0.8, alpha=0.5)   
    for spine in ["top", "right"]:
        ax.spines[spine].set_visible(False)
        ax.spines[spine].set_color(line_color)
        
    ax.yaxis.set_major_formatter(mtick.PercentFormatter())
    ax.xaxis.set_ticks(range(16, 44, 4)) ##fix the tick frequency 
    ax.xaxis.label.set(fontsize=12, fontweight='bold')
    ax.yaxis.label.set(fontsize=12, fontweight='bold') ## increase the weight of the axis labels
    
    ax.set_position([0.08, 0.08, 0.82, 0.78]) ## make space for the title on top of the axes
    
    ## title and subtitle
    fig.text(x=0.08, y=0.92, s="Sassuolo | Squad Age Profile", 
            ha='left', fontsize=24, fontweight='bold', 
            path_effects=[pe.Stroke(linewidth=3, foreground='0.15'),
                       pe.Normal()]) 
    fig.text(x=0.08, y=0.88, s="Serie A | 2020-21", ha='left', 
            fontsize=18, fontweight='bold', 
            path_effects=[pe.Stroke(linewidth=3, foreground='0.15'),
                       pe.Normal()])

fig.savefig("sassuolo-squad-age-profile", dpi=180)