Hi!
The below graphs illustrate the pass relationships between different members of the Invincibles squad during the 03/04 season. The data comes from Statsbomb open data and covers the vast majority, although not all, games from that season.
A major weakness of the Invincibles was their reliance on Thierry Henry: for shots and goal involvements. with 30 goals and 6 assists, Henry was directly involved in 52% of the 69 goals scored across the season. 43% of shots on target came from him. The two matrices below can be used to investigate this weakness.
The matrix that includes all passes reveals the players that most often get the ball to Henry. Right back Ashley Cole and midfielder Patrick Vieira both get the ball to Henry regularly, but the vast majority of balls to Henry come from Robert Pirès. It is also worth noting that another common pass relationship is Ashley Cole to Pirès. Thus, the Invincible's MO is to get the ball from Cole to Henry via Pirès.
This reliance on Pirès to provide for Henry is also clear when looking specifically at key passes (passes that precede a shot), as shown in the second matrix. Henry receives 25 key passes from Pirès, 14 from Bergkamp, and 12 from Vieira. We can also see that when he's not executing chances, Henry is a key creator of opportunities for his teammates. Notably, 15 to Bergkamp and 12 to Pirès. Aside from Henry, Bergkamp, and Pirès, the rest of the team execute very few shots, reflecting a lack of diversity in the squad's attacking threat and reinforcing my claim that this is a key weakness of an otherwise fantastic side.
%%HTML
<script>
function luc21893_refresh_cell(cell) {
if( cell.luc21893 ) return;
cell.luc21893 = true;
console.debug('New code cell found...' );
var div = document.createElement('DIV');
cell.parentNode.insertBefore( div, cell.nextSibling );
div.style.textAlign = 'right';
var a = document.createElement('A');
div.appendChild(a);
a.href='#'
a.luc21893 = cell;
a.setAttribute( 'onclick', "luc21893_toggle(this); return false;" );
cell.style.visibility='hidden';
cell.style.position='absolute';
a.innerHTML = '[show code]';
}
function luc21893_refresh() {
if( document.querySelector('.code_cell .input') == null ) {
// it apeears that I am in a exported html
// hide this code
var codeCells = document.querySelectorAll('.jp-InputArea')
codeCells[0].style.visibility = 'hidden';
codeCells[0].style.position = 'absolute';
for( var i = 1; i < codeCells.length; i++ ) {
luc21893_refresh_cell(codeCells[i].parentNode)
}
window.onload = luc21893_refresh;
}
else {
// it apperas that I am in a jupyter editor
var codeCells = document.querySelectorAll('.code_cell .input')
for( var i = 0; i < codeCells.length; i++ ) {
luc21893_refresh_cell(codeCells[i])
}
window.setTimeout( luc21893_refresh, 1000 )
}
}
function luc21893_toggle(a) {
if( a.luc21893.style.visibility=='hidden' ) {
a.luc21893.style.visibility='visible';
a.luc21893.style.position='';
a.innerHTML = '[hide code]';
}
else {
a.luc21893.style.visibility='hidden';
a.luc21893.style.position='absolute';
a.innerHTML = '[show code]';
}
}
luc21893_refresh()
</script>
from statsbombpy import sb
%matplotlib inline
import json
from pandas.io.json import json_normalize
import numpy as np
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Arc, Rectangle, ConnectionPatch
from matplotlib.offsetbox import OffsetImage
import matplotlib.patches as mpatches
from functools import reduce
import plotly.graph_objects as px
import plotly.express as px
import plotly.graph_objs as go
import warnings
from plotly.validators.scatter.marker import SymbolValidator
#sb.matches(competition_id=2, season_id=44)
%%capture --no-display
#get invincibles season open data from Statsbomb
#sb.competitions()
matches_0304_df = sb.matches(competition_id=2, season_id=44)
matchid_list = matches_0304_df["match_id"].tolist()
#print(matchid_list)
seasonevents_df = sb.events(match_id=3749052)
seasonevents_df = seasonevents_df[0:0]
#print(seasonevents_df)
for i in matchid_list:
events_df = sb.events(match_id=i)
seasonevents_df = seasonevents_df.append(events_df)
arsenal_passes_df = seasonevents_df[(seasonevents_df.type == "Pass") & (seasonevents_df.possession_team == "Arsenal")]
arsenal_shots_df = seasonevents_df[(seasonevents_df.type == "Shot") & (seasonevents_df.possession_team == "Arsenal")]
ars_count_passes_df = arsenal_passes_df[['player', 'pass_recipient']]
ars_players = ["Ashley Cole", "Dennis Bergkamp", "Patrick Vieira", 'Thierry Henry', 'Sulzeer Jeremiah "Sol" Campbell', "Robert Pirès ", "Jens Lehmann", "Eduardo César Daude Gaspar", "Kolo Habib Touré", "Gilberto Aparecido da Silva", "Laureano Bisan-Etame Mayer", "Ray Parlour", "Fredrik Ljungberg"]
ars_count_passes_df = ars_count_passes_df.value_counts().to_frame('Count').reset_index()
ars_count_passes_df = ars_count_passes_df[ars_count_passes_df['player'].isin(ars_players)]
ars_count_passes_df = ars_count_passes_df[ars_count_passes_df['pass_recipient'].isin(ars_players)]
#print(ars_count_passes_df)
ars_pivot_df = ars_count_passes_df.pivot("player", "pass_recipient", "Count")
fig = px.imshow(ars_pivot_df, aspect="Auto", color_continuous_scale='Inferno')
fig.update_layout(
xaxis_title="Recipient",
yaxis_title="Passer",
title="Arsenal 03/04: Pass Matrix (1000mins+ played)",
)
fig.show()
shot_ending = arsenal_shots_df[(arsenal_shots_df.type == "Shot")]
kp_list = shot_ending["shot_key_pass_id"].tolist()
arsenal_kp_df = arsenal_passes_df[arsenal_passes_df['id'].isin(kp_list)]
ars_count_kp_df = arsenal_kp_df[['player', 'pass_recipient']]
ars_players = ["Ashley Cole", "Dennis Bergkamp", "Patrick Vieira", 'Thierry Henry', 'Sulzeer Jeremiah "Sol" Campbell', "Robert Pirès ", "Jens Lehmann", "Eduardo César Daude Gaspar", "Kolo Habib Touré", "Gilberto Aparecido da Silva", "Laureano Bisan-Etame Mayer", "Ray Parlour", "Fredrik Ljungberg"]
ars_count_kp_df = ars_count_kp_df.value_counts().to_frame('Count').reset_index()
ars_count_kp_df = ars_count_kp_df[ars_count_kp_df['player'].isin(ars_players)]
ars_count_kp_df = ars_count_kp_df[ars_count_kp_df['pass_recipient'].isin(ars_players)]
#print(ars_count_passes_df)
ars_pivot_kp_df = ars_count_kp_df.pivot("player", "pass_recipient", "Count")
fig = px.imshow(ars_pivot_kp_df, aspect="Auto", color_continuous_scale='Portland')
fig.update_layout(
xaxis_title="Recipient",
yaxis_title="Passer",
title="Arsenal 03/04: Key Pass Matrix (1000mins+ played)",
)
fig.show()