Skip to content

Instantly share code, notes, and snippets.

@OTStats
Created November 7, 2022 23:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OTStats/562472add29a1adbeac8b1295e9419e8 to your computer and use it in GitHub Desktop.
Save OTStats/562472add29a1adbeac8b1295e9419e8 to your computer and use it in GitHub Desktop.
# -- Created by Owen Thompson (@OTStats)
# 2022-09-29
# -- Load libraries
library(tidyverse)
library(ggtext)
library(ggforce)
library(lubridate)
library(worldfootballR)
library(glue)
library(ggimage)
library(showtext)
font_add_google("Lato")
showtext_auto()
# -- Import Data
spi_raw <- read_csv("https://projects.fivethirtyeight.com/soccer-api/club/spi_matches.csv")
# Prep data
matches <- spi_raw %>%
transmute(date,
league,
league_id,
team = team1,
opponent = team2,
teamGoal = score1,
oppGoal = score2,
result = case_when(score1 > score2 ~ "W",
score1 < score2 ~ "L",
score1 == score2 ~ "D"),
ha = "Home",
team_spi = spi1,
opponent_spi = spi2,
team_xg = xg1,
opponent_xg = xg2) %>%
bind_rows(
spi_raw %>%
transmute(date,
league,
league_id,
team = team2,
opponent = team1,
teamGoal = score2,
oppGoal = score1,
result = case_when(score1 < score2 ~ "W",
score1 > score2 ~ "L",
score1 == score2 ~ "D"),
ha = "Away",
team_spi = spi2,
opponent_spi = spi1,
team_xg = xg2,
opponent_xg = xg1)) %>%
mutate(game_goal_diff = teamGoal - oppGoal) %>%
mutate(result_points = case_when(result == "W" ~ 3,
result == "D" ~ 1,
TRUE ~ 0))
doParallel::registerDoParallel()
dates <- seq(ymd("20220226"), ymd("20220310"), by = "day")
results <- fotmob_get_matches_by_date(date = dates)
filtered_results <- results %>%
dplyr::select(primary_id, ccode, league_name = name, matches) %>%
dplyr::filter(league_name == "Major League Soccer", ccode == "USA")
# one way of getting data out of the results
unnested_results <- filtered_results %>%
tidyr::unnest_longer(col = matches) %>%
unnest(everything()) %>%
unnest(cols = c("home", "away"), names_sep = "_") %>%
unnest(cols = status) %>%
janitor::clean_names()
match_ids <- unnested_results %>%
distinct() %>%
pull(id)
details_df <- fotmob_get_match_details(match_ids)
shots <- details_df %>%
unnest(shots) %>%
mutate(team = if_else(team_id == home_team_id, home_team, away_team))
mls_team_color_df <- shots %>%
distinct(team, team_color, team_id)
mls_df <- matches %>%
filter(league_id == 1951) %>%
mutate(season =
case_when(between(date, ymd("20220226"), ymd("20220913")) ~ 2022,
# between(date, ymd("20210416"), ymd("20211107")) ~ 2021,
# between(date, ymd("20200229"), ymd("20200308")) ~ 2020,
# between(date, ymd("20200812"), ymd("20201108")) ~ 2020,
# between(date, ymd("20190302"), ymd("20191008")) ~ 2019,
TRUE ~ 0)) %>%
filter(season == 2022) %>%
arrange(team, date) %>%
with_groups(team, mutate, matchday = row_number()) %>%
mutate(half = if_else(matchday <= 17, "first", "second")) %>%
group_by(team, half) %>%
summarize(xGF = mean(team_xg, na.rm = TRUE),
xGC = mean(opponent_xg, na.rm = TRUE),
.groups = "drop") %>%
# pivot_wider(id_cols = team, names_from = season, values_from = c(xGF, xGC)) %>%
mutate(team = case_when(
team == "Los Angeles Galaxy" ~ "LA Galaxy",
team == "Atlanta United FC" ~ "Atlanta United",
team == "Chicago Fire" ~ "Chicago Fire FC",
team == "Minnesota United FC" ~ "Minnesota United",
team == "Houston Dynamo" ~ "Houston Dynamo FC",
team == "Montreal Impact" ~ "CF Montreal",
team == "Orlando City SC" ~ "Orlando City",
TRUE ~ team
)) %>%
inner_join(mls_team_color_df, by = "team") %>%
mutate(logo = if_else(half == "second", glue("https://images.fotmob.com/image_resources/logo/teamlogo/{team_id}.png"),
NULL))
pacman::p_load(ggpath)
# library(gghighlight)
# p <-
mls_df %>%
ggplot() +
geom_link2(aes(x = xGF,
y = xGC,
# alpha = stat(index),
size = stat(index),
color = team_color,
group = team), n = 100, lineend = "round") +
scale_size(range = c(.01, 1.8)) +
guides(size = "none", alpha = "none") +
scale_color_identity() +
# geom_image(aes(x = xGF, y = xGC, image = logo), size = .05) +
geom_from_path(aes(x = xGF, y = xGC, path = logo), width = .045, alpha = 0.9) +
coord_fixed() +
# scale_y_continuous(breaks = seq(.75, 2, by = 0.25)) +
scale_x_continuous(breaks = seq(.75, 2.25, by = 0.25)) +
scale_y_reverse(breaks = seq(.75, 2, by = 0.25)) +
labs(title = "Team xG evolution during the 2022 season",
subtitle = "Start of tail: First 17 matches of 2022; End of tail: Second half of 2022 matches to date\nCreated by: Owen Thompson | @OTStats",
x = "Average xG Created",
y = "Average xG Conceded",
caption = glue("Data as of {format(Sys.Date()-1)}\nSource: 538")) +
theme_minimal() +
theme(text = element_text(family = "Lato"),
plot.title.position = "plot",
plot.title = element_text(size = 20),
plot.background = element_rect(fill = "#f2f4f5", color = "#f2f4f5")) +
# --- Upper Right ---
annotate(geom = "text",
x = 2, y = .98,
label = "There's Good...", family = "Lato",
hjust = 1, vjust = 0.3, alpha = 0.5, size = 3) +
# --- Upper Right... and there's Philly ---
annotate(geom = "text",
x = 2.2, y = 1.025,
label = "...and then there's Philly", family = "Lato",
hjust = 0.5, vjust = 0.3, alpha = 0.5, size = 3) +
# --- Bad, bad, bad ---
annotate(geom = "text",
x = 1.1, y = 2,
label = "All around bad", family = "Lato",
# hjust = 0.5, vjust = 0,
alpha = 0.5, size = 3) +
# --- Fun to watch ---
annotate(geom = "text",
x = 1.85, y = 1.9,
label = "Fun to watch", family = "Lato",
# hjust = 0.5, vjust = 0,
alpha = 0.5, size = 3) +
# --- Boring ---
annotate(geom = "text",
x = 1.1, y = 1.05,
label = "Defensively sound, can't create", family = "Lato",
# hjust = 0.5, vjust = 0,
alpha = 0.5, size = 3)
source("Developer/OT/gameplots/R/add_logo.R")
ggsave(filename = "20220929 MLS 2022 season xG evolution.png",
plot = last_plot(),
width = 9, height = 8, dpi = "retina")
# -- Add Leauge logo to plot
plot_with_logo <- add_logo(plot_path = "20220929 MLS 2022 season xG evolution.png",
logo_path = glue("https://images.fotmob.com/image_resources/logo/leaguelogo/130.png"),
logo_position = "top right",
logo_scale = 12)
magick::image_write(plot_with_logo, "20220929 MLS 2022 season xG evolution.png")
@OTStats
Copy link
Author

OTStats commented Nov 7, 2022

20220929 MLS 2022 season xG evolution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment