Introdução

Neste projecto, imaginamo-nos como o analista contratado por um grande clube europeu. A equipa técnica quer utilizar os dados para melhorar o desempenho da equipa, tanto a nível individual com a nível colectivo. O objectivo aqui é maximizar o impacto de cada jogador e criar estratégias que permitam à nossa equipa superar os adversários.

Vamos trabalhar com dados reais de um jogo da Champions League e a tarefa é usar o R para desvendar padrões, identificar oportunidades e comunicar estes insights valiosos de forma clara e com auxílio visual.

Instalação e Carregamento de Pacotes

Primeiramente, instalamos os pacotes necessários e que iremos utilizar ao longo de todo o projecto. Após os termos instalados no nosso sistema, basta simplesmente carregar as bibliotecas

Carregamento das bibliotecas a utilizar

library(ggplot2)
library(readxl)
library(soccermatics)
library(ggConvexHull)
library(dplyr)

Carregar os dados

Vamos agora carregar os dados com os quais iremos trabalhar. A função read_excel() vai ler o ficheiro excel (xlsx) que está no nosso working directory e atribuí-lo a um data frame, denominado “dataset”.

dataset <- read_excel("MBDAF_ed7_M4_Atividade_Individual.xlsx")

Normalização dos dados

Para garantir que os dados estão normalizados e prontos a ser trabalhados, vamos fazer duas transformações. Primeiro, garantimos que os dados das posições x e y estão em formato numérico

# Garantir que coordenadas são numéricas
dataset$pos_x <- as.numeric(dataset$pos_x)
dataset$pos_y <- as.numeric(dataset$pos_y)


Segundo, ajustamos as coordenadas da equipa visitante (neste caso, o PSG). Vamos fazer uma inversão das coordenadas x e y, o que nos permitirá projectar em gráfico todas as acções e posições dos jogadores em sentido contrário. Teremos assim o Manchester City a atacar da esquerda para a direita, e o PSG atacará da direita para a esquerda. Também podem haver acções mal classificadas ou com erros ortográficos que iremos abordar.

dataset <- dataset %>%
  mutate(
    pos_x = if_else(Team == "PSG", 105 - pos_x, pos_x),   # Se a equipa for o PSG, fazemos a transformação das coordenadas x. Ao comprimento total do campo retiramos o valor da posição x registada. Isto resulta na posição no ponto oposto do campo, como que "espelhado"
    pos_y = if_else(Team == "PSG", 68 - pos_y, pos_y),    # O mesmo para as coordenadas y, mas desta vez retiramos o valor do y à largura do campo
    Action = if_else(Action == "Wide Shots", "Wide shot", Action) # Existem acções classificadas de forma semelhante, assim ficam iguais sob a mesma classificação
  )


Parte 1: Análise Individual

Na primeira parte deste projecto, vamos analisar o desempenho individual de 3 jogadores-chave neste jogo.

Acções Defensivas de Leandro Paredes

Nesta primeira análise, queremos estudar as acções defensivas de Leandro Paredes. Para isso, começaremos por definir um vector de acções defensivas e depois filtramos o nosso dataset para recolher os dados do jogador e as acções que sejam iguais às do nosso vector.

accoes_defensivas <- c("Challenges (won)", "Challenges (lost)", "Interceptions", "Picking-ups", 
                       "Tackles (Successful actions)", "Tackles (Unsuccessful actions)")

leandro_paredes_defensive_data <- dataset %>% 
  filter(code == "8. Paredes", Action %in% accoes_defensivas)

Agora estamos prontos para projectar o gráfico final

# Criar o gráfico das acções defensivas do Leandro Paredes
paredes_def_plot <- soccerPitch(# Usamos o soccerPitch() do pacote soccermatics, que já traz um visual apelativo de um campo de futebol
  theme = "grass",              # Indicamos que queremos o tema "grass" que nos mostra um campo relvado
  arrow = "l",                  # Indicação do sentido do ataque do jogador. Como é jogador do PSG e invertemos as suas coordenadas x e y, então será "l", indicando que ataca da direita para a esquerda 
  title = "Leandro Paredes - Acções Defensivas",  # Título do Gráfico
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)") + # Subtítulo com o contexto do jogo analisado
  
  # Juntamos os "data points" de interesse, ou seja, as acções defensivas do jogador e as suas coordenadas, colorindo cada acção com uma cor diferente
  geom_point(data = leandro_paredes_defensive_data, aes(x = pos_x, y = pos_y, colour = factor(Action)), size = 5) +
  
  
  # Com este código, removemos o título da legenda, deixando o gráfico mais limpo mas mantendo a perceptibilidade 
  labs(colour = NULL) +
  
  # Personalizar as cores para cada tipo de acção defensiva, destacando-as mais
  scale_colour_manual(values = c("orange", "green2", "skyblue1", "yellow2", "purple", "red")) + 
  
  # Ajustes à legenda
  theme(  
    legend.position = "inside", 
    legend.position.inside = c(0.182, 0.2),                 # Ajuste no posicionamento para o canto inferior esquerdo
    legend.text = element_text(size = 5, face = "bold"),    # Formatação do texto da legenda
    legend.box.background = element_rect(fill = "white", colour = "black"), # Colocação de uma text box para ficar mais perceptível
    legend.margin = margin(1.5, 1.5, 1.5, 1.5))

E visualizamos assim o resultado:

paredes_def_plot

Análise

Com o gráfico acima, conseguimos perceber que o jogador Leandro Paredes actuou principalmente em acções defensivas no seu meio campo defensivo, com ligeira tendência o lado direito. Isto faz sentido, sendo ele um médio-centro que normalmente joga mais descaído para o lado direito. Rapidamente identificamos que das 5 disputas de bola que participou, apenas perdeu uma. Efectuou também 5 tackles e foi bem sucedido em 4, mas o lance que perdeu foi numa zona frontal à sua baliza e muito perto da grande área - uma zona de alto risco. Destacam-se também as 4 recuperações de bola (picking-ups), tendo duas delas sido bem dentro do meio campo adversário.


Mapa de Percurso e Heatmap de Rodri

Nesta análise, queremos estudar as zonas do campo onde Rodri é mais influente. Perceber através do Path Map e do Heat Map quais as zonas onde este jogador executa mais acções, é essencial para perceber o seu estilo de jogo e contributo para o colectivo. Começamos por filtrar os dados que necessitamos para trabalhar - neste caso, filtramos todas as acções executadas pelo Rodri

rodri_dados <- dataset %>% filter(code == "16. Rodri")

De seguida, podemos criar o path map com os dados recolhidos

# Criar o gráfico de percurso do Rodri
rodri_action_map <- soccerPitch( # novo mapeamento do campo onde vamos inserir os dados
    theme = "grass", 
    arrow = "r",                 # como é um jogador do Man City, atacará da esquerda para a direita 
    title = "Mapa de Percurso do Rodri (*)",
    subtitle = "Man City vs PSG (Champions League - 24/11/2021)") +
  
  # Desenhamos as linhas que vão conectar cada acção entre as suas posições
  # Desenhamos as linhas a azul e definimos a espessura como 1
  geom_path(data = rodri_dados, aes(x = pos_x, y = pos_y), col = "blue", lwd = 1) +
  
  # Destacamos os pontos onde cada acção acontece, tornando mais perceptível a posição do jogador a cada acção
  # Marcamos estes pontos com uma cor idêntica à do equipamento do Man City e definimos o seu tamanho como 3
  geom_point(data = rodri_dados, aes(x = pos_x, y = pos_y), colour = "skyblue1", size = 3) + 
  
  # Legendas explicativas
  labs(caption = "*todas as acções realizadas no jogo") + # Adicionamos uma nota para completar o gráfico
  
  # Ajustes visuais à caption
  # Ajuste na posição horizontal, vertical, tamanho e colocar em itálico
  theme(plot.caption = element_text(hjust = 0.85, vjust = 35, size = 8, face = "italic"))

Agora, o heat map

# Criar o HeatMap de acções do Rodri, para percebermos melhor em que zonas do campo o jogador tem mais influência
rodri_heatmap <- soccerHeatmap(
  rodri_dados,        # Seleccionamos o data frame a trabalhar
  lengthPitch = 105,  # Definimos o comprimento do campo
  widthPitch = 68,    # Definimos a largura do campo
  xBins = 10,         # Definimos o número de zonas a destacar no eixo do x (10 zonas em todo o comprimento do campo)
  yBins = 10,         # Definimos o número de zonas a destacar no eixo do y (10 zonas em toda a largura do campo)
  kde = TRUE,         # Com o kernel density estimates a TRUE, o gráfico terá uma aparência mais "smooth" onde vemos efectivamente as zonas de calor do jogador, sem uma separação drástica por zonas
  arrow = "r",        # Como jogador do Man City, atacará da esquerda para a direita
  title = NULL,       # Excluímos o título, adicionaremos depois
  subtitle = NULL,    # Exluímos o subtítulo, adicionaremos depois
  x = "pos_x",        # Indicação da coluna que representa os dados do eixo do x
  y = "pos_y") +      # Indicação da coluna que representa os dados do eixo do y
  
  # Criar titulo, subtítulo e notas personalizadas
  labs(
    title = "Rodri Heatmap",
    subtitle = "Man City vs PSG (Champions League - 24/11/2021)",
    caption = "Mapa de calor, destacando áreas onde Rodri executou mais acções") +

  # Ajustes visuais às etiquetas definidas acima
  theme(
    plot.title = element_text(hjust = 0.5, vjust = -17, size = 16, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, vjust = -26, size = 10, face = "italic"),
    plot.caption = element_text(hjust = 0.85, vjust = 25, size = 8, face = "italic"))

Por fim, os resultados finais:

rodri_action_map

rodri_heatmap

Análise

Comparando os dois gráficos, conseguimos perceber que fazem ambos sentido. Numa equipa que normalmente joga muito avançada no terreno, parece natural ver o Rodri tão projectado e envolvido em acções no meio campo adversário. Vemos um equilibrio muito forte na zona central do terreno e percebemos bem o alcance das suas acções dentro da largura entre as grandes-áreas. No primeiro gráfico conseguimos ver como cada acção está interligada entre si, ao passo que no segundo vemos as zonas do terreno de jogo onde o Rodri foi mais influente. Analisando em conjunto, poderemos identificar quais os movimentos mais comuns dentro de cada zona e, identificando as possibilidades, poderá a nossa equipa estar preparada para contrariar estas acções e movimentações - prevenindo acções mais preponderantes do jogador, retirando-lhe influência no jogo.


Comparação de dribbles - Sterling vs Messi

Vamos agora analisar os dribbles destes 2 jogadores. Como se comparam no mesmo tipo de acções neste jogo? Começamos por definir o vector de acções que representam dribbles, e filtramos o dataset para cada jogador e acção

# Definimos as acções relativas a dribbles
action_dribbles <- c("Dribbles (Unsuccessful actions)", "Dribbles (Successful actions)")

# Guardamos um data frame apenas com os dribbles do Sterling
sterling_dribbles <- dataset %>%
  filter(code == "7. Sterling" & Action %in% action_dribbles)

# Guardamos um data frame apenas com os dribbles do Messi
messi_dribbles <- dataset %>%
  filter(code == "30. Messi" & Action %in% action_dribbles)

Criamos primeiro o mapa dos dribbles de Sterling

# Criar o gráfico de dribbles do Sterling
sterling_dribbles_plot <- soccerPitch(
  theme = "grass", 
  arrow = "r", 
  title = "Sterling - Eficácia de dribbles",
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)") +
  
  # Incluir a localização dos dribbles e identificar por bem ou mal sucedido
  geom_point(data = sterling_dribbles, aes(x = pos_x, y = pos_y, colour = factor(Action)), size = 5) + 
  
  # Atribuir cores a cada acção, de forma manual, para tornar o gráfico mais apelativo e dentro do esquema de cor do Man City
  scale_color_manual(values = c("skyblue1", "red1")) +
  
  # Excluir o título da legenda
  labs (color = NULL) + 
  
  # Introduzir uma etiqueta com a nota da taxa de sucesso dos dribbles
  # Ajustada a sua localização, cor e formatando a negrito
  annotate(
    "text", x = 94, y = 2, label = "Taxa de sucesso: 43%", color = "black", size = 3, fontface = "bold"
  ) + 
  
  # Ajustes aos titulos e subtitulos
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, size = 12, face = "italic"),
    legend.position = "inside",                                             # Posicionamento da legenda "dentro" do gráfico do campo                  
    legend.position.inside = c(0.801, 0.899),                                 # Ajuste no posicionamento para o canto superior direito
    legend.text = element_text(size = 6, face = "bold"),                    # Formatação do texto da legenda
    legend.box.background = element_rect(fill = "white", colour = "black"), # Colocação de uma text box para ficar mais perceptível
    legend.margin = margin(2,2,2,2)) 

E de seguida, o de Messi

messi_dribbles_plot <- soccerPitch(
  theme = "grass", 
  arrow = "l",                            # Como jogador do PSG, atacará da direita para a esquerda
  title = "Messi - Eficácia de dribbles",
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)") +
  
  # Incluir os pontos de localização dos dribbles do Messi
  geom_point(data = messi_dribbles, aes(x = pos_x, y = pos_y, colour = factor(Action)), size = 5) + 
  
  # Escolher as cores manualmente, de forma a linhar com o esquema de cores do PSG
  scale_color_manual(values = c("navyblue", "red1")) +
  
  # Excluir o título da legenda
  labs (color = NULL) + 

  # Introduzir uma etiqueta com a nota da taxa de sucesso dos dribbles
  # Ajustada a sua localização, cor e formatando a negrito  
  annotate(
    "text", x = 93, y = 2, label = "Taxa de sucesso: 100%", color = "black", size = 3, fontface = "bold"
  ) +  
  
  # Ajustes no título, subtítulo e legenda
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, size = 12, face = "italic"),
    legend.position = "inside",                                             # Posicionamento da legenda "dentro" do gráfico do campo                  
    legend.position.inside = c(0.808, 0.877),                               # Ajuste no posicionamento para o canto superior direito
    legend.text = element_text(size = 6, face = "bold"),                    # Formatação do texto da legenda
    legend.box.background = element_rect(fill = "white", colour = "black"), # Colocação de uma text box para ficar mais perceptível
    legend.margin = margin(2,2,2,2)) 

Por fim, vemos ambos os gráficos e analisamos.

sterling_dribbles_plot

messi_dribbles_plot

Análise

Se analisarmos simplesmente a taxa de eficácia dos dribbles de cada jogador, poderíamos facilmente inferir que o Messi (com 100% dos seus dribbles bem sucedidos) foi mais eficaz e preponderante nas acções da sua equipa do que o Sterling na sua (apenas 43% de eficácia). Mas estaria esta análise correcta? Analisando ambos os gráficos, podemos ver que sim, o Messi foi bem sucedido em todos os seus dribbles, mas tentou apenas 2 - um deles no círculo central ainda no seu meio campo defensivo, outro pouco dentro do meio campo adversário e muito perto da linha lateral. Já o Sterling foi mais audaz no número de tentativas de dribble (7), apesar de ter falhado 4. Mas destas 7, apenas 1 foi no meio campo defensivo e 3 foram dentro da grande área adversária! Podemos então, com estes gráficos, deduzir que o Sterling pode ter criado mais situações de perigo e que procura desafiar mais vezes o adversário no lado esquerdo do ataque, uma zona que lhe será certamente mais confortável. Se o defrontarmos, teremos de estar atentos às suas investidas pelo flanco esquerdo, onde procura também conduzir a bola e entrar na grande área para dribblar e procurar o remate.


Parte 2: Análise Colectiva

Finalizada a análise do desempenho individual, passamos agora para uma análise colectiva

Posicionamento Médio dos Jogadores Titulares

Na primeira fase da análise colectiva, vamos olhar para a posição média dos jogadores titulares de cada equipa e perceber de que forma ocupam o espaço de jogo. Agregaremos também um ConvexHull para melhor percepção do polígono posicional de cada equipa.

Começamos por criar os vectores com os jogadores titulares de cada equipa

# Definição dos jogadores titulares de cada equipa
mancity_starters <- c("31. Ederson", "2. Walker", "5. Stones", "3. R. Dias", "27. Cancelo", "7. Sterling", "11. Zinchenko", "16. Rodri", "26. Mahrez", "20. B. Silva", "8. Gundogan")

psg_starters <- c("1. K. Navas", "2. Hakimi", "5. Marquinhos", "3. Kimpembe", "8. Paredes", "7. Mbappe", "25. N. Tavares", "30. Messi", "27. Gueye", "10. Neymar", "21. A. Herrera")

Vamos filtrar o dataset para apenas as acções dos jogadores titulares e calcular a posição média de cada jogador. Aqui, faremos um group_by() por 2 colunas: por jogador e equipa. Isto permite-nos mostrar as duas equipas no mesmo gráfico

# Filtrar dados e criar novo data frame apenas com os dados dos titulares neste jogo
titulares_data <- dataset %>%
  filter(code %in% psg_starters | code %in% mancity_starters)

# Calculo da posição média dos jogadores titulares de ambas as equipas
titulares_posicao_media <- titulares_data %>%
  group_by(code, Team) %>% # Agrupamos por code (nome do jogador) e Team, para conseguirmos criar um único plot
  summarise(
    avg_x = mean(pos_x),   # Cálculo da posição média no eixo do x
    avg_y = mean(pos_y))   # Cálculo da posição média no eixo do y

Agora, vamos filtrar e separar os dados de cada equipa e criamos o ConvexHull de cada uma

# data frame filtrado apenas aos jogadores do Manchester City e novamente calculados os pontos médios
# Isto ajudará a criar correctamente o ConvexHull
mancity_posicao_media <- titulares_data %>%
  filter(Team == "Manchester City") %>%
  group_by(code) %>%
  summarise(
    avg_x = mean(pos_x),
    avg_y = mean(pos_y))

# Mesmo tratamento, desta vez para os jogadores do PSG
psg_posicao_media <- titulares_data %>%
  filter(Team == "PSG") %>%
  group_by(code) %>%
  summarise(
    avg_x = mean(pos_x),
    avg_y = mean(pos_y))

# Cálculo do ConvexHull do Manchester City
mancity_CHull <- mancity_posicao_media %>%
  slice(chull(avg_x, avg_y))

# Cálculo do ConvexHull do PSG
psg_CHull <- psg_posicao_media %>%
  slice(chull(avg_x, avg_y))

Terminamos com a produção do gráfico final onde mostramos ambas as equipas em campo, a posição média de cada jogador e adicionamos ainda o polígono do ConvexHull

# Criamos o gráfico com a posição média de cada jogador em campo
# Incluimos o ConvexHull
# Garantimos que aparecem as duas equipas em campo
# O Man City ataca da esquerda para a direita. O PSG ataca da direita para a esquerda
mancity_psg_convexhull <- soccerPositionMap(
  titulares_posicao_media,                                            # Utilizamos o dataframe com ambas as equipas         
  lengthPitch = 105,                                                
  widthPitch = 68,
  theme = "grass",
  fill1 = if_else(titulares_posicao_media$Team == "PSG", "navyblue", "skyblue1"), # Cores a atribuir ao preenchimento dos data points, personalizados por esquema de cores de cada equipa
  col1 = if_else(titulares_posicao_media$Team == "PSG", "red", "white"),          # Cores a atribuir à circunferência em volta dos data points, alinhado com as cores de cada equipa
  arrow = "none",                                                                 # Sem setas a indicar o sentido do ataque, já sabemos em que direcção ataca cada equipa
  title = "Posicionamento Médio e ConvexHull - Titulares da Partida",
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)",         
  x = "avg_x",                                                                    # Coluna com a informação do eixo do x
  y = "avg_y",                                                                    # Coluna com a informação do eixo do y
  id = "code") +                                                                  # Coluna com a informação do nome dos jogadores, que estará sobre cada data point
  
  # Colocação do ConvexHull do Man City
  geom_polygon(data = mancity_CHull, aes(x = avg_x, y = avg_y), alpha = 0.4, fill = "lightblue1")  +
  
  # Colocação do ConvexHull do PSG
  geom_polygon(data = psg_CHull, aes(x = avg_x, y = avg_y), alpha = 0.55, fill = "lightpink") 
mancity_psg_convexhull

Análise

Analisando a posição média e o ConvexHull de ambas as equipas, podemos ver de imediato que o Manchester City procurou jogar mais adiantado no terreno, pressionando mais o adversário - apenas 3 jogadores (!) estão posicionados no seu meio campo defensivo. Conseguimos perceber que os Citizens focaram-se mais na ala esquerda do seu ataque, tendo lá o Cancelo mais projectado para dar apoio ao Sterling e Zinchenko - Bernardo Silva, Rodri e Gundogan estão por perto mas numa zona central do terreno, deixando Mahrez mais isolado à direita. Do lado do PSG, vemos a equipa menos projectada no ataque (apenas 3 jogadores no meio campo adversário), o que mostra uma postura mais de expectativa, algo natural de uma equipa visitante. Apesar de adoptarem um 4-3-3 base, observando a posição média do Messi vemos que procura zonas centrais do terreno, onde pode vir buscar jogo entre linhas, apoiar no passe e abre espaço na ala direita para Hakimi, que está mais projectado na largura, poder investir. Temos de estar atento a este espaço criado pelo Messi, caso enfrentemos esta equipa.


Mapa de Passes de cada equipa

Vamos agora analisar o Pass Map de cada equipa, identificando os passes bem sucedidos e mal sucedidos. Devido ao elevado número de passes neste jogo, faremos 2 gráficos - um para cada equipa. Começamos mais uma vez por filtrar os dados necessários para cada equipa

# Filtrar para os jogadores do Man City e dentro das acções que representam passes bem sucedidos ou falhados
passes_mancity <- dataset %>%
  filter(Team == "Manchester City" & Action %in% c("Passes accurate", "Passes (inaccurate)"))

# Filtro para os mesmos dados, mas relativos ao PSG
passes_psg <- dataset %>%
  filter(Team == "PSG" & Action %in% c("Passes accurate", "Passes (inaccurate)"))

Para criar visualizações mais intuitivas e atractivas, vamos personalizar os gráficos com as cores de cada equipa e atribuir ícones diferentes para passes bem ou mal sucedidos

# Personalizar formas dos data points e cores (conforme esquema de cores de cada equipa)
shape_passes <- c("Passes accurate" = 19, "Passes (inaccurate)" = 13)
color_passes_mancity <- c("Passes accurate" = "skyblue1", "Passes (inaccurate)" = "darkred")
color_passes_psg <- c("Passes accurate" = "navyblue", "Passes (inaccurate)" = "darkred")

Criamos primeiro o Map Pass para o Manchester City

# Criar o gráfico para o PassMap do Manchester City
mancity_passmap <- soccerPitch(
  theme = "grass", 
  arrow = "r", 
  title = "PassMap - Manchester City",
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)") +
  
  # Colocamos os data points relativos aos passes do Man City,
  # colorindo e alterando a forma consoante o passe é bem ou mal sucedido
  geom_point(data = passes_mancity, aes(x = pos_x, y = pos_y, colour = factor(Action), shape = factor(Action)), size = 3) + 
  
  # Incluimos a personalização manual relativa à forma das acções dos passes
  scale_shape_manual(values = shape_passes) +
  
  # Incluimos a personalização manual relativa à cor, personalizado ao City
  scale_color_manual(values = color_passes_mancity) +
  
  # Eliminamos os títulos das legendas, para manter o gráfico mais clean
  labs(colour = NULL, shape = NULL) + 

  # Ajustes na legenda
  theme(
    legend.position = "inside",                                             # Posicionamento da legenda "dentro" do gráfico do campo                  
    legend.position.inside = c(0.831, 0.905),                               # Ajuste no posicionamento para o canto superior direito
    legend.text = element_text(size = 6, face = "bold"),                    # Formatação do texto da legenda
    legend.box.background = element_rect(fill = "white", colour = "black"), # Colocação de uma text box para ficar mais perceptível
    legend.margin = margin(1.5, 1.5, 1.5, 1.5)) 

E da mesma forma criamos para o PSG

# Fazemos o mesmo processo para o PSG
psg_passmap <- soccerPitch(
  theme = "grass", 
  arrow = "l", 
  title = "PassMap - PSG",
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)") +
  
  geom_point(data = passes_psg, aes(x = pos_x, y = pos_y, colour = factor(Action), shape = factor(Action)), size = 3) + 
  
  scale_shape_manual(values = shape_passes) +
  scale_color_manual(values = color_passes_psg) + 
  
  labs(colour = NULL, shape = NULL) +
  
  # Ajustes na legenda
  theme(
    legend.position = "inside",                                             # Posicionamento da legenda "dentro" do gráfico do campo                  
    legend.position.inside = c(0.831, 0.905),                               # Ajuste no posicionamento para o canto superior direito
    legend.text = element_text(size = 6, face = "bold"),                    # Formatação do texto da legenda
    legend.box.background = element_rect(fill = "white", colour = "black"), # Colocação de uma text box para ficar mais perceptível
    legend.margin = margin(1.5, 1.5, 1.5, 1.5)) 

Apresentamos ambos os gráficos.

mancity_passmap

psg_passmap

Análise

Olhando para estes visuais e conhecendo o estilo de jogo de Guardiola, é claro que o Manchester City executa muitos mais passes e com elevada taxa de sucesso. O que é interessante ver é a densidade de passes a acontecer no meio campo adversário e em particular na ala esquerda. Relembrando a nossa análise no ponto anterior, confirmamos que o City procurou focar neste lado do campo e jogar futebol apoiado, com passes mais curtos e movimentações rápidas para criação de espaços e oportunidades. No caso do PSG, vemos uma enorme quantidade de passes feitos dentro da sua própria grande-área! Isto pode ser indicativo da pressão elevada do City, que obriga a defesa parisiense a procurar passes mais rápidos para sair da pressão ou simplesmente troca a bola em posições recuadas pois não tem espaço mais à frente. De notar também que vemos mais passes bem dentro do meio campo adversário, do lado direito do ataque do PSG, o que pode corroborar a nossa suspeita da procura de Hakimi pelo espaço deixado nas costas por Lionel Messi. Vários indicadores a ter aqui em atenção, caso no futuro uma destas equipas apareça no nosso caminho!


Mapa de remates e xG de cada equipa

Para finalizar o projecto, vamos analisar os remates de cada equipa, de que posição foram realizados e os resultados de cada remate. Vamos também incluir o total de xG de cada equipa, como etiqueta no gráfico. Começamos por definir o vector de acções que geraram xG e filtramos o dataset para termos dados dos remates de cada equipa. Com estes dados, calculamos o total de xG de cada equipa, somando todos os valores.

# Recolher estas acções que têm um xG associado
remates_accoes <- c("Shots blocked", "Wide shot", "Shot on target", "Goals", "Shot into the bar/post")

# Filtrar o dataset para recolher os dados de xG do Man City e somar o total do xG para a equipa
# Descobrimos assim o total de xG para este jogo, informação que vamos utilizar como etiqueta
mancity_xg <- dataset %>%
  filter(Team == "Manchester City" & Action %in% remates_accoes) %>%
  group_by(Team) %>%
  summarise(total_xg = sum(xG))

# Filtrar o dataset para recolher os dados de xG do PSG e somar o total do xG para a equipa
# Descobrimos assim o total de xG para este jogo, informação que vamos utilizar como etiqueta
psg_xg <- dataset %>%
  filter(Team == "PSG" & Action %in% remates_accoes) %>%
  group_by(Team) %>%
  summarise(total_xg = sum(xG))

Filtramos agora os dados de ambas as equipa que se enquadrem nas acções definidas como remates. Assim conseguiremos mostrar remates de ambas as equipas no mesmo gráfico. Personalizamos também as formas de cada resultado de remate, bem como cores para cada equipa.

# Filtrar os dados de remates, dentro das acções definidas, para ambas as equipas
total_remates <- dataset %>%
  filter(Action %in% remates_accoes)

# Personalizar as formas para cada acção, preenchimentos e cores para irem de encontro ao esquema de cores das equipas
shape_xg <- c("Shots blocked" = 13, "Wide shot" = 24, "Shot on target" = 22, "Goals" = 19, "Shot into the bar/post" = 25)
fill_xg <- c("Manchester City" = "skyblue1", "PSG" = "navyblue")
color_xg <- c("Manchester City" = "gold", "PSG" = "red")

Como já transformamos as coordenadas de cada equipa no início do projecto, sabemos que o Manchester City ataca da esquerda para a direita e por isso os remates feitos aparecerão no lado direito - a baliza defendida pelo PSG. Já o PSG, que ataca em sentido contrário, terá os seus remates perto da baliza da esquerda - defendida pelo Man City.

# Criar o ShotMap final com ambas as equipas
# O Man City, como ataca da esquerda para a direita, tem as posições de remate mapeadas na baliza da direita
# Já o PSG, vai no sentido inverso
mancity_psg_shot_map <- soccerPitch(
  theme = "grass", 
  arrow = "none", 
  title = "Shot Map - Posição e Resultado dos Remates, por Equipa",
  subtitle = "Man City vs PSG (Champions League - 24/11/2021)") + 
  
  # Colocar as localizações dos remates, colorindo e alterando a forma conforme a equipa e acção
  geom_point(data = total_remates, mapping = aes(x = pos_x, y = pos_y, shape = factor(Action), fill = factor(Team), colour = factor(Team)), size = 5)+
  
  # Personalização dos data points (formas, cores e preenchimentos)
  scale_shape_manual(values = shape_xg) + 
  scale_fill_manual(values = fill_xg) + 
  scale_color_manual(values = color_xg) +
  
  # Personalização dos títulos das etiquetas
  labs(fill = NULL, colour = NULL, shape = NULL) + 
  
  # Etiquetas extra para conseguirmos ver o total de xG do PSG e do Man city
  annotate(
    "text", x = 8, y = 56, label = paste("PSG xG: ",psg_xg$total_xg), color = "navyblue", size = 3.5, fontface = "bold"
  ) + 
  
  annotate(
    "text", x = 94, y = 56, label = paste("Man City xG: ",mancity_xg$total_xg), color = "skyblue1", size = 3.5, fontface = "bold"
  ) +
  
  
  # Ajustes na legenda
  theme(
    legend.position = "inside",                                             # Posicionamento da legenda "dentro" do gráfico do campo                  
    legend.position.inside = c(0.5, 0.23),                                 # Ajuste no posicionamento para o centro inferior
    legend.text = element_text(size = 6, face = "bold"),                    # Formatação do texto da legenda
    legend.box.background = element_rect(fill = "white", colour = "black"), # Colocação de uma text box para ficar mais perceptível
    legend.margin = margin(1.5, 1.5, 1.5, 1.5)) 

O Gráfico final:

mancity_psg_shot_map

Análise

Para finalizar o nosso projecto, a análise aos remates e xG deste jogo. Do lado do PSG, vemos que fizeram 7 remates - 3 não acertaram o alvo e 2 foram bloqueados. Apenas 2 foram no sentido da baliza e um deles resultou mesmo em golo. A equipa francesa acaba o jogo com um xG de 0.83, tendo assim marcado mais golos do que seria de esperar, considerando o tipo de remates efectuados. Já a equipa inglesa totalizou 14 remates - 9 deles dentro da grande área! Dos 5 remates na direcção da baliza, 2 encontraram o caminho para o golo, dando assim a vitória por 2-1 à equipa da casa - o Manchester City terminou então o jogo com um xG de 2.43.


Conclusão

Finalizada a análise deste jogo, a nossa equipa técnica tem então mais informações relevantes para ajudar na preparação dos jogadores para o próximo embate frente a qualquer uma destas equipas. Conseguimos não só obter insights valiosos relativamente a jogadores-chave e com muito peso na productividade, mas também detectar padrões de estratégia de jogo e abordagem táctica destas equipas - o que nos permitirá fazer ajustes tecnico-tácticos que possam contra-atacar as investidas adversárias, bem como explorar as lacunas apresentadas pelo Manchester City ou pelo PSG.